关于原型

关于两个大宝贝:

__proto__ & prototype

还是面试的时候被挖出来的坑 T^T

参考和引用的链接 ↓

对象原型
从__proto__和prototype来深入理解JS对象和原型链
继承与原型链
三分钟看完JavaScript原型与原型链

然后,完全不知道怎么来分段呢。。。

原型和原型链

早些时候一直以为 JavaScript 是面向对象语言,后来接触的多了也又意识到与 JAVA 面向对象有很大的差异。
后来看到文献说 JavaScript 是 prototype-based language

每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。 基于原型的语言?

原型对象也是对象嘛,所以一层一层的,组成了原型链。

__proto__ 和 prototype

注意: __proto__ 已经被弃用。可以通过 Object.getPrototypeOf(obj) 代替

MDN 中的说法 :每一个实例对象都有一个私有属性 ,称为 __proto__ ,指向它的构造函数的原型对象,称 prototype 。这个原型对象也有自己的原型对象,一层层向上直到没有原型对象的 null 。null 也就是作为原型链的最后一个环节。

对象的 __proto__ 指向它的构造函数的原型对象 prototype 。

而 prototype 也是一个对象,那么自然而然的它也会有 __proto__ 。

↑ 不是百分百正确的 __proto__ 会一层一层的向上翻原型链,需要考虑到的是原型链的顶端是 null ,而 null 是没有原型对象的,也就不存在 __proto__ 指向不存在的 prototype 。

只有函数具有 prototype 。
三个原因:

  1. ES 规范就是这样的 (不是
  2. 函数在 JavaScript 里是一等公民 (不是
  3. 创建函数时,会为函数自动添加 prototype ,是一个具有 constructor 属性的对象 。通过 new 关键字调用该函数作为构造函数时,实例就会继承这个构造函数的 prototype 的所有属性和方法 。而继承的方法就是实例通过 __proto__ 指向 构造函数的 prototype 。

그래서!

1
2
let demo = new Object()
demo.__proto__ === Object.prototype // true

demo 调用的构造函数是 Object (← 感觉这样说有点问题) 所以 demo 的 __proto__ 就是 Object.prototype 。

再举一个 MDN 上的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function foo() {
this.a = 1;
this.b = 2;
}
let bar = new foo()
foo.prototype.b = 3;
foo.prototype.c = 4;

bar.prototype // undefined
foo.prototype // {b: 3, c: 4}
foo.a // undefined
bar.a // 1
// 注意:
bar.b // 2
bar.c // 4

可以看到实例 bar 的 b 属性值是 2 而不是上面 foo.prototype.b=3 定义的 3 ,并且 bar 具有 c 属性。

  1. 为什么 bar.b 的值是 2 ? 因为这个 b 是自身的属性 ,尽管原型上也有一个 b 属性,但是也不会被访问到 。这个情况称为属性遮蔽 ,类似 override 。
  2. 为什么 bar.c 的值是 4 ? 当访问一个对象的属性时,不仅会在对象本身上搜索,还会搜索对象的原型,依次层层向上搜索 。

其实已经差不多理解完了原型(链)了。
那么什么是原型呢?差不多可以理解为具有 constructor 属性的对象 ( 即 prototype 。

0%