3

I'm recently reading the "Effective javascript". In the item "Use call methods with a custom receiver". The author provides an example of adding the contents of one table to another using this method :

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);
        }
    }
};

Now if I test this method writing things like:

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

I get the contents of table2 entries as [1, 3, Object, Object]. Which confuses me. Why do we get those two additionnal objects. Probably, I didn't get the call method properly. Can someone explain to me what is happening ?

2 Answers 2

2

The reason is

table2 = table;
table1 = table;

table2 and table1 refer to the same object => you are adding to the same table object.

You get the final two objects is because your add entry create new object:

{key: key, value: value}

Your final result looks like this:

[1, 3, {0:1}, {1:3}]

{0:1},{1:3}: 0,1 are the indexes

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, I forgot about that.
1

Both table1 and table2 reference to table, so when you call:

table1.entries = [1, 3];

it actually adds these entries to table2 too.

To solve this, use the new keyword:

table2 = new table;
table1 = new table;

In addition, the reason you get something like [1, 3, Object, Object] instead of [1, 3, 1, 3] is because the addEntry method adds an object instead of just numbers like you did:

{key: key, value: value}

so the format of each entry is actually an object.

If you want to be able to see something meaningful instead of Object, stringify the entries array:

console.log(JSON.stringify(table2.entries));

5 Comments

The new keyword cannot be used that way in JavaScript. For cloning, use something like var table2 = {}, k; for (k in table) { table2[k] = table[k]; }
Yes, I was about to ask the same thing since I got 'object is not a funtion'. Good that you clarified.
True :) I haven't notest that table is not a function. Though it should be in a real application
Though if you have several instances of this, the best way would be to just actually write a class (and then use new correctly). Cloning objects is somewhat tricky and @tom's solution is only a simple attempt (I guess that's why he said "something like").
Indeed. My simple clone is shallow and fails to create a new entries array. Here is an implementation using a 'class' like Alon and Ingo suggest: jsfiddle.net/6YTFd

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.