最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

Day 14 – JavaScript References VS Copying

XAMPP下载 admin 853浏览 0评论
 今天不做作品,而是討論一下在 JavaScript 中的複製。或許你有遇過下面問題

let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2[2] = 5;
arr2;  // [1, 2, 5]
arr1;  // [1, 2, 5]
原本的 arr1 居然也被更改了!假如你也正有著個疑惑那就接著看下去吧!如果你已經知道原因那也看下去吧!

基本型別(Number, String, Boolean, undefined, null)
先看範例

let a = 1;
let b = a;
b = 3;
b;  // 3
a;  // 1

當 a 是基本型別並 b = a時,a 實際上複製一份自己的值給 b 這個變數,也因此當更改 b 的值的時候 a 的值不會一起被更改,而這種特性適用所有基本型別。

Array
假設現在有一 array

let fruits = [‘watermelon’, ‘papaya’, ‘banana’, ‘lemon’];
接著用新的變數複製一份 fruits 的值並更改內容

let fruits2 = fruits;
fruits[0] = ‘pamelo’;
fruits2;  // [‘pamelo’, ‘papaya’, ‘banana’, ‘lemon’]
fruits;  // [‘pamelo’, ‘papaya’, ‘banana’, ‘lemon’]
原本的 fruits 竟然也被改到了!
這是因為當對 array 使用 fruits2 = fruits 時,不同於基本型別複製了「值」,實際上是複製了一份指向 [‘watermelon’, ‘papaya’, ‘banana’, ‘lemon’] 的參考點(reference),或者可以說現在 fruits 以及 fruits2 都指向相同的 array [‘watermelon’, ‘papaya’, ‘banana’, ‘lemon’],所以當更改其中一個時,另一個也會被改變。

既然 fruits2 = fruits 不會複製實際值,那我們要如何複製 array 的值呢?

請參考使用下列幾種方法,如果有其他方法也歡迎補充~

Array.from(..)
這個方法之前在將 array-like 轉成 array 時常用到,但它也可以用來複製 array 喔!

let fruits3 = Array.from(fruits);
fruits3[0] = ‘pamelo’;
fruits3;  // [‘pamelo’, ‘papaya’, ‘banana’, ‘lemon’]
fruits;  // [‘watermelon’, ‘papaya’, ‘banana’, ‘lemon’]
原本的 fruits 沒有被改到,很好!

slice(..)
slice() 也可以達成一樣的效果,它原本的使用目的是取出部分 array 內容,但同樣能用於複製

let fruits4 = fruits.slice();  // 若沒有帶入參數則會是整個 array
fruits4[0] = ‘pamelo’;
fruits4;  // [‘pamelo’, ‘papaya’, ‘banana’, ‘lemon’]
fruits;  // [‘watermelon’, ‘papaya’, ‘banana’, ‘lemon’]
… (Spread Operator)
第三種方法是使用 ES6 的新語法展開運算子(Spread Operator)

let fruits5 = […fruits];  // 若沒有帶入參數則會是整個 array
fruits5[0] = ‘pamelo’;
fruits5;  // [‘pamelo’, ‘papaya’, ‘banana’, ‘lemon’]
fruits;  // [‘watermelon’, ‘papaya’, ‘banana’, ‘lemon’]
Object
上面提到的特性(複製參考點而不是實際的值)不只適用 array,同樣也適用於 object。
舉例來說

let person = {
name: ‘Henry’,
age: 66
}

let man1 = person;
man1.age = 30;
man1;  // {name: ‘Henry’, age: 30}
person;  // {name: ‘Henry’, age: 30}
man1 同樣只複製到 {name: ‘Henry’, age: 66} 的參考點而不是實際值,以下列出 object 的複製方法

Object.assign(..)
let man2 = Object.assign({}, person, {age: 87, job: ‘teacher’});
man2;  // {name: ‘Henry’, age: 87, job: ‘teacher’}
person;  // {name: ‘Henry’, age: 66}
原本的 object 沒有被動到,耶!

目前我只有想到這個複製方法,如有其他方法歡迎提供

上述的方法雖然可以複製,但其實只是淺層複製(只複製一層),也就是當 object/array 中的項目有 object/array 時會失效,見下方範例

let cat = {
name: ‘Miao’,
birthYear: 2006,
description: {
friendly: false,
fat: true
}
}

let cat2 = Array.from(cat);
cat2.birthYear = 2012;
cat2.description.fat = false;

cat2;  // {name: ‘Miao’, birthYear: 2012, description: {friendly: false, fat: false}}
cat;  // {name: ‘Miao’, birthYear: 2006, description: {friendly: false, fat: false}}
可以看到 cat.description.fat 還是被改了

如果想要完整複製這種 object/array,可以考慮寫一個 function 並使用迴圈來複製每一層

array 和 object 除了上述的幾種方法其實還有一種方法,有用但很糙,請將它視為沒有辦法的辦法

let cat3 = JSON.parse(JSON.stringify(cat));
如果試著更改 description 中的內容,會發現原本的 cat 沒有被改到,這是因為 JSON.stringify 先將 object 轉成了 string(此時原本的參考點就不復存在了)並透過 JSON.parse 還原

希望這篇提到的內容對於你了解複製值&參考點有幫助,沒有的話也沒關係。

转载请注明:XAMPP中文组官网 » Day 14 – JavaScript References VS Copying

您必须 登录 才能发表评论!