艾草:「来,接球!」
(我看着眼前一颗球飞了过来,正准备伸出手接时,突然变成了两颗。)
「咦咦,为何?」
艾草:「我用魔法复制了一颗球呀!」
「这麽好用,那我能不能拿来复制房子呀?」
艾草:「没那麽好的事,如果复制大型物件像房子,魔法只能复制出它的样子,但你去改房子的摆设,也会连动影响到原本的房子,因为它们实际上还是存在同一个空间。」
「它的界线在哪呀?求教学。」
(不知道有没有机会复制钱钱 ($ε $ ) )
在开始介绍传值、传参考前想先补充一个小知识。
其实我们每宣告一个变数,都会有相对应的记忆体空间存放变数,也会有另一个记忆体空间存放变数的值,例如你宣告一个变数 a
值为数字 1 的话,可以想像记忆体会如下表格:
了解了记忆体空间的小概念後,让我们接着学习罗!
在值为原始型别的情况下如果设变数定 a
、 b
的值相同时,比较 a
与 b
会得到以下结果:
let a = 1;
let b = 1;
console.log(a === b)//true
在原始型别的情况下,是去比较这两个值是否相等。
而当将 a
的值赋予给 b
时,其实它会直接拷贝 a
的值数字 1 过来,因为是复制的关系,所以今天将 b
重新赋予一个数字型别的 2 ,也不会影响到 a
。
let a = 1;
let b = a;
b = 2;
console.log(a)//1
在原始型别的情况下,因为是传值的关系,所以就算我改变了变数 b
的值,也并不会连带影响到变数 a
,他们的变数记忆体指向就是两条平行线,如图:
而物件型别(包含函式)传参考 (by reference)有什麽特性呢?
在针对物件去做比较时会发现以下情况:
let obj = {
key:'value'
}
let newObj = {
key:'value'
}
console.log(obj === newObj)//false
会发现里面的属性与值明明是一样的,但回传比对结果却是 false
,因为物件是传参考,所以比对的是记忆体位置,还不太了解没关系,让我们继续看下去。
let obj = {
key:'value',
};
let newObj = obj;
console.log(obj === newObj) //true
newObj.name = "王小明";
console.log(obj)//{key: "value", name: "王小明"}
像这样明明我们改的是 newObj
却连 obj
也更动了,原因就是因为物件是透过传参考的形式,传参考代表 newObj
其实是指向 obj
的记忆体空间,如图:
我们简单替他们的记忆体空间编码为 0x001,可以清楚地看到两者都是指向同一个记忆体空间,所以当你改动 newObj
时也会同时改动到 obj
。
补充:在变数宣告章节有提到关於 const
宣告原始型别难以被重新赋予值,但物件型别因为是传参考的特性,所以只要不改变记忆体空间就不会报错,如下:
//不会报错
const obj = {
key:'value'
}
obj.name = "王小明";
//会报错
const obj = {
key:'value'
}
obj = {};//Uncaught TypeError: Assignment to constant variable.
只要不直接赋予该变数一个新的物件 {}
大括号,只是单纯去修改物件值,不影响到记忆体空间的情况下,可以透过 const
去宣告物件型别的值。
小结:原始型别的值是透过拷贝的方式,所以并不会互相影响,物件型别会共用同一个记忆体空间,所以会互相连动。
而该如何避免这个情况呢?
我们可以透过以下几种方法:
浅层拷贝指可以将第一层的位置的记忆体位置指向其他记忆体空间,但如果物件内又包了一个物件的值,该物件的值还是会与原物件共用一个记忆体空间:
Object.assign()
语法,可以复制一个或多个物件所有的属性到新物件上,如下:
let obj = {
key:'value'
}
let newObj = Object.assign({},obj);
console.log(obj === newObj)//false
展开运算子 ...
,透过 ES6 的新语法展开运算子也可以达成浅层拷贝:
let obj = {
key:'value'
}
let newObj = {
...obj
};
console.log(obj === newObj)//false
直接使用将物件转字串又转回物件的方式。
let obj = {
key:'value'
}
let newObj = JSON.parse(JSON.stringify(obj));
console.log(obj === newObj)//false
Object.assign()
、展开运算子JSON.parse(JSON.stringify(obj))
请问以下叙述何者错误?
A 原始型别的情况下是传值,物件型别的情况是传参考
B 用 const
宣告的情况下,无论原始型别或物件型别,都不能修改任何值
C 如果想浅层拷贝可以透过展开运算子、Object.assign()
语法
D 传参考指的是记忆体会指向同一个记忆体位置
解答:用 const
宣告的物件型别,因为物件传参考的特性,在不透过 =
重新赋予记忆体空间的情况下,进行属性值的新增、修改并不会报错。
0 陷阱!0 误解!8 天重新认识 JavaScript!(iT邦帮忙铁人赛系列书)
Vue 3 实战影音课程(六角学院)
<<: Day20-<router-link> 建立路由连结
今天是铁人赛最後一天了,想分享的主题也差不多了,就来个总集篇做个收场吧! 从最基本的 认识 Blaz...
没错各位!今天是最後一天!很突然的就完赛了,我跟同学们说的时候,大家都相当错愕,前阵子才听我说要参加...
变数 JS目前有三种宣告变数的方法。 在ES5以前都用var,ES6之後推出let与const。 新...
讲完了那麽多的Html,接下来要进入到CSS环节的部分了,身为网页装潢师的它,我们先从怎麽使用它开始...
ES6出现的Arrow function,看起来简短许多,但却充满许多陷阱(限制),所以充份了解箭头...