原型链
构造函数、原型对象、实例对象三者的关系
- 每个函数内部都有一个 prototype 属性(原型),这是一个指针,指向了一个原型对象。所有通过构造函数实例化的实例对象,都会从关联的原型对象中“继承”属性。
- 原型对象内部也有一个 constructor 属性(构造函数),也是一个指针,反向指回了构造函数。
- 实例对象内部也有一个 _proto_ 属性,也是一个指针,也是指向了关联的原型对象。(Object的 _proto_ 是 null)
function Person () { }
var person = new Person()
console.log(person.__proto__ === Person.prototype) // true
console.log(Person.prototype.constructor === Person) // true
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
原型链
因为原型对象也是一个对象,也有 _proto_ 属性,如果一个原型对象作为另一个构造函数的实例,则该原型对象的 _proto_ 属性将指向另一个原型对象,从而构成原型链。
如何读取对象属性
当读取对象属性时,如果对象内部定义了该属性,就会直接读取;如果没有定义该属性,就会沿着原型链逐层搜索该属性。
function Person () {}
Person.prototype.name = 'Kevin'
var person = new Person()
person.name = 'Daisy'
console.log(person.name) // Daisy
delete person.name
console.log(person.name) // Kevin
补充
原型链
由于原型链的存在,可以通过实例直接访问对应的构造函数
instance.constructor = Constructor.prototype.constructor
_proto_
- 绝大部分浏览器都支持通过 _proto_ 访问实例的原型对象,但是 _proto_ 并不是定义在实例的原型对象上,而是定义在Object的原型对象 Object.prototype 上的。
- 与其说 _proto_ 是一个属性,不如说是一个 getter/setter,当访问 obj._proto_ 时,返回 Object.getPrototypeOf(obj)
真的是继承吗?
继承意味着属性的复制,但是在JavaScript的原型链中,定义在原型对象上的属性并不会复制到实例对象上,而是通过它们之间的这种关联。因此,与其说是继承,不如说是委托。