1 | function Person() { |
Person 就是一个构造函数,new 来创建一个实例对象 person
Prototype
prototype是*只有 函数 *才会有的一种属性
1 | function Person() { |
函数的 prototype 属性指向一个对象,这个对象就是 调用这个构造函数创建的实例的原型,也就是 person1 和 person2 的原型
__proto__
每个对象都有一个 __proto__
属性,指向它的原型,也就是其构造函数的prototype属性
constructor
每个原型对象都有一个指向其构造函数的 constructor 属性
1 | Person.prototype.constructor === Person |
构造函数、实例 和 原型对象的关系:
1 | Person.prototype === person.__proto__ |
原型链
javascript 中继承的原理就是原型链
1 | function Person () { |
当读取实例的属性时,javascript 首先会在实例上查找有没有这个属性,如果在实例身上没有找到,那么就会上翻一级,在 person.__proto__
上查找是否有对应的属性,上面的例子就是这样的一种情况
但是如果在实例的原型对象上还是没有找到对应的属性呢?这就涉及到了原型链的知识,如果在实例的原型对象上还是没有找到对应的属性,javascript 就会顺着原型链继续查找
原型链,说白了就是
1 | instance.__proto__.__proto__.xxxxx = Constructor.prototype |
就是这样的一个链式结构,javascript会在这个原型链的原型对象上查找对应属性,直到找到了对应属性,或到了null
这个原型链是一定会有终点的,当javascript到达我们定义的继承链的最上层时,这个原型对象就会被看做一个普通的object,它是可以通过 new Object 来创建的,也就是说
1 | var object = new Object(); |
Person.prototype 其实就是这样的一个对象,所以说,Person.prototype.__proto__
,是指向 Object.prototype
的,而 Object.prototype.__proto__
,就是 null
javascript原生对象的原型链
1 | Array.prototype.__proto__ === Object.prototype |
构造函数作为实例,其原型对象
1 | // 构造函数的原型对象: |
我们之前讲过,所有对象都有 __proto__
属性,那么 函数对象自然也是有 __proto__
属性的,每个函数,都可以看做是 new Function()
构建出来的,所以
1 | Person.__proto__ === Function.prototype // true |
一个比较特殊的例子
1 | Function.__proto__ === Function.prototype |
可以理解为:就是先有的Function,然后实现上把原型指向了Function.prototype,但是我们不能倒过来推测因为Function.proto === Function.prototype,所以Function调用了自己生成了自己。一种内建规则,不必深究
Object.prototype 并不是一个正统的对象,因为它的__proto__
为 null,可以说,对象都是实例,而实例不一定都是对象
【题外话】Function对象,所有的函数都是继承自 Function 对象,我们平时使用的 bind apply call
这些函数,都是在Function 的 prototype 上定义的属性—— MDN-Function