js 原型理解(原型对象)

Posted 岁末博

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js 原型理解(原型对象)相关的知识,希望对你有一定的参考价值。

  以前在网上搜了一些关于js原型的资料,看了过后,是有一部分理解,但是还不够全面,在这我就写写下关于js的原型。

  看了下js高级程序设计,我对js原型的有了一定的理解。里面谈到我们创建对象时,如果一直手写一些相似的对象或者说里面有重复的属性时,会非常麻烦。列如:

  

let a = {
      name: ‘a‘,
      idnex: 1
    }
let b = {
      name: ‘b‘,
      idnex: 2
    }

  为了解决这种问题,就出来了一些能创建对象的模式。

//工厂模式

function createObj (name, index) {
      let o = {}
      o.name = name
      o.index = index
    o.sayName = function () {
      alert(this.name)
    }
return o } let a = createObj(‘a‘, 1) let b = createObj(‘b‘, 2)

   这种模式,虽然解决创建多个相似对象的问题, 但却没有解决对象识别的问题(即怎样知道一个对象的类型)。对于这句话,我的理解是,这样创建的对象,在类型上区别不出来吧,这种模式产生的对象,感觉都是同一层面上的,都是通过 new Object 出来的(而原型是可以通过new CreateObj  等构造名创建)

  随着js发展,构造函数模式就出来了

  //构造函数模式

  function CreateObj (name, index) { this.name = name this.index = index this.sayName = function () { alert(this.name) } } let a = new CreateObj(‘a‘, 1) let a = new CreateObj(‘b‘, 2)

 

  这种模式的问题就是每个方法都在实例上创建一遍,如上面的sayName.

  我们可以把方法提取出来:

  

  function CreateObj (name, index) {
      this.name = name
      this.index = index
      this.sayName = sayName
    }
     function sayName () {
        alert(this.name)
      }
    let a = new CreateObj(‘a‘, 1)
    let a = new CreateObj(‘b‘, 2)

  这样的话,所有的实例都会共有这个sayName方法。但是也有新的问题,这样定义的方法是全局的,如果定义多个方法,命名都会要让人崩溃的,也会造成覆盖的风险。

对以上的这些问题,就可以用原型来解决。

  //原型模式    

   function A () { } A.prototype.name = ‘a‘ A.prototype.index = 1 A.prototype.syaName = function () { console.log(this.name) }                              //原型对象:{name: a, index: 1, syaName: function () {console.log(this.name) } }    let a1 = new A() let a2 = new A()

  这里用了prototyope(原型,js仅仅会在函数给它这个属性),这里 A.prototype是指向一个对象的,你就当它就是一个原型对象。上面创建了一个原型对象且包含属性name、index、sayName,然后通过它new出来的实例,本身会有一个[[prototype]]属性,在js中这是个内部属性,一般不能直接访问,但是在Firefox、Safari、Chrome在每个对象上都支持一个属性_proto_,这个可以理解成这个内部属性。 [[prototype]]这个属性指向的就是它的原型对象,但是这里要注意的是,在原型机制中,只会访问实例本身没有的属性,才会再去找原型对象中是否有这个属性,如:

  

  function A () {
  }
  A.prototype.name = ‘a‘
  A.prototype.index = 1
  A.prototype.syaName = function () {
    console.log(this.name)
  } 

  A.prototype.c = [1, 34]
  let a1 = new A()
  let a2 = new A()
  console.log(a1.a) // 1
  console.log(a2.a) // 1
  console.log(a2.c) // [1, 34]
  console.log(a2.c) // [1, 34]
  a2.a = 2
  a2.c.push(‘3‘)
  console.log(a1.a) // 1
  console.log(a2.a) // 2
  console.log(a2.c) // [1, 34, 3]
  console.log(a2.c) // [1, 34, 3]

  这里可能有人会疑惑,为什么a1中的a不会改变,c改变了。先说下整个过程:

  a1、a2都没有属性a,c ,所以它就去访问它的原型对象,如果都是只是访问的话,因为访问的是同一个对象,所以就得到同样的值。

  然后, a2.a  =  2  这个赋值操作,是会优先对a2这个对象进行赋a这个属性的(那么a2就会有自己的属性a并且值为2),而不是去对原型对象的属性a重新赋值。而a2.c不是赋值操作,只是对元数据进行修改,因为a2里面没有c属性,也修改不了自己的属性c,那么就会对原型对象里面的数据进行修改了。我们可以验证一下:

  a2.a = 2
  a2.c = [1, 2]
  console.log(a1.a) // 1
  console.log(a2.a) // 2
  console.log(a2.c) // [1, 34]
  console.log(a2.c) // [1, 2]

  这里都是给自己的实例对象添加了各自的属性,而原型对象并没有改变,所以他们自己有的属性就访问自己的,没有的就访问没改变的原型对象。

  简而言之,js中每个对象会有一个内部属性[[prototype]],该属性指向它的原型对象。

       而原型对象,可以通过函数的prototype来创建以及给它赋属性。

       每个通过原型构造函数产生的实例对象,是共享同一个原型对象的,该对象的属性值是不能通过实例赋值修改的。

 




















以上是关于js 原型理解(原型对象)的主要内容,如果未能解决你的问题,请参考以下文章

简单粗暴地理解js原型链--js面向对象编程

简单粗暴地理解js原型链--js面向对象编程

彻底理解js的原型链

js 原型理解(原型对象)

关于js的对象原型继承

JS原型原型链深入理解