iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0
自我挑戰組

JavaScript 30天挑戰 自學筆記系列 第 14

JS30 自學筆記 Day14_Object and Arrays - Reference VS Copy

  • 分享至 

  • xImage
  •  

今日任務: 認識JavaScript 的參數傳遞

JavaScript 的資料型別與資料結構

動態型別

JavaScript 是弱型別,也能說是動態的程式語言。這代表你不必特別宣告變數的型別。程式在運作時,型別會自動轉換。這也代表你可以以不同的型別使用同一個變數。

var foo = 42;    // foo 目前是數字
var foo = 'bar'; // foo 目前是字串
var foo = true;  // foo 目前是布林值

資料型別

最新的 ECMAScript 標準定義了七種資料型別:

原始型別(Primitive type)

  • 布林值 (Boolean)
  • null
  • undefined
  • 數值 (Number)
  • 字串 (String)
  • Symbol: 表示獨一無二的值(於 ECMAScript 6 新定義)

物件型別( Object Type )

  • 物件 (Object): 基本上,原始型別以外的都是物件型別
    • 常見的有:物件、陣列、函式都是物件型別

JavaScript 的參數傳遞

傳值(By Value)

在JS中,原始型別都是使用傳值(By Value)

當a指定為原始型別,會在記憶體中存一個自己的位置(假設叫做0x001)
指定b的值等於a(b=a)時,
b也會在記憶體中存一個自己的位置(假設叫做0x002),再複製一份a的值存在裡面
稱之為傳值(By Value)

所以a 和 b 存在於兩個不同的記憶體位置,兩個不會互相影響

舉例: 字串、數字

 let a = 10;
 let b = age;
 console.log(a, b);
 b = 20;
 console.log(a, b);

 let name = 'Sarah';
 let name2 = name;
 console.log(name, name2);
 name2 = 'Ryan';
 console.log(name, name2);

傳址(By Reference)

在JS中,物件型別都是使用傳址(By Reference)

當a指定為物件型別,會在記憶體中存一個自己的位置(假設叫做0x001)
指定b的值等於a(b=a)時,
b會直接指定到a記憶體的位置(0x001)
稱之為傳址(By Reference)

所以a 和 b 兩個會互相影響,a改變b也會跟著改變,反之亦然

舉例:陣列

const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
// and we want to make a copy of it.
const teams = players;
console.log(players, teams);

teams[2] = 'Jim';
//players和teams都被改變
console.log(players, teams);

所以我們要怎麼copy一個陣列而不會連動到原陣列?

slice()

會回傳一個新陣列物件,為原陣列選擇之 begin 至 end(不含 end)部分的淺拷貝(shallow copy)。而原本的陣列將不會被修改。

const team2 = players.slice();
team2[3] = 'Tom';

[ ].concat(陣列)

concat 是英文 concatenate 的縮寫,意思是串接(link things together in a chain or series.)

const team3 = [].concat(players);
team3[3] = 'Tom3';

ES6 展開運算子(spread operator):[...陣列]

const team4 = [...players];
team4[3] = 'ES6';

Array.from(陣列)

const team5 = Array.from(players);
team5[3] = 'Array.from';


舉例:物件
除了陣列,物件也一樣

const person = {
    name: 'Wes Bos',
    age: 80,
};
const captain = person;
captain.number = 99;
console.log('person', person);
console.log('captain', captain);

所以我們要怎麼copy一個物件而不會連動到原物件?

Object.assign(target, obj1,obj2,...)

用來複製一個或多個物件(obj1,obj2,...)到target,。回傳的值為target。
fruit: 'apple'會直接加進去,age:12會直接覆蓋過去

const captain2 = Object.assign({}, person, { fruit: 'apple', age: 12 });

ES6 展開運算子(spread operator):[...物件]

const captain3 = { ...person };
captain3.number = 111;

淺拷貝(shallow copy) VS 深拷貝(deep copy)

以上都是淺層的copy,深層的還是會被改變

const wes = {
    name: 'Wes',
    age: 100,
    social: {
        twitter: '@wesbos',
        facebook: 'wesbos.developer',
    },
};

const dev = Object.assign({}, wes);
dev.age = 50;
dev.social.twitter = '@asdf111';

console.log('wes', wes);
console.log('dev', dev);

可以發現只有第一層沒有跟著連動,第二層資料還是一起被改變了

淺拷貝(shallow copy)

以上複製方法都是淺拷貝,也就是只有第一層複製了,但是深層的還是共用一個記憶體

深拷貝(deep copy)

那要怎麼完整的複製,讓兩個指向完全不同的記憶體呢?

JSON.parse(JSON.stringify(obj))

1.先轉成字串,不再是物件
JSON.stringify():將JavaScript 值轉換為 JSON 字符串

const dev2 = JSON.stringify(wes);


2.再把他轉回物件
JSON.parse(): 將JSON 字串轉換成 JavaScript 的數值或是物件

const dev2 = JSON.parse(JSON.stringify(wes));

dev2.age = 30;
dev2.social.twitter = '@zxc222';
console.log('wes', wes);
console.log('dev2', dev2);

今日學習到的:

  • JavaScript 是弱型別,也能說是動態的程式語言。
  • 原始型別都是使用傳值(By Value),存在於不同的記憶體位置,不會互相影響
  • 物件型別都是使用傳址(By Reference),指向相同的記憶體位置,會互相影響
  • 淺拷貝(shallow copy)
    • 陣列
      • slice()
      • [ ].concat(陣列)
      • ES6 展開運算子(spread operator):[...陣列]
      • Array.from(陣列)
    • 物件
      • Object.assign(target, obj1,obj2,...)
      • ES6 展開運算子(spread operator):[...物件]
  • 深拷貝(deep copy)
    • JSON.parse(JSON.stringify(obj))

效果連結:連結

參考連結:
MDN: JavaScript 的資料型別與資料結構
Fooish 程式技術: JavaScript 資料型態 (Data Types)
Object references and copying
PJCHENder :談談 JavaScript 中 by reference 和 by value 的重要觀念
MDN: slice()
MDN: Object.assign({}, obj)
MDN: JSON.parse()
MDN: JSON.stringify()


上一篇
JS30 自學筆記 Day13_Slide In on Scroll
下一篇
JS30 自學筆記 Day15_LocalStorage and Event Delegation
系列文
JavaScript 30天挑戰 自學筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言