1. 原型
1.1 定义
- 我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
- 原型对象默认有一个constructor属性,该属性指向构造函数。
- 调用构造函数创建一个新实例后,该实例的内部包含一个指针(proto),该指针指向构造函数的原型对象
- 所有函数的默认原型都是object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype
- 函数的默认原型对象是Function.prototype,而Function.prototype的原型指向Object.prototype
- Object.prototype对象的原型为null,即为原型链顶端
用图示说明上述代码的原型关系:function Foo(){}
var foo = new Foo()
var obj = new Object()
1.2 确定对象和原型之间的关系
prototypeObj.isPrototypeOf(object):用于测试一个对象是否存在于另一个对象的原型链上。
object instanceof constructor:用于检测构造函数constructor的prototype
属性是否出现在实例对象object的原型链上。
1.3 获取对象原型
Object.getPrototypeOf(object):方法返回指定对象的原型(内部[[Prototype]]
属性的值)
1.4 原型链读写规则
读取:当代码读取对象的某个属性时,都会执行一次搜索,首选从对象实例本身搜索,如果实例中找到了具有给定名字的属性,则返回该属性的值,如果没有找到,则继续搜索指针指向的原型对象,如果没有找到,则继续在该原型对象的原型上查找,直到原型链的顶端null,如果还未找到则返回undefined。
写入:**当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,添加这个属性只会阻止我们访问原型中的哪个属性,但不会修改那个属性。**
1.5 hasOwnProperty
obj.hasOwnProperty(prop):使用该方法可以检测一个属性存在于实例中还是原型中,在给定的属性存在于对象实例中,返回true
**
1.6 in for-in Object.keys() Object.getOwnPropertyNames()
1.6.1 in
in操作符会在通过对象能访问给定属性时返回true,无论该属性存在于实例中还是原型中,无论属性是否可枚举
利用这个特性,结合使用hasOwnProperty()方法,可以确定改属性到底存在于对象中还是原型中。
function hasPrototypeProperty(obj,prop) {
return !obj.hasOwnProperty(prop) && (prop in obj)
}
1.6.2 for-in
for (variable in object):以任意顺序返回所有能通过对象访问的,可枚举的除了symbol以外的属性,其中既包括存在于实例中的属性,也包括原型中的属性,屏蔽了原型中不可枚举的属性的实例属性也会在for-in中返回
1.6.3 Object.keys()
Object.keys(obj): 获取对象实例上所有可枚举的属性
1.6.4 Object.getOwnPropertyNames()
Object.getOwnPropertyNames(obj):获取所有实例属性,无论是否可枚举
1.7 原型的动态性
由于在原型中查找值的过程是一次搜索,因此我们对原型所作的任何修改都能够立即从原型实例中反映出来
var foo = Foo()
Foo.prototype.sayHi = functyion() {
console.log('hi!')
}
foo.sayHi() //'hi!'
但是如果重写整个原型对象,情况就不同了,调用构造函数时会为实例添加一个指向最初原型的指针,而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。这时构造函数的prototype和实例对象的proto指向了不同的对象。
function Person() {}
var friend = new Person()
Person.prototype = {
constructor: Person,
name: 'Nicholas',
sayName: function() {
console.log(this.name)
}
}
friend.sayName() //error