原型与原型链
Opened this issue · 0 comments
原型
对于使用过基于类的语言 (如 Java 或 C++) 的开发人员来说,JavaScript 有点令人困惑,因为它是动态的,并且本身不提供一个 class 实现。(在 ES2015/ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型的)
当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节 ---MDN
prototype
首先了解原型对象prototype,每个函数都有一个 prototype 属性,而这个prototype里装的就是这个函数的原型对象.
function a () {}
a.prototype.name = 'a'
const i = new a()
console.log(i.name) // 'a'
我们可以看到,挂在在构造函数原型上的属性,可以被构造函数的实例获取到。
当然前提是构造函数中,也有同名属性呢?
function a () {
this.name = 'x'
}
a.prototype.name = 'a'
const i = new a()
console.log(i.name) // 'x'
这里我们看到,如果构造函数中,有原型对象的同名属性是,实例获得的是实例中的属性。
这其实是一个向上查找的过程,在你将"name"作为标志符去查找的时候,它会先在实例中查找
如果找到了,则直接返回给你,并中断查找,如果没找到则去它的原型对象上找,
如果还没找到会去哪里找呢。
我们现在要引入一个概念__ proto __
__ proto __
这是浏览器实现的一个属性,不是javaScript的标准属性,这个属性是用于获得实例对象的原型的。
比如:
function a () {}
const i = new a()
console.log(i.__ proto __ === a.prototype) // true
我们发现这个实例的__ proto __ 是指向 该实例构造函数的prototype的。
这时我们发现,原型对象也是一个实例,那也应该有一个__ proto __,那么:
function a () {}
const i = new a()
console.log(i.__ proto __ === a.prototype) // true
i.__ proto __.__ proto __ === Objcet.protoype // true
a.prototype.__ proto __ === Objcet.protoype // true
原来他们原型对象的原型对象(__ proto __)是Object。因为他们都是对象,是由Objcet实现的。
那么回到刚刚原型网上查找的过程,它在原型上没查找到,就会去原型的原型上查找,最终
回到那里呢?
console.log(Object.prototype.__ proto __ === null) // true
最后会找到null,如果找到这里了,说明没有找到那个属性,那么这个属性也就是undefine了。
这一条向上查找的路程,这就是我们所说的原型链的一部分,原型链中还有一个环节,
试想我知道一个构造函数的原型对象,那我怎么通过原型知道它的构造函数是谁呢?
原型对象中还有一个属性,是constructor, 这个里面装的就是该原型的构造函数的地址。
Constuctor
function a () {}
console.log(a.prototype.constructor) // ƒ a() {}
看到这里,可以在脑海中试想一下原型链的各个环节,我就不发图了,最后贴一段代码
帮你理解原型链。
const a = function foo() {}
const i = new a()
console.log(a.prototype.constructor) //ƒ foo() {}
console.log(i .__ proto __.constructor) //ƒ foo() {}
a.prototype === a.__ proto __ // false
a.__ proto __ 是将a视为一个实例,它既是一个函数,也是一个实例,
那么它是谁的实例?
a.__ proto __ === Function.prototype // true
可以得知,它其实是Function的一个实例。
Function.prototype.__ proto __ === Object.prototype // true
Object.prototype.__ proto __ === null // true
这些应该能帮助你理解。
补充一个特殊的
Function._ proto _ === Function.prototype // true
你可以理解构造函数Function,它自己也是它自己的实例。