【问题标题】:Pushing to a Javascript array that has a __proto__推送到具有 __proto__ 的 Javascript 数组
【发布时间】:2014-10-18 12:36:35
【问题描述】:

好吧,我在这里杀了我的大脑,我有一个数组

var myArray = ['Bob', 'Sue', 'Jim'];
myArray.__proto__ = new Entity();

//Entity looks something like this
Entity = function(){
   this.isChanged = false;
   this.add = function(newPerson){
      alert(this.length); //alerts with 3
      alert(JSON.stringify(this)); //alerts a {}
      this.push(newPerson); 
      this.isChanged = true;

  }
}

push 在一个对象上不存在,但它显然是一个数组,根据返回 3 的警报。

非常好奇如何访问我的数组,这要归功于我的 proto

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    感谢我的__proto__,如何访问似乎被对象包裹的数组

    它没有被包装——它只是因为你对__proto__的修改而失去了它的身份。该数组现在继承来自您的 new Entity 实例,而不是来自 Array.prototype

    如果你想在上面调用Array 方法,你必须使用.call

    Array.prototype.push.call(this, newPerson);
    

    但是,无论如何,您的继承实现是有问题的。即使您使用数组对象和mutate its [[prototype]],您也应该这样做

    var myArray = new Entitiy(['Bob', 'Sue', 'Jim']);
    
    // Entity looks like this
    function Entity(arr) {
        if (!Array.isArray(arr)) {
            arr = [];
            // maybe:
            // arr.push.apply(arr, arguments);
        }
        arr.__proto__ = Entity.prototype;
        arr.isChanged = false;
        return arr;
    }
    Entity.prototype = Object.create(Array.prototype);
    Entity.prototype.constructor = Entity;
    Entity.prototype.add = function(newPerson) {
        alert(this.length); //alerts with 3
        alert(JSON.stringify(this)); //alerts a ["Bob","Sue","Jim"]
        this.push(newPerson);
        this.isChanged = true;
    };
    

    【讨论】:

    • 非常好!谢谢!这正是我想要的。如果我发布了完整的代码,您会看到我正在尝试将 Entity 用于对象和数组。一些属性确实不需要被数组继承,所以为了变得更简单,事情变得非常奇怪哈哈。
    【解决方案2】:

    数组没有被包装,它不再是一个数组! __proto__ 是一个 deprericated getter/setter 对,用于访问内部对象 [[Prototype]]。由于您分配了一个值,因此使用了 setter,您只需使用 Entity 的实例覆盖其完整原型。这就是为什么push()(以及所有其他:pop()、splice()、...)不再存在的原因。

    为什么alert(this.length);works ? length 不是 Array.prototype 的属性,而是每个 Array 实例自己的属性。所以它不会被改变原型覆盖/删除,你的“东西”仍然有长度。您可以通过以下方式进行检查:

    console.log(Object.getOwnPropertyNames(myArray)); // --> ['0', '1', '2', 'length']
    

    当然,您可以访问“事物”的属性,例如console.log(myArray[1]) // --> 'Sue'或分配新属性,但您必须为此使用对象方法。因此,如果在 Entity() 而不是 this.push(newPerson) 中使用 this[this.length] = newPerson 它会起作用。

    Reference for __proto__ here.

    【讨论】:

    • MDN 可能已经过时,__proto__ 以某种形式被编入 es 6 规范 stackoverflow.com/questions/13839115/…
    • @JaredSmith:请注意,这个答案来自 2012 年,ES6 已经继续前进。改变 [[prototype]] 应该使用 Reflect.setPrototypeOf 完成,__proto__ 仍然被弃用(但已编码 - 标准化 - 用于Annex B 中的网络遗留兼容性)
    • 谢谢大家!我从工具包中删除了 proto,现在使用新版本。
    猜你喜欢
    • 2020-05-11
    • 2011-07-07
    • 2015-10-22
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多