Underscore对于object的extend之坑

之前在处理两个object的合并时,通常使用underscore的extend方法,但其实这个方法并不是深度合并(拷贝),在以下场景中将会出现问题。

有如下两个object:

a = {
    attribute: {
        border: {
            width: 2, 
            color: 'red'
        }, 
        width: 300, 
        height: 100
    }
};
b = {
    attribute: {
        border: {
            width: 3
        }
    }
}

现在需要用b来更新a,具体的场景可能为:a是某一个数据结构,现在需要修改其中的border的width,为了使修改操作更具有鲁棒性,使用一个有相同结构但不完整的b进行操作。考虑使用underscore的extend方法:

a = _.extend(a, b);

这将会得到以下结果:

a = {
    attribute: {
        border: {
            width: 3
        }
    }
};

注意到,虽然width被修改了,但是color却丢失了。原因在于,extend函数找到了attribute这个key是a与b共同拥有的,并且不想等,于是它以b的为准,修改了a的attribute值,并没有继续深入查询。

解决的方法,一个是自己写拷贝修改函数(比如递归实现),另一个方法是使用jQuery的extend,可以指定深度搜索模式

a = $.extend(true, {}, a, b);