javascript|[[Prototype]] ——原型链两万字全面解析「建议收藏」( 八 )



链上的 Foo.prototype 。 但是这个对象也没有 constructor 属性(不过默认的 Foo.prototype 对象有这个属性 , 默认的已经被修改为空对象) 。 所以它会继续委托 , 这次会委托给委托链顶端的 Object.prototype 。 这个对象有 constructor 属性 , 指向内置的 Object 函数 。


Foo.prototype 被人为修改成空对象 。 所以指向 Object.prototype , Object.prototype.constructor 指向 Obeject
错误观点已经被摧毁 。

这里的错误观点指的是 a.constructor === Foo 理解为由 Foo 构造 , 然而并不是 。
a 的原型就是 Foo 的原型 。 a.constructor 即 Foo.prototype.constructor
当然 , 你可以给 Foo.prototype 添加一个 consructor 属性 , 不过这需要手动添加一个符合正常行为的不可枚举属性 。
举例来说:
function Foo() {Foo.prototype = { // 创建一个新原型对象// 需要在 Foo.prototype 上修复丢失的 constructor 属性// 新对象属性起到 Foo.prototype 的作用Object.defineProperty(Foo.prototype 'constructor' {  enumerable: false  writable: true  configurable: true  value: Foo // 让 constructor 指向 Foo)var a = new Foo()a // Foo { ___proto___: { constructor: ? Foo()  
修复 constructor 需要很多手动操作 。 所有这些工作都是源于把「constructor」错误地理解为「由……构造」 , 这个误解的代价实在太高了 。
实际上 , 对象的 constructor 会默认指向一个函数 , 这个函数可以通过对象的 prototype 引用 。 「constructor」和「prototype」这两个词的含义可能适用也可能不适用 。 最好的办法是记住这一点:「constructor」并不表示被构造 。

a.constructor 并不表示由 Foo 构造 , 而是委托给 Foo
constructor 并不是一个不可变属性 。 它是不可枚举的 , 但是它的值是可写的 。 此外 , 你可以给任意 [[Prototype

链中的任意对象添加一个名为 constructor 的属性对其进行修改 , 你可以任意对其赋值 。
和 [[Get

算法查找 [[Prototype

链的机制一样 , constructor 属性引用的目标可能和你想的完全不同 。
现在你应该明白这个属性多么随意了吧 。

似乎这个属性被修改了 , 对于使用 new 实例新对象也不影响 。
结论:一些随意的对象属性引用 , 比如 a.constructor 实际上是不被信任的 , 它们不一定会指向默认的函数引用 。 此外 , 很快我们就会看到 , 稍不留神 a.constructor 就可能会指向你意想不到的地方 。
a.constructor 是一个非常不可靠并且不安全的引用 。 通常来说要尽量避免使用这些引用 。
原型继承我们已经看到过了许多 JavaScript 程序中常用的模拟类行为的方法 , 但是如果没有「继承」机制的话 , JavaScript 中的类就只是一个空架子 。
实际上 , 我们已经了解了被称作是原型继承的机制 , a 可以「继承」 Foo.prototype 并访问 Foo.prototype 的 myName 函数 。 但是我们之前只把继承看作是类是类之间的关系 , 并没有把它看作是类和实例之间的关系:

image-20220416115424863
还记得这张图吗?它不仅展示出对象 a1 到 Foo.prototype 的委托关系 , 还展示出 Bar.prototype 到 Foo.prototype 的委托关系 , 而后者和类继承很相似 , 只有箭头的方向不同 。 图中由下到上的箭头表明这是委托关联 , 不是复制操作 。