即使在使用闭包之后,对象值也不会更新

时间:2015-12-30 21:06:42

标签: javascript

var repeatelem = function(elem, n){
            // returns an array with element elem repeated n times.
            var arr = [];
            for (var i=0; i<n; i++) {
              (function(newValue, index){
                                console.log(index)
                                Object.defineProperty(newValue, 'reasonId', {
                                    value:index,
                                    configurable:true
                                });
                              arr = arr.concat(elem);
                        }(elem, i))

            };
            return arr;
        };
        var res = repeatelem({a:1},3)
        console.log(res)

输出: OUTPUT

我除了reasonId是0,1,2。 不确定,为什么即使在使用闭包后,reasonId的值设置为最后一个索引值也存在问题。

Plunkr

例外:

[{a:1,'reasonId':0 }, {a:1,'reasonId':1 }, {a:1,'reasonId':2 }]

1 个答案:

答案 0 :(得分:1)

包含对象的Javascript变量,实际上包含对象的引用,因此您可以正确复制i的值,但elemnewValue是相同的宾语。没有复制。

所以当你运行arr.concat(elem)(我认为你的意思是arr.concat(newValue))时,你会反复将同一个对象连接到你的数组中。

在将对象附加到数组之前,需要复制对象。 见How do I correctly clone a JavaScript object?。在您的情况下,关闭也是不必要的;当循环中存在异步代码时,通常用于解决问题。您可以将代码简化为:

var repeatelem = function(elem, n){
    // returns an array with element elem repeated n times.
    var arr = [];
    for (var i=0; i<n; i++) {
        var copy = Object.assign( {}, elem );
        Object.defineProperty( copy, 'reasonId', {
            value: i,
            configurable: true
        });
        arr.push( copy );
    }
    return arr;
};

其中Object.assign用于制作浅表副本。它是一个ES6函数,可以是shimmed for this use-case。请注意,这只是一个浅层副本,如果元素可以在自己的属性中包含对象,则可能需要深层复制,否则每个元素将彼此共享其子对象,因此当您修改一个子对象时,它们都会更改