简体   繁体   中英

Issue with reference of copied object

I need to copy an object and its methods. Hence i stringify the object and then parse it and add the methods from the original object (but bound to this new copy).

// Taken from: https://stackoverflow.com/questions/31054910/get-functions-methods-of-a-class
function getAllMethods(obj) {
    let props = [];

    do {
        const l = Object.getOwnPropertyNames(obj)
        .concat(Object.getOwnPropertySymbols(obj).map(s => s.toString()))
        .sort()
        .filter((p, i, arr) =>
                typeof obj[p] === 'function' &&  //only the methods
                p !== 'constructor' &&           //not the constructor
                (i == 0 || p !== arr[i - 1]) &&  //not overriding in this prototype
                props.indexOf(p) === -1          //not overridden in a child
               )
        props = props.concat(l)
    }
    while (
        (obj = Object.getPrototypeOf(obj)) &&   //walk-up the prototype chain
        Object.getPrototypeOf(obj)              //not the the Object prototype methods (hasOwnProperty, etc...)
    )

        return props;
}

function copyObject(obj) {
    var copy = JSON.parse(JSON.stringify(obj));

    // Copy all methods
    getAllMethods(obj)
        .filter(prop => typeof obj[prop] === 'function')
        .forEach(prop => copy[prop] = obj[prop].bind(copy));

    return copy;
}

And here some tests:

var foo = { bar:2, f: function() { this.bar = 5 } }
var bar = copyObject(foo);
var baz = copyObject(bar);

bar.f();
bar.bar; // 5

baz.f();
baz.bar; // 2 instead of 5..?!
baz.f.apply(baz); // not working either, baz.bar still 2

Why does a copy of a copy not work as i would expect?


EDIT: In baz.f the this reference is still bound to bar for some reason.

It doesn't work because you can only .bind() the this value on a function once. The this value is basically set in stone the first time you use bind() and after that, you're just "painting another layer" on top of the already-bound function:

 function myFunc() { console.log(this.a); } var f1 = myFunc.bind({ a: 5 }); var f2 = f1.bind({ a: 6 }); f1(); f2(); 

Also keep in mind that you can't rebind this on arrow functions at all:

 var a = 2; var myFunc = () => { console.log(this.a); } var f1 = myFunc.bind({ a: 5 }); var f2 = f1.bind({ a: 6 }); f1(); f2(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM