小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
前端程序员,可能没有谁没没复制对象吧? 今天就一天来学习学习对象的复制。
此对象,非彼对象。
为什么要进行复制
什么时候需要进项对象的复制??
- 不破坏原数据 原始数据可能还需要在别处使用,如果进行了更改,可能导致意外的结果。 比如函数的参数,构造函数的参数等等。
函数式编程中有一个重要的概念,副作用, 无副作用,其中有一条就是不要修改入参。
- 需要基于当前数据,创建新的数据,用于他用。
浅复制
Object.assign
ES6新增的方法,大家都说是浅复制,其不能复制原型上的方法。
语法:
Object.assign(target, ...sources)
target: 目标对象,null, undefined会报错,其余均会先转为Objectsources: 多个源对象,任何数据均可, 非object类型会被忽视,
其实如果只有一级属性,且值都是非引用类型,他就是深复制。
var obj = {a:1, b:2};
var obj2 = Object.assign({}, obj);
就结果上说,是深复制哈。
其除了第一个参数,其余参数是null, undefined也不会报错,真的是比较贴心。
// null 和 undefined作为一个参数,报错
Object.assign(null, {a:1}) // Uncaught TypeError: Cannot convert undefined or null to object
Object.assign(undefined, {a:1}) // Uncaught TypeError: Cannot convert undefined or null to object
// 多个源对象
Object.assign({}, {a:1}, {b:2}) // {a:1, b:2}
// source非对象类型被忽视
Object.assign({}, null, undefined, 1, false, 10n, '') // {}
// function 如果是有属性,也是会被复制的
function a(){}
a.bbbb = 1;
Object.assign({}, a); // {bbbb: 1}
自己实现浅复制
我们也可以自己实现一个,这里直接借用MDN的代码,比较清晰和完善。 大致有三个注意点,代码中均标记出来了.
function assign(target, varArgs) { //
'use strict';
if (target === null || target === undefined) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target); // 注意点1:先转为对象
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) { // 注意点2: for in 遍历
// Avoid bugs when hasOwnProperty is shadowed
// 注意点3: hasOwnProperty 判断是不是自身属性
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
}
基本原理就是 for in 获取属性键,然后Object.prototype.hasOwnProperty判断是不是自有属性, 满足条件就进行复制,反之跳过。
这里就提一个问题:
Object.assign能否复制 Symbol类型的属性???
答案是支持, 而上面的MDN的代码中显然是不支持的? 为什么?
因为 for in 并不能遍历出Symbol类型的属性键。 你想想,你要自己实现 Object.assign前提肯定是其不被支持,既然不被支持,其不备支持,当然 Symbol也不会被支持,因为他们都是ES6才出现的啊。
小结
今天你收获了吗?