物件传参考是 JS 中非常重要的特性,纯值和物件在赋值时的行为模式不同:
先来看看传值的程序码:
var name1 = 'Ryder'
var name2 = name1
name2 = 'Jack'
console.log( name1, name2 )//Ryder , Jack
这个状况很好理解,name1 的资料赋值给 name2,nam2 独立修改资料,不影响 name1 ,但如果是物件的传参考状况呢?
var obj1 = { name:'Ryder' }
var obj2 = obj1
obj2.name = 'Jack'
console.log( obj1.name ,obj2.name) //Jack , Jack
答案会是两边都会是 Jack ,并且若再使用 console.log(obj1 === obj2)
他也会回传 true
,这是因为在 JS 中,物件赋值时是传参考的。
那什麽是传参考呢?
根据上面程序码,一行一行来讲解
var obj1 = { name:'Ryder' }
这样物件本就会有一个独立的记忆体,目前称做 00x1,情况大致如图:
obj2 = obj1
当 obj1
赋值给 obj2
时,其实这段就是提供物件参考的记忆体,因此称作传参考,情况如图:obj1
、 obj2
的记忆体指向是相同记忆体,因此当我们使用 obj2.name
修改时,两个物件的内容都会被修改。再来看看例外状况:
试着为 obj2
赋予新物件:
var obj1 = { name:'Ryder' }
var obj2 = obj1
obj2 = { name:'Ryder' }
connsole.log(obj1 === obj2) //false
结果之所以回传 false
是因为 obj2
有在使用物件实字 {}
建立一个新物件,此时会生成一个新的记忆体指向,用图表示就是:
最後来看看一个状况特别的延伸的范例:
var obj1 = { a:1 }
var obj2 = obj1
obj1.a = { a:2 }
obj1.b = obj1 = { b:1 }
obj1 //{b: 1}
obj2 //{a: {a:2}, b: {b:1}}
这边出现的结果不论是 obj1
、obj2
都令人疑惑,这边一行一行来说明:
var obj1 = { a:1 }
obj1 创立一个物件此时诞生一个新记忆体 00x1 ,内容是 { a:1 }
,状况如图:
obj2 赋值实际获得的是 00x1 记忆体,如图:
obj1 中的 a 属性从原本纯值 1 替换成新物件 { a:2 }
,此时也会建立新记忆体 00x2 ,如图:
接下来是重点 obj1.b = obj1 = { b:1 }
根据运算子相依性特性 obj1 = { b:1 }
会先执行,同时我们也看到 obj1
重新赋值一个新物件,因此会诞生一个新记忆体 00x3 ,并且 obj1
指向的记忆体会被更改成 00x3,如图:
接下来是将 obj1 = { b:1 }
这段回传的 { b:1 }
赋予到 obj1.b
上,但要注意的是我们输入的是 obj1.b = obj1 = { b:1 }
这段只是一行程序码,JS 实际上在编译时不会为了 obj1 = { b:1 }
马上建立一段新的记忆体,因此 obj1.b
实际指向的并非是後来变更的 00x3 而是变更前的 00x1 ,因此就会是 00x1 又塞入了 00x3 内容,如图:
最後使用 console.log(obj1 === obj2.b)
答案也会是 true 了。
P.S. 最让人疑问的便是 obj1.b = obj1 = { b:1 }
这段。
而这段的重点是,JS 在编译这种一行执行的程序码时,是不会为了个别『运算式』去建立记忆体,因此这种一行程序码,都还是会使用原始的记忆体指向。
>>: day11 : argo gitops服务以及ingress (上)
经历了前两天的介绍及环境准备後,我相信大家大概都已经准备好要开始进入Django的世界了吧! 什麽?...
泛型就是参数化类型,将类别参数化。让你在定义类别、方法、介面时先不用决定型别,等到要实体化时再决定型...
Menu 这个套件应用的范围很广,之前讲解过的 Select 也是用这里的 MenuItem 来替换...
点击进入React源码调试仓库。 本篇是详细解读React DOM操作的第二篇文章,文章所讲的内容发...
[深入浅出MQTT]: v3.1.1与v5 的差异 MQTT v3.1.1 与 v5 完全相容,且提...