探索Object.assign()

extend obj

起因

最近在重构以前写过的javascript代码,目的是为了去掉对jQuery的依赖。其中有多处用到了$.extend()方法,自然而然会想到这么一个问题:如何用自己的方式来实现?

思路

首先,定义函数的功能:传入多个对象,将多个对象的内容合并到第一个对象中,最后返回合并后的对象,即参数中的第一个对象。这样的定义是否似曾相识?没错,和ES6中的新特性Object.assign()几乎一模一样。所以,可以从探索Object.assign()开始。

探索Object.assign()

Object.assign(target, ...sources)

使用场景

拷贝对象

只需要传入的第一个参数是空对象即可:

1
2
3
var obj = { foo: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { foo: 1 }

合并对象

注意第一个传参将会被改变,所以如果不想改变第一个有值参数,可以传入一个空对象:

1
2
3
4
5
6
7
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意第一个参数,即o1有了变化。

注意事项

1
2
3
4
5
6
7
8
9
10
11
12
var obj = Object.create({ foo: 1 }, { // foo是obj原型链上的属性
bar: {
value: 2 // bar 是非可枚举(non-enumerable)属性.
},
baz: {
value: 3,
enumerable: true // baz是可枚举属性.
}
});
var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 },只拷贝了baz属性
  • 元类型会被转化为对象
1
2
3
4
5
6
7
var v1 = 'abc';
var v2 = true;
var v3 = 10;
var obj = Object.assign({}, v1, null, v2, undefined, v3);
//元类型里面的字符串被转化为字符数组,null和undefined被忽略
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
  • 异常会抛出,但是已经执行的代码会生效
1
2
3
4
5
6
7
8
9
10
11
12
13
var target = Object.defineProperty({}, 'foo', {
value: 1,
writable: false
}); // target.foo 为只读属性
Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// 会抛出异常:TypeError: "foo" is read-only,但是之前的赋值操作已经生效。
console.log(target.bar); // 2
console.log(target.foo2); // 3
console.log(target.foo); // 1, 异常就是在这儿发生的,所以还是1
console.log(target.foo3); // undefined
console.log(target.baz); // undefined

pollyfill

上面是对Object.assign()概念层面的探索,由于要考虑旧版本浏览器兼容性问题,需要写一个pollyfill,其实这才是重头戏。不过,只有理解了Object.assign()都干了些什么,才有可能写出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(function () {
if (typeof Object.assign != 'function') {
Object.assign = function (target) {
//第一个传参不能是undefined和null,因为它们不能被转为对象
if (target === undefined || target === null) {
throw new TypeError('Can not convert undefined or null to object');
}
//使用Object对象化target
var output = Object(target);
for (var idx = 1,l=arguments.length; index < l; idx++) {
var source = arguments[idx];
//后续传参也需要判断undefined和null
if (source !== undefined && source !== null) {
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
output[key] = source[key];
}
}
}
}
return output;
};
}
})();

结束

好了,现在可以在宿主环境大胆使用Object.assign()了,Let’s rock it~~~

参考链接:

MDN:Object.assign()

微信环境下长按识别或保存

微信支付二维码
支付宝支付二维码