【问题标题】:Extending prototype on object literal在对象文字上扩展原型
【发布时间】:2015-04-30 21:16:44
【问题描述】:

如果我有以下代码,为什么它返回一个错误,说 Cannot set property 'second_prop' of undefined 。我认为您可以扩展原型属性并为对象原型添加更多变量和方法。既然两个console语句都返回'Object'和true,那为什么会返回undefined的错误。我的想法是,如果“obj”是 Object 类型的对象,那么我应该能够做 temp.prototype.newproperty?因此,对象将具有“新属性”。但我显然错了,所以我在这里遗漏了一些东西。 更重要的是,当 obj 已经是对象文字时,为什么我需要执行 Object.create() ?不是已经是对象了吗?我只是在看一些例子并试图理解这一点

    var obj = {
        first_property: 'first property'
    }
    console.log(typeof obj);
    console.log(obj instanceof Object);

    var temp = Object.create(obj);
    temp.prototype.second_prop = 'second property'

输出

//object
//true
//Uncaught TypeError: Cannot set property 'second_prop' of undefined

那么,为什么我不能做 temp.prototype 或 obj.prototype?

【问题讨论】:

标签: javascript html object web object-construction


【解决方案1】:

如果我有以下代码,为什么它返回一个错误说 无法设置未定义的属性“second_prop”

Javascript 文字对象已经是一个实例化的对象,并且没有.prototype 属性。该属性位于构造函数上,而不是已经实例化的对象。在当前任何浏览器(IE9+)中,您都可以使用Object.getPrototypeOf() 来获取已构建对象的原型。

但是,这听起来更像是您宁愿克隆一个对象,然后向克隆添加属性。或者,如果您希望两个对象具有相同的附加属性,则添加该属性,然后克隆它。或者,如果你只是想使用你的文字对象,那么就照原样使用它。

一旦一个对象已经被构建,原型就是一个内部属性,它通常不意味着你会弄乱它。如果您打算更改所有对象的原型,则应该更改构造函数的原型。如果您只想更改对象的这个实例的属性,那么只需更改对象本身的属性,而不是原型。

与往常一样,如果您描述您实际想要完成的任务(而不是为什么您自己的解决方案没有达到您的预期),我们可以为您提供更好的帮助。

我认为你可以扩展原型属性并添加更多 对象原型的变量和方法。

可以,但.prototype 属性位于构造函数上,而不是已构建的对象上。

既然两个控制台语句都返回'Object'和true,那为什么 它是否返回未定义的错误。我的想法是,如果 'obj' 是 对象类型的对象,那么我应该能够做到 temp.prototype.newproperty?

您将作为实例化对象与作为具有原型的构造函数混淆了。实例化对象有一个原型作为内部属性,而不是公共.prototype 属性。因此,当某事物报告 instanceof 时,这意味着它实际上是该类型对象的实例(因此在其内部原型链中具有该类型对象原型),而不是具有公共 .prototype 属性的构造函数。

更重要的是,当 obj 已经存在时,为什么我还需要执行 Object.create() 对象文字?不是已经是对象了吗?

Object.create() 的目的是创建一个新对象,使用现有对象作为原型。如果您被声明为 Javascript 文字并且您只想将文字本身用作对象,那么没有理由在其上使用 Object.create()。只需使用字面量作为已构建的对象即可。

【讨论】:

  • 现在我们说“普通”浏览器 :-) “新”浏览器会实现 Reflect.setPrototypeOf (ES6),只有旧浏览器不支持 ES5。
  • @Bergi - 我使参考更加具体(IE9+)。连 ES6 浏览器都会支持Object.getPrototypeOf(),对吧?
  • 是的,ES6 是向后兼容的,所以他们肯定会实现 ES5 Object.getPrototypeOf
  • @user1142130 - 我在回答中添加了更多细节,以解决您问题的各个方面。如果您还需要更多解释,请告诉我。
【解决方案2】:

temp 没有原型。对象有一个原型。您可以通过调用Object.prototype 来更改所有对象的原型,但不能只更改一次对象。

【讨论】:

  • 它确实有一个原型 (obj),但没有一个 .prototype 属性。
  • temp 确实继承自 obj,后者继承自 Object.prototype,后者继承自 null
  • @Bergi 在您的控制台中,执行var temp = Object.create({}) 然后尝试拨打temp.prototype。你会发现它不存在。现在,如果你愿意,你可以创建它……你可以做temp.prototype = {}; temp.prototype.second_prop = 'second_property';,但它的行为就像一个普通的对象键,而不是实际的对象原型
  • @Bergi temp 什么都不继承。它是一个引用,而不是 Object 本身的扩展。
  • @MatthewHerbst:我没有说有temp.prototype,我确实说过temp 对象确实有一个原型——即obj。因为这就是Object.create 的工作原理……
【解决方案3】:

.prototype 是一个并不总是链接到对象的实际原型的属性。真正的原型可以通过.__proto__访问

var obj = {
    first_property: 'first property'
}
console.log(typeof obj);
console.log(obj instanceof Object);

var temp = Object.create(obj);

temp.__proto__.second_prop = 'second property';

console.log(Object.getPrototypeOf(temp));

//{ first_property: 'first property',
//second_prop: 'second property' }

【讨论】:

  • 最好只使用Object.getPrototypeOf,永远不要提及__proto__
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-24
  • 2015-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多