这个章节比较偏观念,如浅複製及深複製的一些概念,我觉得是非常重要的重点。
start with strings, numbers and booleans
首先是字串、数值、布林值的赋值
let a = "A"; let b = a; a = "B"; console.log(a, b); // B,A let c = 0; let d = c; c++; console.log(c, d); // 1,0 let e = true; let f = e; e = !f; console.log(e, f); // false,true
发现记忆体没有A就创建一个A值并赋予记忆体位置
,再将g,h,i指向,A的记忆体位置
,再来找B,C都没有,就创建B,C并赋予记忆体位置,再来h指向B记忆体位置,i指向C记忆体位置,最后将g+h=AB并赋予记忆体位置,g指向AB记忆体位置,接着g+i=ABC并赋予记忆体位置,g指向AB记忆体位置。
let g = "A"; let h = "A"; let i = "A"; h = "B", i = "C", g += h, g += i; console.log(g, h, i); //ABC , B ,C
Let's say we have an array
接着是做关于阵列的複製。
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy']; let player2 = players; player2[0] = "jojo"; console.log(players, player2); [0: "jojo",1: "Sarah",2: "Ryan",3: "Poppy"] [0: "jojo",1: "Sarah",2: "Ryan",3: "Poppy"]
发现这并不是我们所要得複製,他们都对应到同一个阵列,所以利用以下几种方法,可达到互不影响的複製。
法1:slice()方法,利用slice可达到複製,因为slice会额外再产生一个新的阵列。
let player2 = players.slice(); player2[0] = "jojo"; console.log(players, player2); (4) ["Wes", "Sarah", "Ryan", "Poppy"] (4) ["jojo", "Sarah", "Ryan", "Poppy"]
法2:concat()
方法,被用来合併两个或多个阵列。此方法不会改变现有的阵列,会回传呼叫者阵列本身
,也就是与players的值合併后的空阵列。
let player2 = [].concat(players); player2[0] = "jojo"; console.log(players, player2);
法3:解构赋值,将players中的值拆分出来,在合併至player2,回传一个新的阵列。
let player2 = [...players]; player2[0] = "jojo"; console.log(players, player2);
再来是配合呼叫函数所产生的阵列複製。
function createObj(name) { return { //name:name name }; } let pr1 = createObj("johnny"); let pr2 = createObj("lisa"); let pr3 = createObj("iggy"); let gr1 = [pr1, pr2, pr3]; let gr2 = gr1.slice(); // 由于gr2[0]值为pr1,所以他会去改变gr2[0].name,也就是pr1的值,那我再次获取gr1,它里面的pr1也会是改变后的值。 gr2[0].name = "momo"; console.log(gr1, gr2); // (3) ["momo", "lisa", "iggy"] // 但如果改为这样,可发现两者已互不影响,因为记忆体发现我们的记忆体中并无momo这个值,所以他会创建一个momo的值,并给予他一个记忆体空间,而后我们gr2[0](也就是gr2的pr1)就会指向他,并不影响。 gr2[0] = "momo"; console.log(gr1, gr2); // (3) ["johnny", "lisa", "iggy"] (3) ["momo", "lisa", "iggy"]
with Objects
接下来是物件之间的複製与赋值。
let person = { name: 'Wes Bos', age: 80 }; let p1 = person; // 查看记忆体无XXX后,创建一个XXX的值并赋予记忆体空间,接着person在指向他,而与p1互不影响。 person = "XXX"; console.log(person, p1); // XXX,{...} // 前面步骤与上面一样,不同的是会改变person.name的值也就是0x1的name,因此p1也会受影响,因为p1指向的也是person所指向的0x1。 person.name = "XXX"; console.log(person, p1); // {XXX...},{XXX...}
将物件x,y合併后,赋予z,会发现后者的重複的name可以覆盖前者的。
let x = { name: "bogi", age: 87 }; let y = { name: "dandy" }; let z = Object.assign(x, y); console.log(z); // {name: "dandy", age: 87}
如果我们今天在物件新增一个函数
,然后以kk複製他并一样先字串化,然后再转回obj化,会发现再以kk呼叫就会报错,因为经stringify,function会被lose掉
。
let k = { name: "eva", age: 22, eat: function () { console.log("amazing"); } }; let kk = JSON.parse(JSON.stringify(k)); // k.eat() // amazing // kk.eat() // Uncaught TypeError: kk.eat is not a function at <anonymous>:1:4
如果今天我们的物件不含函
数,那么利用JSON.parse(JSON.stringify(wes)),就可以达到deep copy
,但如果有就无法。
const wes = { name: 'Wes', age: 100, social: { twitter: '@wesbos', facebook: 'wesbos.developer' } }; const dev = Object.assign({}, wes); // 第一题 // 互不影响 dev.social = null; console.log(wes); // 不变 {twitter...}; // 第二题 dev.social.facebook = null; console.log(wes.social); // {twitter:..., facebook:null} const dev3 = JSON.parse(JSON.stringify(wes));
第一题
第二题
第三题:
首先将wes(0x6)的资料,经由stringify将0x6拿出来,并赋予一个新的记忆体空间0x8,再来经过parse,将0x5的资料拿出来(因为0x5为物件(或阵列或函数)资料就会重新赋予记忆体空间)0x9,而后重新创建一个记忆体空间0x10让wes3指向他。