原型链
js 是一种基于原型的语言,每个对象拥有一个原型对象,对象从原型继承方法和属性。原型对象也可以能拥有原型,并从中继承方法和属性,一层一层,最终构成了原型链。
注意:OOP中,首先定义类,此后创建对象实例,类中定义的所有属性和方法都被复制到实例中。而 js 中是通过在实例和它的构造器之间建立一个链接。
prototype
每一个函数都有一个属于自己的 prototype 属性,它指向一个对象,而这个对象就是实例的原型。
原型就是每一个 js 对象在创建的时候与之关联的一个对象。每一个对象都会从原型"继承"属性。所以继承的属性都源自 prototype 属性之上的。prototype 属性的值是一个对象。原型链下游的对象继承的属性和方法,都存在其中。
[[Prototype]]
对象都有一个特殊的隐藏属性 [[Prototype]], 它要么是 null,要么就是另一个对象的引用,该对象被称为原型。
[[Prototype]] 是内部的而且是隐藏的,但是浏览器给我提供了访问它的方法。
proto
let user1 = {};
let user2 = {};
user2.__proto__ = user1;
允许我们从 user2 中读取一个它没有的属性. js 会去 user1 去寻找.
注意:
- 引用不能形成闭环。
- proto 的值可以是对象,也可以是 null, 其他类型会被忽略。
proto 和 [[Prototype]] 的关系
- 二者是不一样的,proto 是 [[Prototype]] 的历史原因留下来的 getter/setter.
- proto 属性有点过时,它的存在是历史的原因,我们现在应该使用的是 Object.getPrototypeOf 和 Object.setPropertyPf 来取代 proto 的 getter/setter.
- proto 受到浏览器环境的限制,但是几乎所有的环境都支持他。
- 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;
原型链
前面说过,实例的原型也是一个对象,既然是对象,一开始说过,每一个对象在创建的时候都有一个与之关联的原型对象.