juanjuan2wei/Blog

原型与原型链

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,它自己也是它自己的实例。