原型链的深刻理解

原型链的定义:每个实例对象都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

知识点:

  • prototype:是函数独有的属性,指向实例对象原型对象
  • constructor:是对象独有的属性,指向构造函数
  • proto:是对象独有的属性,指向对象的原型对象

注:函数也是对象,所以函数也有 constructorproto 属性

说了这么多,来点实际的上代码,构建一个原型链:

const F1 = function(name) {
  this.name = name
};

const F2 = function(age) {
  this.age = age;
};

F2.prototype.name = '芳芳';
F2.prototype.hobby = '跳舞';
F2.prototype.eat = () => '胖丁爱吃鱼';
const newF1 = new F1('胖丁');
const newF2 = new F2('11');

// 将 构造函数 F2 的原型对象绑定到 实例对象 newF1 的原型对象的原型对象上,
newF1.__proto__.__proto__ = F2.prototype;

console.log(newF1.name);   // 胖丁
console.log(newF1.eat());  // 胖丁爱吃鱼
console.log(newF1.hobby);  // 跳舞
console.log(newF1.age);    // undefined

console.log(F1.__proto__.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
// console.log(null.__proto__); // 报错 Cannot read property '__proto__' of null
复制代码

上述形成的原型链示图如下:

原型链.png

接下来我们通过示图以及代码对原型链进行解释

  • 原型链:当 实例对象 newF1 要访问属性时(我们这里访问的属性是 hobbyage 还有 name ),我们会先从该实例对象(newF1 )所对应的构造函数内部查找,如果有的话,就返回,从访问 name 属性我们就能看出,获取的属性值是 构造函数 F1 内的值,而不是原型链 newF2.prototype 上的值;如果在所对应的构造函数上查找不到的话,就会去实例对象的原型对象(newF1.proto)上查找,如果实例对象的原型对象也查找不到,会接着到实例对象的原型对象所对应的原型对象上查找(newF2.prototype)上查找,如果有我们要访问的属性,就会返回该属性的值,从访问 hobby 属性我们就可以看出来;但是查询不会访问原型对象所对应的构造函数,从访问 age 属性,我们就可以看出来;如果该原型对象上也查询不到会接着到所对应的原型对象上查找,直到查找到 null,这样就形成了一个链式查询,就是原型链

本来以为这里就结束了,但是我发现了一个问题:**Object 既是构造函数也是实例化对象, Function 也既是构造函数也是实例化对象 **,他们之间是不是存在什么关系呢?

// 注:Object 既是构造函数也是实例化对象, Function 也既是构造函数也是实例化对象 
const obj = {} // 等价于 const obj = new Object()
// 对象 obj 的构造函数是 Object
console.log(obj.constructor); // [Function: Object] 
// 1.Object 也是一个最大的对象,他的构造函数是 Function
console.log(Object.constructor); // [Function: Function]

// 2. 当 Function 是对象时 所对应的构造函数是 Function
console.log(Function.constructor); // [Function: Function]
console.log(Function.prototype === Function.__proto__); // true
console.log(Function.__proto__.__proto__ === Object.prototype); // true
复制代码

完善示图如下:

原型链1.png

  • 在这里我们要对 FunctionObject 进行分类讨论
  • 当 Object 是对象时,他的构造函数就是 Function
  • 当 Function 是对象的时候,他的构造函数 就是指向 自己 Function,所以 Function.prototype === Function.proto,其中第一个 Function 是对象,第二个 Function 是函数

最后,感谢这篇博文,本文中的部分内容参考自这篇博文:帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

猜你喜欢

转载自juejin.im/post/7107157621664284703