剖析原型链

178 阅读2分钟

prototype

首先要清楚一个概念,每个构造函数,也就是每个函数都有一个prototype属性,通过向prototype添加属性,用这个构造函数创建出来的对象会继承这个属性,

function Person() {
​
}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin

其实,函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 person1 和 person2 的原型。

那什么是原型呢?你可以这样理解:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

构造函数和实例原型的关系图

proto

这是每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型。

function Person() {
​
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

原型链示意图

图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。

img

Object.prototype.__proto__ === null //true
object instanceof constructor
//相当于
object.__proto__ === constructor.prototype

instanceof操作符就是把实例的隐性原型跟构造函数的显性原型相比较返回布尔值

4 个用于拓展原型链的方法

  • new-initialization
  • Object.create
  • Object.setPrototypeOf
  • proto
function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};
​
function Bar() {}
​
// 设置Bar的prototype属性为Foo的实例对象
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
​
// 修正Bar.prototype.constructor为Bar本身
Bar.prototype.constructor = Bar;
​
var test = new Bar() // 创建Bar的一个新实例// 原型链
test [Bar的实例]
    Bar.prototype [Foo的实例] 
        { foo: 'Hello World' }
        Foo.prototype
            {method: ...};
            Object.prototype
                {toString: ... /* etc. */};

总结

  • Object 是所有对象的爸爸,所有对象都可以通过 __proto__ 找到它
  • Function 是所有函数的爸爸,所有函数都可以通过 __proto__ 找到它
  • Function.prototype 和 Object.prototype 是两个特殊的对象,他们由引擎来创建
  • 除了以上两个特殊对象,其他对象都是通过构造器 new 出来的
  • 函数的 prototype 是一个对象,也就是原型
  • 对象的 __proto__ 指向原型, __proto__ 将对象和原型连接起来组成了原型链