传值(call by value)vs传址(call by reference)
基本型别(Number、String、Boolean、null、undefined)属于 call by value。物件型别(Array、Object、function) 为 call by reference。1. 传值
当资料为基本型别(如 string、number、boolean、null、undefined),那么即为赋值。
let a = 10let b = 10console.log(a === b) // true
a 更新后不会影响 b
let a = 10let b = aa = 20console.log(a === b) // false
2.传址
当资料为物件型别(Array、Object、function),那么即为赋址。
var obj1 = { v1: 1 };var obj2 = { v1: 1 };console.log( obj1 === obj2 ); // false
因为两者的记忆体位置并不相同。在比较物件型别时,比较的是记忆体位置,而非值。
let obj1 = { v1: 1 };let obj2 = obj1;obj1.v1 = 0;console.log( obj2.v1 ); // 0obj2.v2 = 2;console.log( obj1.v2 ); // 2console.log( obj1 === obj2 ); // true
当我们修改任意物件属性时,另一边的属性也会更动,这是因为两个变数指向相同的记忆体位置,并没有新的物件被複製出来。
注意例外
pass by sharing => 当物件被传入function当参数且物件被重新赋址时,物件是不会被影响的。let obj1 = { v1: 1 };function change(e){e = {v1:100};console.log(obj1) //{ v1: 1 }}change(obj1)console.log(obj1) //{ v1: 1 }
若改成以下,则可变更资料
let obj1 = { v1: 1 };function change(e){console.log(obj1) // { v1: 1 }e.v1=100;}change(obj1)console.log(obj1) //{ v1: 100 }
浅层拷贝vs深层拷贝
浅层拷贝:複製资料只能複製第一层,因为深层的物件或阵列还是传址,不会完全複製一份深层拷贝:深拷贝就是完全複製一份,不会有共用记忆体的问题。1.浅层拷贝常见方法
物件的浅拷贝Object.assign()展开运算子 ...阵列的浅拷贝slice()concat()forEach + push()map()filter()... 展开运算子2.深层拷贝常见方法
利用 JSON 方法:先转 JSON 格式,再转回来。第三方函式库jQuery 的 $.extendLodash 的 _.cloneDeep()更详细内容请参考 竹白笔记
面试题目
1.b 会呈现什么答案?
let a = {};let b = a ;let c = b = {number:1};c.name = "tom";console.log(b)
Ans:{number:1,name:tom}
在第三行,c、b皆指向{number:1}
2.请问 console.log(hello.a)、console.log(a)会出现什么?
function hello(){ a = 1;}hello.a = "hi";hello();console.log(hello.a)console.log(a)
Ans:hi、1
3.console.log(family[0].members.bro)会是?
let family = [{ name:"tom", members:{ mon:'妈', dad:'爸', bro:'哥', }}]let newArray = [];family.forEach((item)=>{ newArray.push(item);})newArray[0].members.bro = '弟' ;console.log(family[0].members.bro)
Ans:弟
因浅层拷贝,故深层指向被複製的物件
4.console.log(family.name)、console.log(family.members.mon)会是?
let family = { name:"tom", members:{ mon:'妈', dad:'爸', bro:'哥', }};let newfamily = {...family};newfamily.name = 'ted';newfamily.members.mon = "momy" ;console.log(family.name)console.log(family.members.mon)
Ans:tom、momy