原型链

js 是一种基于原型的语言,每个对象拥有一个原型对象,对象从原型继承方法和属性。原型对象也可以能拥有原型,并从中继承方法和属性,一层一层,最终构成了原型链。

注意:OOP中,首先定义类,此后创建对象实例,类中定义的所有属性和方法都被复制到实例中。而 js 中是通过在实例和它的构造器之间建立一个链接。

prototype

每一个函数都有一个属于自己的 prototype 属性,它指向一个对象,而这个对象就是实例的原型。

原型就是每一个 js 对象在创建的时候与之关联的一个对象。每一个对象都会从原型"继承"属性。所以继承的属性都源自 prototype 属性之上的。prototype 属性的值是一个对象。原型链下游的对象继承的属性和方法,都存在其中。

[[Prototype]]

对象都有一个特殊的隐藏属性 [[Prototype]], 它要么是 null,要么就是另一个对象的引用,该对象被称为原型。

[[Prototype]] 是内部的而且是隐藏的,但是浏览器给我提供了访问它的方法。

proto

let user1 = {};
let user2 = {};

user2.__proto__ = user1;

允许我们从 user2 中读取一个它没有的属性. js 会去 user1 去寻找.

注意:

  1. 引用不能形成闭环。
  2. proto 的值可以是对象,也可以是 null, 其他类型会被忽略。

proto 和 [[Prototype]] 的关系

  1. 二者是不一样的,proto 是 [[Prototype]] 的历史原因留下来的 getter/setter.
  2. proto 属性有点过时,它的存在是历史的原因,我们现在应该使用的是 Object.getPrototypeOf 和 Object.setPropertyPf 来取代 proto 的 getter/setter.
  3. proto 受到浏览器环境的限制,但是几乎所有的环境都支持他。
  4. proto 感官上更加强烈。

constructor

每一个原型都有一个 constructor 属性指向关联的构造函数。每个实例都从原型中继承了一个 constructor 属性。

function Person() {}
var person1 = new Person();
person1.constructor === Person;
Person.prototype.constructor === Person;

可以创建新的实例
var person3 = new person1.constructor();

获取对象实例的构造器的名字
person1.constructor.name;

原型链

前面说过,实例的原型也是一个对象,既然是对象,一开始说过,每一个对象在创建的时候都有一个与之关联的原型对象.