一、起因(一月份)
记得在年前我看一些文章,突然有了一个疑惑,为啥const是不能改变的.
这里我就不在讲什么数据栈堆储存的区分了,一搜一大把,就是下面的地方注意点。 注:
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
来源:阮一峰ES6"es6.ruanyifeng.com/#docs/let"
我就很疑惑,为啥这个值就是不能改动,这里就有人会说,哦那新的ECMA就是这样规定的。乍一听没毛病,但是我还是想知道为啥(不是较真),以为之前的ecma数据是没有类似性质的数据呢。我开始了寻找我疑惑的过程。
二、不太完美的结论。
1.百度
当时拿出了初级程序员的活命技能,百度,,,但是百度了半天,只有这个文章区稍微深究了一下,但是还是没有解答我的疑惑,如下
七、var、let、const实现原理 记得JS权威指南中有一句很精辟的描述: ”JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.” 以下属于推测,在网上没查到确凿的原理机制(若有误望指正): 原理大概是:在js解析的时候,优先解析const,因为它不能修改的是栈内存在的值和地址。然后解析let 因为没有块作用域可能底层有处理,最后解析var。
链接:'blog.csdn.net/aaa333qwe/a…' 我不认为和作用域有啥关系,我想知道的是,这样一个值或者概念,是怎么出现咋了新的ECMA中,肯定有个时机或者东西,,,, 追踪继续。。。
2.stackoverflow
"stackoverflow.com/questions/5…" 里面也解释了 一大堆,但是最后引导了其他地方这里不深究,有兴趣的可以去看看,我觉得在当时还是没有解答我的疑惑,,,,
3.mdn
链接:"developer.mozilla.org/zh-CN/docs/…"
Constants are block-scoped, much like variables defined using the let statement. The value of a constant can't be changed through reassignment, and it can't be redeclared.
常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变,并且不能重新声明。
描述 此声明创建一个常量,其作用域可以是全局或本地声明的块。 与var变量不同,全局常量不会变为窗口对象的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。
const声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。
好了到了这,我当时算是死心了,就按着这里解释了,就是一个不可变得值,就完事了,什么作用域啥的 其实并不是我的疑惑,也并不能完全打消我的疑惑, 就此,我还找过我们组后端大佬问过JAVA有没有类似的不可修改数据,回答有,问为啥,回答就是这样定义的。好了,,。。。。本以为就此结束了谁知道,两个月后我算是找到我想要的答案,如果你和我一样还感兴趣,请看下去。
三、一个看似毫无相关的新知识点(对象变量和词法环境)
早上我挤地铁的时候再看一个大佬的面试题集合,里面提到了知识点,是我新了解到的
链接:"www.cxymsg.com/guide/mecha…"
关于JavaScript的运行机制,
注:这篇文章讨论的特别好,我觉如果你有时间的话一定要看一下
我们主要讨论创建阶段,执行阶段的主要工作就是分配变量
#执行上下文的创建阶段 执行上下文的创建阶段主要解决以下三点:
决定 this 的指向 创建词法环境(LexicalEnvironment) 创建变量环境(VariableEnvironment) 你可能在一些过时的教材或者文章中见过变量对象(VO)这种说法,它的意思与词法环境类似,但是那是ES3的标准,现在早已经改了,改变的原因讨论如下Why variable object was changed to lexical environment in ES5?
哦。这里就很有趣了,因为我之前看红宝书的确就是有变量对象的概念,具体位置再73页,4.2:执行环境及作用域。如下图内容,(这方面没有概念,或者概念不清的请阅读完整这一章节后继续) 图

"stackoverflow.com/questions/4…"
如果你不能翻墙的话请多等等也可以,如果你不想点开的话,我来给你截图,如下。
四、意外收获
先上图,中英文吧,我三级半的英文就不 显摆了,,


如上图回答中,
除了所有环境记录支持的可变绑定外,声明性环境记录还提供了不可变的绑定。不变绑定是一种标识符和值之间的关联一旦建立就不能修改的绑定。
我不知道作者这个引用那里来的,如果来源没问题的话,那么这个回答是不是就很好的解释了我最最开始的疑惑,,,,,,为啥新的ECMA的const有了这样的一个“不可改变”的特性,原来,不仅仅是“哦,ECAM就是那么规定搞的那么简单”,是人家改变了,执行过程中数据存放的形式,引入了新的词法环境而去替代了之前的变量对象,而其中又有了“declarative environment records ”声明性环境记录这种提供了不可变的绑定的关系。这些元素直接将标识符绑定与ECMAScript语言值相关联。。。。
还是那句话,如果这个回答者的引用来自官方,那么回答是不是就很清楚了,因果明显了,因为新的ECAM的运行机制中加入这样的一个提供不可绑定关系的声明性环境记录,就有了const这种不可改变的值。。。。至此,至少我的当时疑惑算是解答了,同时也收获了关于运行机制的最新的的概念。。
说到这,你是和我一样有些收获还是晕晕呼呼还是觉得我就是闲着没事再扯淡呢?关于这个问题我也想说一下。
五、思考
当我get到这样一个我认为有收获的一个点后和同事讨论,但是收到的反馈大致是那不还是ECAM规定的么。。。。好了,到了这,我这个爱辩论的劲就上来了,如果你和上面的想法一样,并且你要还有知道这有啥用的思想(虽然我想了想也会偶尔也有这种感觉)我来比个例子
一个刚入门的前端,学了Vue2.X不去了解原理,就知道,Vue在改变数组(对象)的时候会有些特殊的表现,(因为bject.defineProperty的只针对属性的监听,还需要hack很多方法,)当他某天开始用Vue3.X后发现这种特殊表现没了(新的Vue使用Proxy可以直接监听对象而非属性。。。。各种优点),那好了如果,这个哥们,不去多追究,他完全可以认为是vue就是那么定义的,就完事了。。
但是为啥,你我都去了解Vue的实现,去了解3.X的优化?
同这个问题一样,我知道“declarative environment records ”声明性环境记录这种提供了不可变的绑定的关系,让我大概知道const 不能改变的原因,不会让我代码撸的更快,也不会让我Bug少点,但同时,你去了解Vue原理。也一样,不会让你录得更快,bug更少点,,别说什么我知道源码的实现了,就可以提高多少效率。。。。只有自己清楚,,,,
好了,既然行为都一样,那么为什么会有源码的了解呢,除了面试加薪之外,是否是因为,理工男(程序员)都有一个想要知其然 且知其所以然的想法 ,也许有了这才是stackoverflow那么多有意思且有趣的值得思考的问题,也是我们获取知识的的动力来源呢?至少我是。。。。我好奇,,,,,嘿嘿,也许憨憨一样的(狗头微笑)
说了这么多,希望你能明白我的意思,请保持一个好奇的心,哪怕进一步,解开心中疑惑的那一瞬间,是开心的,真的。。。
六、后记
- 说实话,整个文章,有点乱,很多自己的观点,但是还是希望,看完的你有所收获。
- 当然我也很期待,有真正的大佬,对于我的文章中的地方或者这个结果进行指导,让我这篇文章不是误人子弟,因为我也不敢确定。
- 最后,我希望大家看完有任何想法欢迎讨论指点,(我是个杠精,贼爱辩论,,,,,,)哈哈。。。