提问人:McBacon 提问时间:10/30/2023 最后编辑:isherwoodMcBacon 更新时间:10/31/2023 访问量:52
构造函数原型的更改会影响实例化的对象吗?
Will change of constructor's prototype influence the instantiated object?
问:
如果我有一个带有定义原型的函数(构造函数),假设:
function Student(name) {
this.name = name;
}
Student.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
}
我使用该函数实例化和对象(据我所知,它应该在创建时将新创建的对象的属性设置为上述原型对象,并将属性设置为函数)。_prototype
constructor
Student
const s1 = new Student('John');
s1.sayHello();
我确定调用会起作用,但是,如果我像这样更改原型怎么办?sayHello()
Student
Student.prototype.sayGoodbye = function() {
console.log(`Goodbye, my name is ${this.name}`);
}
应该可以打电话吗?s1
sayGoodbye
我已经读到不应该改变,所以在这个逻辑中它应该抛出一个错误,但是,在 Chrome 的控制台面板和 node.js 项目中尝试它,它工作并且 s1 可以调用 .有人可以帮我理解这一点吗?_prototype
sayGoodbye
答:
我不确定是什么意思。你的意思是 ?或?这两者是不同的东西(并且被弃用,取而代之的是 和 ,以及类似的方法)。_prototype
.__proto__
.prototype
.__proto__
Object.getPrototypeOf
Object.setPrototypeOf
Reflect
“改变原型”有几种不同的含义。
将 ,如,替换为 。除了对可读性的可能影响之外,还有性能因素,MDN 的警告中总结了这一点:
[[Prototype]]
Object.setPrototypeOf
警告:根据现代 JavaScript 引擎优化属性访问的本质,更改对象目前在每个浏览器和 JavaScript 引擎中都是非常缓慢的操作。此外,更改继承的影响是微妙而深远的,不限于在语句中花费的时间,而是可以扩展到任何可以访问任何已被更改的对象的代码。您可以在 JavaScript 引擎基础知识:优化原型中阅读更多内容。
[[Prototype]]
Object.setPrototypeOf(...)
[[Prototype]]
由于此功能是语言的一部分,因此引擎开发人员仍然需要高性能地(理想情况下)实现该功能。在引擎开发人员解决此问题之前,如果您担心性能,则应避免设置对象。相反,请使用 创建一个具有所需 的新对象。
[[Prototype]]
[[Prototype]]
Object.create()
通过替换或添加属性来修改内置对象或库对象。不鼓励这样做,主要是因为它不是面向未来的。例如,是一个非常有用的函数,它在 2012 年并不存在。如果有人将它添加到数组原型中,那么它会很有用,但是当它在几年后实现时,任何自己定义的人都会用效率较低的代码替换效率更高的代码。
[[Prototype]]
Array.prototype.find
Array.prototype.find
您可以防范它,并且仅在尚未定义函数时才替换该函数,但可能会出现不兼容问题。当 now-standard 找不到匹配的元素时,它将返回。如果你的 polyfill 正在返回,但你不理会内置的,以防它存在,并且你的代码在 和 上的行为不同,你就有问题了。
.find
undefined
null
.find
null
undefined
通过定义或替换原型上的属性来修改您自己的对象。这似乎是您在问题中使用的含义。耸肩。这是你的代码。
[[Prototype]]
是的,对原型属性的任何更改都将反映在原型对象中,除非它们被原型对象上的属性所掩盖。正如 deceze 在他们的评论中解释的那样,原型属性在创建时不会复制到原型对象上。相反,在查找时,在原型对象上检查该属性,然后在原型上检查,然后在原型的原型上检查该属性,直到找到它(或者,如果在根对象到达链的末尾之前找不到此类属性,则返回)。因此,如果将属性添加到原型中,则添加属性的时间(无论是在创建原型对象之前还是之后)都没有区别,只要是在访问该属性之前。
undefined
作为您问题的答案“s1 应该能够呼叫 sayGoodbye 吗? 是的,它应该。 要弄清楚为什么。你必须了解 [[prototype]] 链。任何构造函数,如您的函数:
function Student(name) {
this.name = name;
}
是具有 .prototype 属性的对象。该构造函数的任何实例都将具有一个属性,该属性将指向该属性,而该属性又指向 Object.prototype([[prototype]] 链的末尾)。
现在,当你向该链中的任何原型节点添加一个属性时 - 假设 - 它将被实例看到,因为当你像这样调用它时: ,JS 引擎将在 Student 对象中查找它,如果它没有找到它,那么引擎将在引用的对象中查找它, 在我们的例子中,如果它也没有在那里找到它,它将继续在 [[prototype]] 链中徘徊,直到它找到它或到达链的末端,即 .var student = new Student("name");
__proto__
Student.prototype
__proto__
sayGoodbye
student
student.sayGoodbye()
student.__proto__
Student.prototype
Object.prototype
评论