什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。


当前回答

我使用npm克隆图书馆,显然它也在浏览器中工作。

https://www.npmjs.com/包装/克隆

let a = clone(b)

其他回答

Shallow copy one-lineer (ECMAScript 第五版):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

并下载单线复制(ECMAScript 第六版,2015年):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

我的场景略有不同,我有一個物體,擁有<unk>的物體以及功能,因此,Object.assign() 和 JSON.stringify() 並沒有解決我的問題。

因此,我决定做一个简单的功能,使用内置的方法来复制一个对象,其字面特性,其粘着的对象和功能。

let deepCopy = (target, source) => {
    Object.assign(target, source);
    // check if there's any nested objects
    Object.keys(source).forEach((prop) => {
        /**
          * assign function copies functions and
          * literals (int, strings, etc...)
          * except for objects and arrays, so:
          */
        if (typeof(source[prop]) === 'object') {
            // check if the item is, in fact, an array
            if (Array.isArray(source[prop])) {
                // clear the copied referenece of nested array
                target[prop] = Array();
                // iterate array's item and copy over
                source[prop].forEach((item, index) => {
                    // array's items could be objects too!
                    if (typeof(item) === 'object') {
                        // clear the copied referenece of nested objects
                        target[prop][index] = Object();
                        // and re do the process for nested objects
                        deepCopy(target[prop][index], item);
                    } else {
                        target[prop].push(item);
                    }
                });
            // otherwise, treat it as an object
            } else {
                // clear the copied referenece of nested objects
                target[prop] = Object();
                // and re do the process for nested objects
                deepCopy(target[prop], source[prop]);
            }
        }
    });
};

下面是测试代码:

let a = {
    name: 'Human', 
    func: () => {
        console.log('Hi!');
    }, 
    prop: {
        age: 21, 
        info: {
            hasShirt: true, 
            hasHat: false
        }
    },
    mark: [89, 92, { exam: [1, 2, 3] }]
};

let b = Object();

deepCopy(b, a);

a.name = 'Alien';
a.func = () => { console.log('Wassup!'); };
a.prop.age = 1024;
a.prop.info.hasShirt = false;
a.mark[0] = 87;
a.mark[1] = 91;
a.mark[2].exam = [4, 5, 6];

console.log(a); // updated props
console.log(b);

对于效率相关的担忧,我认为这是我遇到的问题的最简单和最有效的解决方案,我会欣赏任何关于这个算法的评论,这可能会使它更有效。

对于想要使用 JSON.parse(JSON.stringify(obj)) 版本的人,但没有失去日期对象,您可以使用 Parse 方法的第二个论点将行转换为日期:

function clone(obj) { var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/; return JSON.parse(JSON.stringify(obj), function(k, v) { if (typeof v === 'string' && regExp.test(v)) return new Date(v) return v; }) } // usage: var original = { a: [1, null, undefined, 0, {a:null}, new Date()], b: { c(){ return 0 } } } var cloned = clone(original) console.log(cloned)

如果你发现自己做这种类型的事情是正常的(例如,创建 undo redo 功能 ) 它可能值得看看 Immutable.js

const map1 = Immutable.fromJS( { a: 1, b: 2, c: { d: 3 } } );
const map2 = map1.setIn( [ 'c', 'd' ], 50 );

console.log( `${ map1.getIn( [ 'c', 'd' ] ) } vs ${ map2.getIn( [ 'c', 'd' ] ) }` ); // "3 vs 50"

https://codepen.io/anon/pen/OBpqNE?编辑器=1111

在我的经验中,一个重复版本大大超越了JSON.parse(JSON.stringify(obj))。这里是一个现代化的重复深对象复制功能,可以在单一线上匹配:

function deepCopy(obj) {
  return Object.keys(obj).reduce((v, d) => Object.assign(v, {
    [d]: (obj[d].constructor === Object) ? deepCopy(obj[d]) : obj[d]
  }), {});
}

这比JSON.parse方法快40倍。