Vue3内联事件为何可修改const声明的原始类型变量?
为何Vue的事件能够修改const声明的变量?
问题现象
- 代码中的
state是原始类型const变量,按照JavaScript语法规则,直接执行state++修改其值本应抛出错误,将该逻辑写在increase方法中点击触发同样会报错。 - 但将
state++直接写为按钮的@click内联事件逻辑时,触发无任何报错,通过开发者工具可观测到state值确实发生了变化(该变量并未做响应式处理)。
复现代码
HTML
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>모두의 코딩</title> </head> <body> <div id="app"> <span>{{state}}</span><br /> <button @click="state++">inline</button><br /> <button @click="increase">function</button><br /> </div> </body> </html>
JavaScript
<script src="https://unpkg.com/vue@3"></script> <script> const { createApp } = Vue; createApp({ setup() { const state = 1; // 下方代码直接执行会抛出错误 //state++; const increase = () => { state++; }; return { state, increase, }; }, }).mount("#app"); </script>
现象截图

产生原因
这个现象和JavaScript的const语法规则没有任何冲突,核心原因是模板内联表达式的作用域和setup函数内部的作用域不是同一个:
- 你在
setup函数里用const声明的state是setup函数作用域内的常量,increase方法作为setup内部声明的箭头函数,闭包引用的就是这个作用域内的常量。原始类型的const变量不允许重新赋值,所以点击绑定increase方法的按钮时,执行state++必然会抛出赋值错误。 - 模板里的表达式访问变量时,从来不会直接读取setup作用域内的变量,Vue会把模板编译成渲染函数,所有模板里的变量访问都会指向组件实例的代理上下文(你可以理解为一个普通的JS对象,setup返回的所有属性都会被挂载到这个对象上)。
- 你写在
@click="state++"里的内联逻辑,最终会被编译器处理成类似function($event) { return this.state++ }的函数,这里的this指向组件实例代理,修改的是代理对象上的state属性——这是个普通的对象属性,根本不是你用const声明的那个常量,自然不会触发const的赋值限制。 - 你在开发者工具里看到的值变化、页面上
{{state}}的更新,本质都是代理对象上的state属性被修改了,setup作用域里最初用const声明的那个值为1的state常量,从头到尾都没有被改动过。
内容的提问来源于stack exchange,提问作者andy
相关产品推荐
相关产品推荐

