prototype
在JavaScript中,每一个函数都有一个prototype属性,且prototype属性是函数才会有的属性。
那么函数的prototype属性到底指向的是哪?
function Person(){}
Person.prototype.name = 'kevin'
var p1 = new Person()
var p2 = new Person()
console.log(p1.name) // 'kevin'
console.log(p2.name) // 'kevin'
函数prototype属性指向的是一个对象,这个对象正式是调用该构造函数而创建的实例原型,也是p1和p2的原型。
那什么是原型?可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们说的原型,每一个对象都会从原型“继承”属性。
继承意味着复制操作,然而JavaScript默认并不会复制对象的属性,相反,JavaScript只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫做继承,委托的说法反而更加准确些。--《你不知道的JavaScript》
__proto__
每一个JavaScript对象(除了null)都具有一个属性__proto__,这个属性会指向该对象的原型。
function Person(){}
// Person.prototype === p1.__proto__ // true
constructor
每一个原型都有一个constructor属性,属性指向指向关联的构造函数。
function Person(){}
var p1 = new Person()
// Person.prototype.constructor === Person // true
// p1.__proto__.constructor === Person // true
// Object.getPrototypeOf(p1) === Person // true
实例与原型
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到顶层位置。这就是实例属性查找机制,也是原型链的概念。
function Person(){}
Person.prototype.name = 'jack'
var p1 = new Person()
p1.sex = '男'
p1.sex // 男
p1.name // jack
p1.age // null
上述代码中,当打印p1.sex的时候,因为p1.sex是添加了属性,所以能正常打印出来。但打印p1.name时,p1的属性中时不存在的,那么就会在p1的原型中p1.__proto__去找,也就是Person.prototype中去找。当打印p1.age的时候,原型中也不存在,那么就是在原型的原型中去找,那么原型的原型是什么?
其实原型也是一个对象,对象的原型__proto__也就是Object.prototype的原型
Object.prototype.__proto__ === null // true
null表示“没有对象”,即该处不应该有值
Object.prototype.__proto__的值为null,其实就是说Object.prototype是没有原型的
图中由相互关联的原型组成的链状结构(蓝色线条部分)就是原型链