在我们的日常工作中, 经常会遇到一些把一个值赋给另一个值, 简单数据类型我们可以直接用 = 的方式进行简单值拷贝, 那么遇到数组或者对象这些引用类型的拷贝应该怎么做呢? 接下来简单总结了一些数组的浅拷贝和深拷贝的方法
浅拷贝[Shallow copy]
concat()
concat()方法主要用于数组的连接, 该方法不会改变现有的数组, 而仅仅会返回被连接数组的一个副本.
- var arr1 = [1,2,3,4];
- var arr10 = arr1.concat([]);
- console.log(arr1); //1,2,3,4
- console.log(arr10); //1,2,3,4
- arr10.push(10);
- console.log(arr10); //1,2,3,4,10
- console.log(arr1); //1,2,3,4
- // 从此方法可以看出, 使用 concat 方法实现了数组的浅拷贝, 当操作 arr10 时没有影响到 arr1 数组的数据
- slice()
slice()方法用于数组的切割, 基本的语法是 slice(start,end);start 指定从原始数组的那个位置开始切割, end 表示到那个位置结束 [省略该参数默认结束位置是数组的最后一个原始] , 我们可以使用 slice() 方法不指定任何参数实现数组的浅拷贝
- var arr1 = [1,2,3];
- var arr2 = arr1.slice();
- console.log(arr1); //1,2,3
- console.log(arr2); //1,2,3
- arr2.push(4);
- console.log(arr1); //1,2,3
- console.log(arr2); // 1,2,3,4
- // 只影响了 arr2 数组, 实现了数组的浅拷贝
...[ES6 扩展运算符]
对 ES6 熟悉的人肯定都知道这个方法,... 是 ES6 的新语法, 它可以用于数组的扩展,
- var arr1 = [1,2,3]
- var arr2 = [...arr1];
- console.log(arr1); //1,2,3
- console.log(arr2); //1,2,3
- arr2.push(4);
- console.log(arr1); //1,2,3
- console.log(arr2); // 1,2,3,4
- // 只影响了 arr2 数组, 实现了数组的浅拷贝
以上是小编简单总结的数组的浅拷贝方法, 同样你也可以用自己编写的方式进行数组浅拷贝
- // 实现浅拷贝
- function shallowCopy( target ){
- if(typeof target !== 'object') return ;
- // 判断目标类型, 来创建返回值
- var newObj = target instanceof Array ? [] : {};
- for(var item in target){
- // 只复制元素自身的属性, 不复制原型链上的
- if(target.hasOwnProperty(item)){
- newObj[item] = target[item]
- }
- }
- return newObj
- }
- var test = [10,3,{name:'zs',age:10}]
- var cloneTet = shallowCopy(test);
- cloneTest[2].name = 'lisi';
- console.log(test[2].name) //lisi
- console.log(cloneTest[2].name) // lisi
- //.
从上面的结果可以看出, 在修改拷贝出来的 cloneTest 时, 原始的 test 值也被修改了. 为了实现不被修改, 我们需要使用到深拷贝
深拷贝
巧用 JSON.parse(JSON.stringify(Obj))
同样我们可以先将数组转为对象字符串然后在转为对象的方式进行浅拷贝
- var arr1 = [1,2,3];
- var arr2 = JSON.parse(JSON.stringify(arr1));
- console.log(arr1); //1,2,3
- console.log(arr2); //1,2,3
- arr2.push(4);
- console.log(arr1); //1,2,3
- console.log(arr2); // 1,2,3,4
- // 只影响了 arr2 数组, 实现了数组的浅拷贝
使用递归的方式实现深拷贝
- var arr =[{name:'yf',students:{name:'zs',age:10,course:{name:'english'}}}]
- var deepCopy = function(o) {
- if (o instanceof Array) {
- var n = [];
- for (var i = 0; i < o.length; ++i) {
- n[i] = deepCopy(o[i]);
- }
- return n;
- } else if (o instanceof Object) {
- var n = {}
- for (var i in o) {
- n[i] = deepCopy(o[i]);
- }
- return n;
- } else {
- return o;
- }
- }
- var cloneArr = deepCopy(arr);
- cloneArr[0].students.course.name ='aaaaaaaaaaaa';
- console.log(cloneArr);
- console.log(arr);
Note: 此处的判断, 一定要将 o instanceof Array 放在 o instanceof Object 前边, 为什么呢? 英文数组进行 instanceof Object 的判断结果也是 true, 这就关系到原型链的问题了哈.
简单讲一下 instanceof 的原理
- function instance_of(L, R) {//L 表示左表达式, R 表示右表达式
- var O = R.prototype;// 取 R 的显示原型
- L = L.__proto__;// 取 L 的隐式原型
- while (true) {
- if (L === null) // 表示已经取到了原型链的最顶端
- return false;
- if (O === L)// 这里重点: 当 O 严格等于 L 时, 返回 true
- return true;
- L = L.__proto__;
- }
- }
详解一下 [] instanceof Object 的比较过程
- // 而上面说的 [] instanceof Object 返回结果为 true
- var arr = [1,2,3];
- arr instanceof Object
- // 首先取出 arr.__proto__ = Array.prototype,
- arr.__proto__ === Object.prototype // 第一轮比较返回 false
- arr.__proto__.__proto__ === Object.prototype // 第二轮比较返回 true
等于
Array.prototype.__proto__ === Object.prototype // 返回 true
为什么会相等, 可以深入学习一下原型链. 小编下一篇会出相关详解
来源: https://juejin.im/post/5aefd8a76fb9a07acf561153