#コピーのプロセスを理解して不要なミスを回避しましょう。Js 特別シリーズの深いコピーと浅いコピーを一緒に頑張りましょう~
目次
無料学習の推奨事項: javascriptビデオチュートリアル
1. 例をコピー
#データを操作すると、次のような状況が発生する可能性があります:var str = 'How are you';var newStr = str;newStr = 10console.log(str); // How are youconsole.log(newStr); // 10
newStr は、レイアウトは同じですが接続されていない 2 つの同一の部屋のようなものです。
1.2 参照型のコピー例
var data = [1, 2, 3, 4, 5];var newData = data;newData[0] = 100;console.log(data[0]); // 100console.log(newData[0]); // 100
J のデータ型について質問がある場合は、「JavaScript の基本データ型」を参照してください。
2. 浅いコピー
コピーの分割は参照型に基づいて説明されます。浅いコピー - 名前が示すように、浅いコピーは「浅いコピー」です。表面的な作業のみを行います:
var arr = [1, 2, 3, 4];var newArr = arr;console.log(arr, newArr); // [1,2,3,4] [1,2,3,4]newArr[0] = 100;console.log(arr, newArr) // [100,2,3,4] [100,2,3,4]
参照型
の基本的な特性によるものでもあります。変数に格納される値はポインタ ( point)、ストレージを指すオブジェクトのメモリ アドレス。新しい変数に値を割り当てることは、新しいキーを割り当てることと同じであり、部屋は変更されません。
var arr = [1,2,3,4];var res = arr.slice();// 或者res = arr.concat()res[0] = 100;console.log(arr); // [1,2,3,4]
var arr = [ { age: 23 }, [1,2,3,4] ];var newArr = arr.concat();arr[0].age = 18;arr[1][0] = 100;console.log(arr) // [ {age: 18}, [100,2,3,4] ]console.log(newArr) // [ {age: 18}, [100,2,3,4] ]
の原則に従って、
浅いコピーでは私たちの要件を満たせないため、##の達成を手伝ってくれる人がいるかどうかを探しています。 #ディープコピー メソッド。
3.1 JSON
ここでは、最も簡潔な処理を実現するために、JSON の 2 つのメソッドJSON.stringify()
、var arr = ['str', 1, true, [1, 2], {age: 23}]var newArr = JSON.parse( JSON.stringify(arr) );newArr[3][0] = 100;console.log(arr); // ['str', 1, true, [1, 2], {age: 23}]console.log(newArr); // ['str', 1, true, [100, 2], {age: 23}]
この方法はディープ コピーを実装する最も簡単な方法のはずですが、
まだ問題があります。今行ったことを見てみましょう:
すべての型を含む配列を定義しますarr
理解 :
new string に変換し、new string
## を介してnew object# に復元するという変更方法であることがわかります。データ型はオブジェクト参照のコピープロセスを間接的にバイパスし、元のデータには影響を与えません。 制限事項:
このメソッドの基本的な目的は、「転送」中のデータの整合性を確保することであり、
対応する JSON 形式 :
への値の変換にも欠陥があります所以当我们拷贝函数、undefined等stringify
转换有问题的数据时,就会出错,我们在实际开发中也要结合实际情况使用。
举一反三:
既然是通过改变数据类型来绕过拷贝引用这一过程,那么单纯的数组深拷贝是不是可以通过现有的几个API来实现呢?
var arr = [1,2,3];var newArr = arr.toString().split(',').map(item => Number(item))newArr[0] = 100;console.log(arr); // [1,2,3]console.log(newArr); // [100,2,3]
注意,此时仅能对包含纯数字的数组进行深拷贝,因为:
但我愿称它为纯数字数组深拷贝!
有的人会认为Object.assign()
,可以做到深拷贝,我们来看一下
var obj = {a: 1, b: { c: 2 } }var newObj = Object.assign({}, obj)newObj.a = 100;newObj.b.c = 200;console.log(obj); // {a: 1, b: { c: 200 } }console.log(newObj) // {a: 100, b: { c: 200 } }
神奇,第一层属性没有改变,但第二层却同步改变了,这是为什么呢?
因为 Object.assign()拷贝的是(可枚举)属性值。
假如源值是一个对象的引用,它仅仅会复制其引用值。MDN传送门
四、自己实现深浅拷贝
既然现有的方法无法实现深拷贝,不妨我们自己来实现一个吧~
我们只需要将所有属性即其嵌套属性原封不动的复制给新变量一份即可,抛开现有的方法,我们应该怎么做呢?
var shallowCopy = function(obj) { if (typeof obj !== 'object') return; // 根据obj的类型判断是新建一个数组还是对象 var newObj = obj instanceof Array ? [] : {}; // 遍历obj,并且判断是obj的属性才拷贝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj;}
我们只需要将所有属性的引用拷贝一份即可~
相信大家在实现深拷贝的时候都会想到递归,同样是判断属性值,但如果当前类型为object
则证明需要继续递归,直到最后
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' ? deepCopy(obj[key]) : obj[key]; } } return newObj;}
我们用白话来解释一下deepCopy
都做了什么
const obj = [1, { a: 1, b: { name: '余光'} } ];const resObj = deepCopy(obj);
obj
,创建 第一个newObj[]
0
(for in
以任意顺序遍历,我们假定按正常循序遍历)1
obj[1]
另外请注意递归的方式虽然可以深拷贝,但是在性能上肯定不如浅拷贝,大家还是需要结合实际情况来选择。
写在最后
前端专项进阶系列的第五篇文章
,希望它能对大家有所帮助,如果大家有什么建议,可以在评论区留言,能帮到自己和大家就是我最大的动力!
相关免费学习推荐:javascript(视频)
以上がJavaScript トピック 5: 深いコピーと浅いコピーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。