存在了暂时性死区了,就说明 const 声明常量的时候也就不存在啥声明提前的事儿了。这两件事儿吧,其实说的是一个意思,你可得记明白了。
声明常量对象或者数组唠到这儿吧,其实基本上关于 const 都唠完了。这货除了可以真正声明一个常量之外,其实没啥可唠的啦。但是,但可是,可但是~ 嘿嘿~
大叔想问你的问题:如果咱们用 const 声明一个对象或者数组,那这个对象的属性或者数组里面的元素能不能修改呢?
寻思是寻思不明白的,咱们直接整代码吧,用事实来看看到是个啥情况。比方说咱们先声明一个这样婶儿的对象:
const obj = { name: "不想成熟的大叔", age: 37 }大叔今年都 37 啦,但是年轻的心还是有滴。所以,大叔想把 age 这个属性的值改成 18,就像这样婶儿的:
obj.age = 18 console.log(obj)结果~ 咱们运行代码之后得到的结果就是这样婶儿的:
{ name: "不想成熟的大叔", age: 18 }注意啊~ 注意啊~ age 属性的值被成功滴改成了 18!不对吧?const 声明的不是常量吗?常量不是不能改变值吗?这尼玛结果也不对啊?
灵魂三连问也没用,事实摆在眼吧前儿,咱就得认!但是,为啥会这样涅?别急,且听大叔给你慢慢道来~
想整明白这个事儿吧,咱们就得先唠扯唠扯 JavaScript 的存储结构了。JavaScript 的存储结构有俩儿,一个叫做“堆内存”,一个叫做“栈内存”。一般情况下吧,咱们定义的变量或者常量都是存储在堆内存里面的。但是吧,对象和数组算是 JavaScript 里面比较复杂的一种数据,所以实际上对象或者数组的存储形式是这样婶儿的:
知道了这个事儿,你大概就能整明白为啥上面的代码运行的结果是这样婶儿的了吧?!说白了,const 声明的对象的值确实不能改变,但是对象的值存储的是一个引用地址,而具体的属性其实是存储在这个引用地址里面,const 是没办法限制的。
整到这儿,你是不是想问那这样婶儿的问题要怎么解决?嗯~ 也能解决的。你还记得 Object 提供了一个方法叫做 freeze() 吗?这个方法是用来冻结某个对象的。冻结之后不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。所以,就可以利用这个方法来解决上面提到的问题:
const obj = { name: "不想成熟的大叔", age: 37 } Object.freeze(obj) obj.age = 18 console.log(obj)这样处理之后,咱们再来看看打印后的结果吧:
{ name: "不想成熟的大叔", age: 37 }问题被完美滴解决了!等一下,真的是这样婶儿的吗?大叔想继续再操作一下下的,比方说像这样婶儿的:
const obj = { name: "不想成熟的大叔", age: 37, skill: { name: "coding", year: 15 } }啥意思?就是说咱们在声明一个对象的时候,这个对象的属性也同样是一个对象或者数组,那现在的问题就是你利用 Object.freeze() 方法还能成功地冻结不?咱们就来试试吧:
Object.freeze(obj) obj.skill.year = 20 console.log(obj)咱们得到的结果实际上是这样婶儿的:
{ name: "不想成熟的大叔", age: 37, skill: { name: "coding", year: 20 } }发现还是被修改了~ 这又是咋回事儿呢?这就说明 Object.freeze() 方法只能冻结当前对象的属性,但是如果某个属性的值还是一个对象或者数组的话,那就说明这个属性存储的还是一个引用地址,实际的数据是存储在这个引用地址中的。
想要解决这个问题其实也不算难,就是继续利用 Object.freeze() 方法来冻结这个值为对象或者数组的属性就行了。就像这样婶儿操作:
Object.freeze(obj.skill) obj.skill.year = 20 console.log(obj)这样咱们得到的结果就是:
{ name: "不想成熟的大叔", age: 37, skill: { name: "coding", year: 15 } }也就是说,关于这个问题咱们想一劳永逸地解决掉,可以定义一个函数,把对象作为参数传递进去。然后,这个函数主要利用递归方式把对象中所有值为对象或者数组的属性分别进行冻结,穷尽为止就可以啦!
写在最后的话好了,整到这儿,ES6 新增的 const 关键字所有大叔想和你唠扯的内容都唠扯完了,也希望能对你有所帮助。最后再说一句:我是不想成熟的大叔,为前端学习不再枯燥、困难和迷茫而努力。你觉得这样学习前端技术有趣吗?有什么感受、想法,和好的建议可以在下面给大叔留言哦~