【问题标题】:Why assignment to the doesn't the object __proto__ doesn't work? [duplicate]为什么分配给对象 __proto__ 不起作用? [复制]
【发布时间】:2020-07-16 11:15:04
【问题描述】:

案例 1 :- 最初在对象文字中,我将 __proto__ 分配给 null,然后我尝试将其重新分配给 animal,但这是行不通的。

'use strict'
let animal = {
    eats: true,
    walk(){
        console.log('Animal Walk');
    }
}

let rabbit = {
    jumps: true,
    __proto__: null
}

rabbit.__proto__ = animal
console.log(Object.getPrototypeOf(rabbit))
rabbit.walk()

案例 2:- 现在我在对象字面量中将 __proto__ 分配为 animal,然后我尝试将其重新分配给 null,在这种情况下它会将 __proto__ 更改为 null

'use strict'
let animal = {
    eats: true,
    walk(){
        console.log('Animal Walk');
    }
}

let rabbit = {
    jumps: true,
    __proto__: animal
}

rabbit.__proto__ = null
console.log(Object.getPrototypeOf(rabbit))
rabbit.walk()

案例 3:- 当我使用 Object.setPrototypeOf() 时,它工作正常

'use strict'
let animal = {
    eats: true,
    walk(){
        console.log('Animal Walk');
    }
}

let rabbit = {
    jumps: true,
    __proto__: null
}

Object.setPrototypeOf(rabbit, animal)
console.log(Object.getPrototypeOf(rabbit))
rabbit.walk()

为什么分配在第一种情况下不起作用?

【问题讨论】:

  • 不应该是动物.__proto__ 而不仅仅是动物吗?
  • @TheoWckr naah,我删除 rabbit.__proto__ = null 行确实可以正常工作。我需要将原型设置为animal 而不是animal's prototype
  • @TheoWckr - 如果 Code Maniac 想要 animal,而不是它的原型,则不是 rabbit 的原型,他们似乎是这样的(因为 animalwalk,但它的原型没有't)。

标签: javascript object prototype


【解决方案1】:

好的,这有点棘手。 :-) 您的代码使用了两种不同的 __proto__ 含义:

  1. __proto__ token in object literals可以指定对象的初始原型,以及
  2. __proto__ accessor property(在创建对象后获取/设置它时)

rabbit.__proto__ = animal 没有改变rabbit 的原型的原因是__proto__Object.prototype 定义的访问器属性。由于您在没有任何原型的情况下创建rabbit(通过在对象文字中使用__proto__: null),rabbit 不会继承该访问器,因此rabbit.__proto__ = animal 只是在rabbit 上创建一个名为__proto__ 的属性,而不是更改它的原型。

__proto__ 的这两个含义都是旧版的仅限 Web(附件 B)兼容性的东西。使用Object.create(创建具有特定原型的对象)、Object.getPrototypeOf 和(如果无法避免更改对象的原型)Object.setPrototypeOf。浏览器之外的 JavaScript 引擎不需要实现像 __proto__ 这样的附件 B 功能(尽管根据我的经验,引擎不会在浏览器之外禁用大部分功能)。

【讨论】:

  • The __proto__ property can also be used in an object literal definition to set the object [[Prototype]] on creation, as an alternative to Object.create(). See: object initializer / literal syntax.。我想知道__proto__ MDN 的这些台词
  • @CodeManiac - 没错,就是first meaning I linked above。这是一个附件 B 功能,这意味着(官方)只有 Web 浏览器中的 JavaScript 引擎应该支持它(尽管根据我的经验,引擎不会禁用浏览器之外的大多数附件 B 功能)。您已成功使用该功能创建 rabbit,因此,rabbit 没有任何原型——这意味着它不继承 __proto__other 含义,所以分配给__proto__ 并没有什么特别的作用。
  • If propKey is the String value "__proto__" and if IsComputedPropertyKey(PropertyName) is false, then Let isProtoSetter be true. 不是说我们在这里设置原型吗?因此,如果我设置__proto__ : animal 并删除rabbit.__proto__ = null,则代码可以正常工作并且rabbit.walk() 可以访问。
  • @CodeManiac - 是的。正如我上面所说:“由于您创建 rabbit 没有任何原型(通过在对象字面量中使用 __proto__: null)...” 稍后分配给 __proto__ 的原因不起作用是在创建之后,rabbit 不会从 Object.prototype 继承,这是定义访问器属性的原因(上面链接的第二个含义)。
  • 啊这意味着如果我使用__proto__: null 它只是不会继承与Object.create(null) 相同的原型,所以现在如果我使用rabbit.__proto__ = animal 它只会创建一个新密钥并且不修改实际原型.另一方面,如果将其设置为__proto__ : animal,它确实会将其添加到prototype,而当我设置rabbit.__proto__ = null 时,它确实会修改实际原型,我做对了吗?
【解决方案2】:

我认为,因为__proto__ 只能在构造函数属性中设置。你不能设置它。 setter 不能在constructor 之外工作。但是,setPrototypeOf 是一个扩展的 util 函数,用于创建原型属性。 这里setPrototypeOf set proto(override) 如果可用,否则它使用原型创建新类。

来自developer.mozilla.org

if (!Object.setPrototypeOf) {
    // Only works in Chrome and FireFox, does not work in IE:
     Object.prototype.setPrototypeOf = function(obj, proto) {
         if(obj.__proto__) {
             obj.__proto__ = proto;
             return obj;
         } else {
             // If you want to return prototype of Object.create(null):
             var Fn = function() {
                 for (var key in obj) {
                     Object.defineProperty(this, key, {
                         value: obj[key],
                     });
                 }
             };
             Fn.prototype = proto;
             return new Fn();
         }
     }
}

【讨论】:

  • “我认为,因为 proto 仅在构造函数属性中。你不能设置它。” 是的,你可以。如果您不从 Object.prototype 继承(或以其他方式将 __proto__ 定义为访问器属性),则不能。
  • 但是看mozila的定义,他们也没有创建。否则在这里创建一个新类。
  • "但是看mozila的定义,他们也没有创造" 恐怕我不明白你的意思,但我对管道的理解很深刻__proto__ 来自阅读规范。有关 OP 代码中发生的情况,请参阅我的答案。
  • @xdeepakv,这里不是这样,T.J 的回答很好地解释了我的代码中发生的事情,无论如何感谢您的时间,我很感激✌️ p.s. :虽然我不是反对者:p
  • @CodeManiac:我也对你的问题投了反对票 :) p.s back ;) :P 所以不用担心。继续编码!
猜你喜欢
  • 1970-01-01
  • 2018-04-16
  • 2014-03-17
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多