We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
浅拷贝技巧:数组concat slice,对象Object.assign()等; 深拷贝技巧:JSON.parse(JSON.stringify(arr1))。
concat slice
Object.assign()
JSON.parse(JSON.stringify(arr1))
如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。
我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
比如,数组的一些方法:concat、slice:
concat、slice
var arr = ["old", 1, true, null, undefined]; var newArr = arr.concat(); newArr.shift(); console.log(arr); // [ 'old', 1, true, null, undefined ] console.log(newArr); // [ 1, true, null, undefined ] var newArr2 = arr.slice(); console.log(newArr2); // [ 'old', 1, true, null, undefined ]
但是如果数组嵌套了对象或者数组的话,就会都受影响,比如:
var arrObj = [{ a: 1 }, { b: 2 }]; var newArrObj = arrObj.concat(); newArrObj[0].a = "aaa"; console.log(newArrObj); // [ { a: 'aaa' }, { b: 2 } ] console.log(arrObj); // [ { a: 'aaa' }, { b: 2 } ]
使用 JSON.stringify()和JSON.parse(),不管是数组还是对象,都可以实现深拷贝,但是不能拷贝函数,会返回一个 null:
JSON.stringify()
JSON.parse()
var arr1 = ["old", 1, true, ["old1", "old2"], { old: 1 }, function() {}]; var newArr1 = JSON.parse(JSON.stringify(arr1)); newArr1.shift(); console.log(arr1); // [ 'old', 1, true, [ 'old1', 'old2' ], { old: 1 }, [Function] ] console.log(newArr1); // [ 1, true, [ 'old1', 'old2' ], { old: 1 }, null ]
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
// target 目标对象,sources 源对象 Object.assign(target, ...sources);
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。
Object.assign
[[Get]]
[[Set]]
String 类型和 Symbol 类型的属性都会被拷贝。
// 赋值一个对象 const obj = { a: 1 }; const copy = Object.assign({}, obj); console.log(copy); // { a: 1 }
针对深拷贝,需要使用其他办法,如借助 JSON,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
obj1 = { a: 0, b: { c: 0 } }; let obj3 = JSON.parse(JSON.stringify(obj1)); obj1.a = 4; obj1.b.c = 4; console.log(JSON.stringify(obj3)); // {"a":0,"b":{"c":0}}
技巧型的拷贝,如上边使用的 concat、slice、JSON.stringify等,如果要实现一个对象或者数组的浅拷贝,该怎么实现呢?
concat、slice、JSON.stringify
思路:既然是浅拷贝,那就只需要遍历,把对应的属性及属性值添加到新的对象,并返回。
代码实现:
var shallowCopy = function(obj) { if (typeof obj !== "object") return; // 判断新建的是数组还是对象 var newObj = obj instanceof Array ? [] : {}; // 遍历obj,并且判断是obj的属性才拷贝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }; var arr20 = ["old", 1, true, ["old1", "old2"], { old: 1 }, function() {}]; var newArr20 = shallowCopy(arr20); console.log({ newArr20 }); // [ 'old', 1, true, [ 'old1', 'old2' ], { old: 1 }, [Function] ]
思路:如果是对象,通过递归调用拷贝函数
var deepCopy = function(obj) { if (typeof obj !== "object") return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] !== "object" ? obj[key] : deepCopy(obj[key]); } } return newObj; }; var obj = { a: function() {}, b: { name: "Tony", age: 10 }, c: [1, 2, 3] }; var newObj = deepCopy(obj); console.log(newObj); // { a: [Function: a], // b: { name: 'Tony', age: 10 }, // c: [ 1, 2, 3 ] }
extend 的用法:合并两个或者更多的对象的内容到第一个对象中。
jQuery.extend( [deep], target, object1 [, objectN ] )
var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; function isPlainObject(obj) { var proto, Ctor; if (!obj || toString.call(obj) !== "[object Object]") { return false; } proto = Object.getPrototypeOf(obj); if (!proto) { return true; } Ctor = hasOwn.call(proto, "constructor") && proto.constructor; return ( typeof Ctor === "function" && hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object) ); } function extend() { // 默认不进行深拷贝 var deep = false; var name, options, src, copy, clone, copyIsArray; var length = arguments.length; // 记录要复制的对象的下标 var i = 1; // 第一个参数不传布尔值的情况下,target 默认是第一个参数 var target = arguments[0] || {}; // 如果第一个参数是布尔值,第二个参数是 target if (typeof target == "boolean") { deep = target; target = arguments[i] || {}; i++; } // 如果target不是对象,我们是无法进行复制的,所以设为 {} if (typeof target !== "object" && !isFunction(target)) { target = {}; } // 循环遍历要复制的对象们 for (; i < length; i++) { // 获取当前对象 options = arguments[i]; // 要求不能为空 避免 extend(a,,b) 这种情况 if (options != null) { for (name in options) { // 目标属性值 src = target[name]; // 要复制的对象的属性值 copy = options[name]; // 解决循环引用 if (target === copy) { continue; } // 要递归的对象必须是 plainObject 或者数组 if ( deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy))) ) { // 要复制的对象属性值类型需要与目标属性值相同 if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; } else { clone = src && isPlainObject(src) ? src : {}; } target[name] = extend(deep, clone, copy); } else if (copy !== undefined) { target[name] = copy; } } } } return target; }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
数组的浅拷贝
如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。
我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
比如,数组的一些方法:
concat、slice
:但是如果数组嵌套了对象或者数组的话,就会都受影响,比如:
数组的深拷贝
使用
JSON.stringify()
和JSON.parse()
,不管是数组还是对象,都可以实现深拷贝,但是不能拷贝函数,会返回一个 null:Object.assign
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]
和目标对象的[[Set]]
,所以它会调用相关 getter 和 setter。String 类型和 Symbol 类型的属性都会被拷贝。
针对深拷贝,需要使用其他办法,如借助 JSON,因为
Object.assign()
拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。浅拷贝的实现
技巧型的拷贝,如上边使用的
concat、slice、JSON.stringify
等,如果要实现一个对象或者数组的浅拷贝,该怎么实现呢?思路:既然是浅拷贝,那就只需要遍历,把对应的属性及属性值添加到新的对象,并返回。
代码实现:
深拷贝的实现
思路:如果是对象,通过递归调用拷贝函数
代码实现:
模拟 jQuery 的 extend
extend 的用法:合并两个或者更多的对象的内容到第一个对象中。
学习资料
The text was updated successfully, but these errors were encountered: