0%

Array Reference and Copying

這是一篇記錄『深入淺出 JS30 Day 14:JavaScript References VS Copying』 的筆記文章, 這個觀念在各大筆式都很常被考到, 所以搞懂它, 擁抱它, 是一件很重要的事情, 底下問題的答案, 都放到excel檔裡面, 都寫對了, 才算是瞭解了.

原始題目

要先有值, 才能賦值.

數字, 字串, Null, undefined, boolean

1
2
3
4
let e = true 
let f = e
e = !f
console.log(e, f)

難度加強

1
2
3
4
5
6
7
//數字
let g = 'A'
let h = 'A'
let i = 'A'

(h = 'B'), (i = 'C'), (g += h), (g += i)
console.log(g, h, i)

陣列

1
2
3
4
let players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
let players2 = players;
players2[0] = "alex"
console.log(players, players2);

陣列實作淺拷貝

slice

1
2
3
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team = players.slice()
console.log(players === team) // false

concat

1
2
3
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team2 = [].concat(players)
console.log(players === team2) //false

spread operator

(我自己最常用的方法)

1
2
3
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team3 = [...players]
console.log(players === team3) //false

Array.from

這個方法也常用來把類陣列轉變為陣列的用法, 例如用在querySelectorAll的篩選器上使用.

1
2
3
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
const team4 = Array.from(players)
console.log(players === team4) //false

難度加強

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 字串
function createObj(name){
return {
name
}
}

let p1 = createObj('alex')
let p2 = createObj('sara')
let p3 = createObj('howard')
let p4= createObj('thor')

let f1 = [p1, p2, p3, p4]
let f2 = f1.slice()

//問題1
f2[0].name = 'alexander';
console.log(f1[0].name)

//問題2s
f2[0] = { name: 'alexander' };
console.log(f1[0].name)

物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let person = {
name: 'wes',
age: 80
}

let p2 = person

// 問題1
person = 'xxx'
console.log(person, p2)

// 問題2
person.name = 'xxx'
console.log(person, p2)

實作淺拷貝

Object.assign({ }, target)

由後往前覆蓋

1
2
3
4
5
6
7
// object.assign
let a = {name: 'alex', age: 36}
let b = {name: 'sara'}

let c = Object.assign(a, b)
console.log(c)
// {name: 'sara', age: 36}

示範要增加key和value的用法

1
2
3
4
5
6
7
const person = {
name: 'Wes Bos',
age: 80
};

const team6 = Object.assign({ }, person, {number: 99} )
console.log(team6) // {name: "Wes Bos", age: 80, number: 99}

JSON.parse(JSON.stringify(target))

先字串化, 再物件化, 用法同Object.assign({ }, target)

1
2
3
4
5
6
let a = {name: 'alex', age: 36}
let b = {name: 'sara'}

let c = JSON.parse(JSON.stringify)(a, b)
console.log(c)
// {name: 'sara', age: 36}

缺陷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let aa = {
name: 'alex',
age: 36,
sayHi:function(){
console.log('hi')
}
}

aa.sayHi() // hi

// JSON.parse
let bb = JSON.parse(JSON.stringify(aa))
bb.sayHi()// undefined, 可以得知function就會被lose掉

// Object.assign
let cc = Object.assign({ }, aa)
cc.sayHi() // hi

那 aa.say === cc.say ?? 兩者function一樣嗎?

如果是不帶function的純data資料, JSON.parse可以做到深拷貝, 如果有帶可能就要用prototype去做

難度加強

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let wes = {
name: 'wes',
age: 80,
social:{
facebook:'wes',
twitter: 'wes developer'
}
}

// case1
let wes2 = Object.assign({ }, wes)
wes2.social = null
console.log(wes.social)

// case2
wes2.social.facebook = null
console.log(wes.social)

// case3
let wes3 = JSON.parse(JSON.stringify(wes))

其餘範例

1
2
3
4
5
6
7
8
9
10
let ary = [{a: 1}, {b: 2}, {c:3}]
ary.forEach(item =>{
for(let key in item){
console.log(key, item[key])
}
})

//a 1
//b 2
//c 3
1
2
3
4
5
6
7
8
9
10
let ary = [{a: 1}, {b: 2}, {c:3}]
ary.forEach((item, index) =>{
Object.keys(item).forEach(key =>{
console.log(index, key, item[key])
})
})

//0 "a" 1
//1 "b" 2
//2 "c" 3

結論

洋洋灑灑寫了一堆, 這場蠻值得的, 要常回來多看, 不敢說自己已經百分百掌握. 總之概念就是要先存值再賦值, 更深刻的講法是要有值才能賦值 , 往這個概念走就八九不離十, 存值比較重要的是, 如果沒有這個值, 得要開新的記憶體空間.

這邊再加強一個觀念

  • 如果是簡單的賦值, 例如 players2 = players , 那新的players2, 在標記完位置後是要存players的值.
  • 如果是淺拷貝, 例如players2 = JSON.parse(JSON.stringify(players)), 那新的players2, 在標記完位置是要存players的位置.

範例答案

此範例以Alex宅幹嘛的教學和wes bros為主