JavaScript call方法的奇怪行为

3

我最近在阅读《高效JavaScript》。在关于“使用具有自定义接收器的call方法”的部分,作者提供了一个使用此方法将一个表格的内容添加到另一个表格中的示例:

var table = {
    entries: [],
    addEntry: function(key, value) {
        this.entries.push({key: key, value: value});
    },
    forEach: function(f, thisArg) {
        var entries = this.entries;
        for (var i = 0, n = entries.length; i < n; i++)
        {
            var entry = entries[i];
            f.call(thisArg, entry.key, entry.value, i);
        }
    }
};

现在,如果我编写像这样的内容来测试此方法:

现在如果我测试这个方法写入诸如:

table2 = table;
table1 = table;
table1.entries = [1, 3];
table1.forEach(table1.addEntry, table2);
console.log(table2.entries);

我以[1,3,Object,Object]的形式获取了table2条目的内容,这让我感到困惑。为什么会有两个额外的对象?可能我的调用方法不正确。有人能解释一下正在发生什么吗?
2个回答

2
原因是:
table2 = table;
table1 = table;
table2table1 指向同一个对象 => 你正在向同一个 table 对象添加内容。
之所以会得到最终的两个对象,是因为你的添加条目创建了新的对象。
{key: key, value: value}

你的最终结果应该是这样的:
[1, 3, {0:1}, {1:3}]

{0:1},{1:3}: 0和1是索引


谢谢,我忘了那个。 - abdelk

1

table1table2 都引用了 table,所以当你调用:

table1.entries = [1, 3];

它实际上也将这些条目添加到table2中。 为了解决这个问题,使用new关键字:
table2 = new table;
table1 = new table;

此外,为什么你得到的是[1, 3, Object, Object]而不是[1, 3, 1, 3],是因为addEntry方法添加的是对象,而不仅仅是像你所做的那样的数字。
{key: key, value: value}

每个条目的格式实际上是一个对象。 如果你想看到有意义的东西而不是“Object”,请对条目数组进行字符串化。
console.log(JSON.stringify(table2.entries));

1
在JavaScript中不能以那种方式使用new关键字。要进行克隆,请使用类似于var table2 = {},k; for(k in table){table2 [k] = table [k];}的内容。 - tom
是的,我正要问同样的问题,因为我得到了“对象不是一个函数”。很好你澄清了。 - abdelk
真的 :) 我没有注意到 table 不是一个函数。尽管在实际应用中应该是这样的。 - Alon Gubkin
1
虽然如果你有多个实例,最好的方法是实际编写一个类(然后正确使用 new)。克隆对象有些棘手,@tom 的解决方案只是一个简单的尝试(我猜这就是他说“something like”的原因)。 - Ingo Bürk
确实。我的简单克隆是浅层的,无法创建一个新的“entries”数组。这里是使用类似Alon和Ingo建议的实现:http://jsfiddle.net/6YTFd/ - tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接