Object.assign 是什么?
此处直接复制mdn文档的内容以下:
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
翻译一下也就是:
Object.assign()要领用于将一切可罗列属性的值从一个或多个源对象复制到目的对象。它会返回目的对象。
为了便于明白,此处贴出mdn的对Object.assign的polyfill
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
个中的Object组织函数为给定的值建立一个对象包裹器。假如值为null或undefined,它将建立并返回一个空对象,不然,它将返回一个Type对应于给定值的对象。假如该值已经是一个对象,它将返回该值。
举个栗子?
Object(1)
// Number {1}
Object('')
// String {"", length: 0}
Object(false)
// Boolean {false}
从polyfill的代码不难看出,Object.assign 就是将所传参数当中的对象的可罗列属性的值掩盖到第一个对象上,那末因为js当中的object,array是援用范例,所以对与对象,数组的掩盖实在只是掩盖了对数组,对象的援用,也即 浅copy
mdn栗子来一枚
var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };
var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
怎样完成深copy?
来个redux 当中reducer 嵌套数据更新的栗子?
add(state, { payload: todo }) {
const todos = state.a.b.todos.concat(todo);
const b = Object.assign({},state.a.b,{todos})
const a = Object.assign({},state.a,{b});
return Object({},state,{a});
},
上面的栗子当中concat()要领用于兼并两个或多个数组。此要领不会变动现有的数组,而是返回一个新的数组。能够明白为应用concat要领建立了一个新的todos数组,如许就能够防止对数据的修正影响到了旧的todos数组,然后将新的todos数组运用Object.assign 给新的b,以此,仅仅完成了sate对象中将深层次的todos的一个‘深copy’。
然则假如state另有其他的属性的值为对象或许数组,简朴的运用Object.assign 只是复制了一个援用。所以在写reducer的时刻须要只管防止state嵌套的太深,为了平安,我们能够运用 updeep来更新数据,或许直接运用不可变数据,此处不再多说,继承讨论Object.assign.
完成一个deepCopy?
前面讨论了对象当中单个属性值的深copy,然则假如有多个值,怎么办呢?一个一个手动找出来?固然不可啊,如许一点儿也不好玩儿
为了完成一个deepCopy,我们先简朴相识一下js的数据范例:
值范例:数值、布尔值、null、undefined。
基础范例值是指在栈内存保留的简朴数据段,在复制基础范例值的时刻,会拓荒出一个新的内存空间,将值复制到新的内存空间,举个栗子:
var a = 1;
var b = a;
a = 2;
console.log(a);//输出2;
console.log(b);//输出1;
援用范例:对象、数组、函数等。
用范例值是保留在堆内存中的对象,变量保留的只是指向该内存的地点,在复制援用范例值的时刻,实在只复制了指向该内存的地点,举个栗子:
var a={b:1}
var a2 = a;
a2.b = 2;
console.log(a) // 输出 {b: 2}
deepCopy
相识了js的数组范例以后,那末完成一个深copy实在重要就是处理援用范例的copy,数组和对象无穷往下拆,终究其属性也是值范例构成的。所以我们能够运用递归完成一个deepCopy
,下面就直接贴代码了,略烦琐,迎接?拍砖
function detectType(source) {
return Object.prototype.toString
.call(source)
.split(/[\[,\s,\]]/)[2]
.toLowerCase();
}
function deepCopy(source, copyDeep) {
var type = detectType(source);
if (!(type === 'object' || type === 'array')) {
return source;
}
var newObject = type === 'array' ? source.slice() :Object.assign({}, source);
if (!copyDeep) {
return newObject;
}
Object.keys(newObject).forEach(function (key) {
newObject[key] = deepCopy(newObject[key], true);
});
return newObject;
}