藉由 IT 鐵人賽中的文章 重新認識 JavaScript,複習、加強自己的基本功,

基本型別 Copy

  • string
  • number
  • boolean
  • null
  • undefined

Pass by value : JavaScript 會建立不同的 Memory 存取,故變數間無關聯性,基本型別可以直接複製。

let age = 100;
let age2 = age;

console.log(age, age2); // 100, 100
age = 200;
console.log(age, age2); // 200, 100

物件型別 Reference

Reference: 多個變數同時使用同一個記憶體

obj1 obj2 的物件分別被以不同記憶體存取,JavaScript 會將物件型態看作一個實體,故 obj1, obj2 不相同。

const obj1 = { value: 10 };
const obj2 = { value: 10 };

obj === obj2; // false

物件型態在 JavaScript 中,會透過引用的方式傳遞 (Pass by reference),此時變數 obj1, obj2 會指向同一個記憶體,所以修改 obj2 內容的同時,obj1也被更新了。

const obj1 = { value: 10 };
const obj2 = obj1;

obj1 === obj2; // true

obj2.value = 30;
console.log(obj1.value); // 30

Array

const arr = [1, 2, 3];
// ES6 spread operator
const copy1 = [...arr];
const copy2 = arr.slice(0);
const copy3 = arr.concat();

拷貝物件

淺拷貝 (One Level)

  • 只會複製第一層
  1. Object.assign()
  2. Object spread
const obj = { a: 1 };
const copy1 = Object.assign({}, obj);
const copy2 = {...obj}

copy1.a = 2;
copy2.a = 3;

console.log(obj.a);   // 1
console.log(copy1.a); // 2
console.log(copy2.a); // 3

深拷貝

JSON.parse(JSON.stringify(obj));

  • JSON.parse() : 字串轉為物件
  • JSON.stringify() : 物件轉為字串
const wes = {
  name: 'Wes',
  age: 100,
  social:{
    twitter: '@wesbos',
    facebook: 'wesbos.developer'
  }
}

const copy = JSON.parse(JSON.stringify(wes));
copy.social.twitter = '@coolman';

console.log(wes.social.twitter);  // @wesbos
console.log(copy.social.twitter); // @coolman

Pass by sharing

範例引用自 重新認識 JavaScript: Day 05 JavaScript 是「傳值」或「傳址」?

透過 function 參數重新賦值,外部變數內容不受影響

const coin1 = { value: 10 };

function changeValue(obj) {
  obj = { value: 123 };
  console.log(obj.value); //123
}

changeValue(coin1);
console.log(coin1.value);   // 10

更新 obj.value,未重新賦值

const coin1 = { value: 10 };

function changeValue(obj) {
  obj.value = 123;
  console.log(obj.value); //123
}

changeValue(coin1);
console.log(coin1.value);   // 123

面試題

var a = { n : 1 };
var b = a;

a.x = a = { n : 2 };

console.log(a.x); // undefined
console.log(b.x); // { n: 2 }

解析

var b = a; (Pass by reference),所以 a, b 指向同記憶體,暫稱「物件 A」

a.x = a = { n: 2 }. 優先高於 = 先建立 x,此時「物件 A」為

// a, b 皆指向物件 A
a: {
  n: 1,
  x: undefined
}

b: {
  n: 1,
  x: undefined
}

賦值順序為由右至左,先執行a = { n: 2 }a 會指向記憶體中新物件,暫稱「物件 B」

// 物件 B
a: {
  n: 2
}

// 物件 A
b: {
  n: 1,
  x: undefined
}

繼續執行 a.x = a ,因為運算順序關係 JS 已經先對 a.x 做計算計算,所以在同條公式下的 a.x 為「物件 A 」下的 x,指向「物件 B」。

// 物件 B
a: {
  n: 2
}

// 物件 A
b: {
  n: 1,
  // x 指向物件 B
  x: {
    n: 2
  }
}

Reference

JavaScript30

重新認識 JavaScript: Day 05 JavaScript 是「傳值」或「傳址」?

從一個簡單例子來理解js引用類型指針的工作方式