关于两个大宝贝:
__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 。
三个原因:
- ES 规范就是这样的 (不是
- 函数在 JavaScript 里是一等公民 (不是
- 创建函数时,会为函数自动添加 prototype ,是一个具有 constructor 属性的对象 。通过 new 关键字调用该函数作为构造函数时,实例就会继承这个构造函数的 prototype 的所有属性和方法 。而继承的方法就是实例通过 __proto__ 指向 构造函数的 prototype 。
그래서!
1 | let demo = new Object() |
demo 调用的构造函数是 Object (← 感觉这样说有点问题) 所以 demo 的 __proto__ 就是 Object.prototype 。
再举一个 MDN 上的例子:
1 | function foo() { |
可以看到实例 bar 的 b 属性值是 2 而不是上面 foo.prototype.b=3 定义的 3 ,并且 bar 具有 c 属性。
- 为什么 bar.b 的值是 2 ? 因为这个 b 是自身的属性 ,尽管原型上也有一个 b 属性,但是也不会被访问到 。这个情况称为属性遮蔽 ,类似 override 。
- 为什么 bar.c 的值是 4 ? 当访问一个对象的属性时,不仅会在对象本身上搜索,还会搜索对象的原型,依次层层向上搜索 。
其实已经差不多理解完了原型(链)了。
那么什么是原型呢?差不多可以理解为具有 constructor 属性的对象 ( 即 prototype 。