JavaScript 原型
一、原型概念
1、原型的出现
基于原型的面向对象系统通过“复制”的方式创建新对象。原型系统的“复制操作”有两种实现思路:
- 不是真的去复制一个原型对象,而是使得新对象持有一个原型的引用(比如 JavaScript)
- 真的复制对象,从此两个对象再无关联。
2、原型的定义
- 每个函数都有一个
prototype
属性(或如果所有对象都有私有字段[[prototype]],就是对象的原型),它指向一个对象,这个对象就是原型对象。(默认情况下,原型对象上都有一个constructor
属性,它是一个指向 prototype 属性所在函数的指针。) - 读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。
二、实例
1、实例和原型的关系
当调用构造函数创建一个实例后,该对象实例内部有个 __proto__
属性,它指向构造函数的原型对象。
1 | Object.__proto__ === Function.prototype //true |
2、实例属性
1 | function Person () {} |
get
当读取实例上的某个属性时,先在实例上找,如果没找到就在原型中找,直到原型为空或者找到为止。
set
可以通过实例访问保存在原型中的值,但不能通过实例重写原型中的值。
通过”实例.属性 = 值’’的形式修改对象属性时,假如这个属性在原型对象上,则它所执行的操作是在实例上创建了一个相同属性名的属性,并没有改变原型对象上的属性,在访问时候,实例会屏蔽原型对象上相同属性名的属性而读取实例上的属性。
3、api
1 | Object.create(proto,[propertiesObject]) 根据指定的原型创建新对象,原型可以是 null; |
三、原型的重写
- 为了简写每次添加属性都要写一次 “构造函数.prototype“ 的写法,可以直接一次赋给它一个对象,然后将要添加的属性封装到那个对象中。但是问题是这样会导致原型对象的 constructor 不在指向该构造函数了,因为此操作相当于重写了默认的原型对象,所以此时的 constructor 指向的是 Object 构造函数,即无法用 constructor 确定对象类型了。所以在重写原型对象后,要同时修改它的 constructor 指向。
- 重写原型对象会切断现有原型和任何之前已经存在的实例对象之间的联系,那些实例对象指向的仍然是之前的那个原型。
四、原型链
让一个原型对象等于另一个类型的实例,原型对象将包含一个指向另一个原型对象的指针,另一个原型中也包含着一个指向另一个构造函数的指针,假如另一个原型又是另一个类型的实例,这样层层递进,就构成了实例和原型的链条。
五、示例
1 | Function.prototype.a = 1; |
微信打赏