有如果需要将一个对象的所有属性,拷贝到另一个对象,需要手动实现。例如:
var extend = function (to, from) { for (var property in from) { to[property] = from[property]; } return to; } extend({}, { a: 1 }) // {a: 1}
上面方法的问题在于,如果遇到存取器定义的属性,只会拷贝值。例如:
extend({}, { get a() { return 1 } }) // {a: 1}
为了解决这个问题,我们可以通过Object.defineProperty方法来拷贝属性。
var extend = function (to, from) { for (var property in from) { Object.defineProperty( to, property, Object.getOwnPropertyDescriptor(from, property) ); } return to; } extend({}, { get a(){ return 1 } }) // { get a(){ return 1 } })
这段代码还是有问题,拷贝某些属性时会失效。
extend(document.body.style, { backgroundColor: "red" });
上面代码的目的是,设置document.body.style.backgroundColor属性为red,实际上网页的背景色并不会变红。如果用第一种简单拷贝的方法,反而能够达到目的。因此可以把两种方法结合起来,对于简单属性,就直接拷贝,对于那些通过属性描述对象设置的属性,使用Object.defineProperty方法拷贝。例如:
var extend = function (to, from) { for (var property in from) { var descriptor = Object.getOwnPropertyDescriptor(from, property); if (descriptor && ( !descriptor.writable || !descriptor.configurable || !descriptor.enumerable || descriptor.get || descriptor.set)) { Object.defineProperty(to, property, descriptor); } else { to[property] = from[property]; } } }
上面的这段代码,可以很好地拷贝对象所有可遍历(enumerable)的属性。