JavaScript 中的 __proto__ 与 prototype

  最近接了几个面试,个别出色的面试官在面试技术部分的时候总是很考察被试者的原生 JavaScript 能力,而业务逻辑写多了就会逐渐淡忘掉最基础同时也是最重要的 JavaScript 知识。所以,工作的同时多复习原生 JavaScript 知识是非常重要的。今天就来聊一下 JavaScript 中 __proto__ 和 prototype。

prototype

  prototype 属性即 JavaScript 的原型属性,是为了给所有实例添加共享属性和共享方法的属性。使用方法可见 这篇文章 中的“原型模式”部分。

  prototype 这个属性指向一个包含所有共享属性和共享方法的对象,我们称之为原型对象。同时这个原型对象也有一个叫做 constructor 的属性,这个属性指回的是原构造函数。

1
2
3
4
5
6
7
8
9
function Person() {
this.name = 'xkf'
this.age = 18
}
Person.prototype.sayName = function() {
console.log(this.name)
}

console.log(Person.prototype) // 会打印出sayName, constructor, __proto__

  上面的代码先是创建了一个名为 Person 的构造函数,然后给这个方法的原型属性(prototype)内添加了一个所有实例共享的 sayName 方法,最后在控制台打印出了该构造函数的 prototype 属性。可以看到,prototype 内包含之前添加的 sayName 方法,接着有 constructor 属性,这个属性指回原构造函数也就是它自己 Person。最后还有一个 __proto__。

__proto__

  JavaScript 的每个实例对象中会有 __proto__ 这样一个私有属性,有些人把这个属性称之为“隐式原型”,这个属性指向构造该对象的构造函数的原型属性(prototype)。

1
2
3
4
5
6
7
function Person() {
this.name = 'xkf'
this.age = 18
}

var p = new Person()
console.log(p.__proto__ === Person.prototype) // true

  上面的代码先是创建了一个名为 Person 的构造函数,然后基于 Person 创建了它的实例”p”。这个时候如果直接打印 p 的话会看到,p 里面除了有继承自构造函数 Person 中的属性 name 和 age 之外,还有一个私有属性(隐式原型)__proto__,而它指向的就是构造该对象的构造函数(Person)的原型,所以两者在最后比较的时候会返回”true”。