原型对象
每个函数都有一个特殊的属性prototype (叫做原型),这个属性是指针对象,对象包含所有相关实例对象共享的属性和方法,所有原型对象都会自动获得一个 constructor (构造函数)属性,如图:
使用哪个函数的prototype属性,那么这个函数就当做一个构造函数,也就是原型对象constructor 属性的值;
一般构造函数首字母都大写,以便和普通函数区分;
在constructor 属性里,我们就能看到函数的prototype 属性;
当调用构造函数创建一个实例对象后,该实例对象会包含一个内部属性,这个属性存放一个指针,该指针指向构造函数的原型对象,ECMA-262第 5版中管这个指针叫[[Prototype]],在脚本中则是提供__proto__属性去访问这个指针;
prototype 和__proto__的区别
prototype 是构造函数的原型对象,也是通过构造函数实例化得到 的对象 的原型对象;每一个实例对象都有__proto__属性,__proto__是从prototype属性派生出来的,是一个指针对象,对象的__proto__属性指向该对象构造函数的原型对象
如果对象构造函数相同,那么prototype和__proto__是一个全等的关系,如:
function Person(){
}
Person.prototype.name = '张三';
Person.prototype.getName = function(){
return this.name
}
let p1 = new Person();
let p2 = new Person();
console.log(p2.__proto__ === Person.prototype) // true
console.log(p2.__proto__ === p1.__proto__ ) // true
上述例子的对象关系如图:
prototype原型对象的原型对象是Object.prototype
可以看到
Object.prototype的__proto__属性就不再是一个指针对象了,这也就是说到‘顶’了,
Object.prototype.__proto__===null
isPrototypeOf 根据名字就能知道判断一个对象的原型对象是否是,比如上面的例子:
Person.prototype.isPrototypeOf(p1)===true
原型链
每个对象都有一个原型对象,原型对象又有一个原型对象.......,这就形成了原型链。
上述讲了__proto__和prototype 的关系,就能理解,我们在获取对象属性时,先从最近的开始查找属性,找到就返回值,找不到,则会去原型链上的原型对象查找,知道原型链末端依旧没有找到就返回undefined