news 2026/4/16 12:29:12

【Vue】08 Vue技术——回顾 Vue 中的 `Object.defineProperty` 方法的使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Vue】08 Vue技术——回顾 Vue 中的 `Object.defineProperty` 方法的使用

文章目录

    • 1. 引言
    • 2. 完整示例代码(含原始注释)
    • 3. 代码结构与变量初始化
      • 3.1 外部变量 `number`
      • 3.2 基础对象 `person`
    • 4. `Object.defineProperty` 的完整配置解析
      • 4.1 被注释掉的数据描述符(Data Descriptor)
      • 4.2 被注释掉的旧式 getter 写法
      • 4.3 实际启用的 getter
      • 4.4 实际启用的 setter
    • 5. 最终日志输出与行为验证
      • 5.1 控制台初始输出
      • 5.2 手动测试 getter/setter(在控制台执行)
        • 测试 1:读取 `age`
        • 测试 2:修改 `age`
        • 测试 3:再次读取
    • 6. 与 Vue 2 响应式系统的关联
    • 7. 总结

1. 引言

在 Vue 2 的响应式系统实现中,Object.defineProperty是核心机制之一。虽然 Vue 3 已经转向使用更强大的Proxy,但理解Object.defineProperty对于掌握 Vue 响应式原理、调试旧项目以及深入 JavaScript 对象属性控制仍具有重要意义。本文将结合一段包含详细注释的示例代码,逐行解析其设计思路、配置选项含义以及运行行为,并展示控制台中的实际输出结果。


2. 完整示例代码(含原始注释)

<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>回顾Object.defineProperty方法</title><!-- 引入Vue --><!-- <script type="text/javascript" src="../js/vue.js"></script> --></head><body><scripttype="text/javascript">letnumber=18letperson={name:'张三',sex:'男',}Object.defineProperty(person,'age',{// value:18,// enumerable:true, // 控制属性是否可以枚举,默认值为false// writable:true, // 控制属性是否可以被修改,默认值是false// configurable:true, // 控制属性是否可以被删除,默认值是false// 当有人读取age的属性时,get函数(getter)就会被调用,且返回值就是age的值// get:function(){// //return 'hello'// console.log('有人读取age属性了')// return number// }get(){//return 'hello'console.log('有人读取age属性了')returnnumber},// 当有人修改person的age的属性时,set函数(setter)就会被调用,且会受到修改的具体值set(value){console.log('有人修改了age属性,且值是:',value)number=value}})console.log(person)</script></body></html>

这段代码不仅实现了age属性的响应式定义,还通过大量注释说明了Object.defineProperty的各种配置项及其作用。下面我们将逐部分讲解这些注释内容和实际代码逻辑


3. 代码结构与变量初始化

3.1 外部变量number

letnumber=18
  • 这是一个闭包变量,用于存储age属性的真实值。
  • 使用外部变量而非直接在对象上存值,是为了配合 getter/setter 实现“拦截”逻辑。
  • 在 Vue 2 中,类似地,每个响应式属性背后都有一个内部存储(如_data.age),并通过 getter/setter 暴露给用户。

3.2 基础对象person

letperson={name:'张三',sex:'男',}
  • 初始对象仅包含两个普通属性:namesex
  • 后续将通过Object.defineProperty动态添加age属性,而非直接赋值(如person.age = 18)。

4.Object.defineProperty的完整配置解析

调用:

Object.defineProperty(person,'age',{/* descriptor */})

目标是为person对象定义一个名为'age'的新属性,其行为由描述符(descriptor)控制。

4.1 被注释掉的数据描述符(Data Descriptor)

// value:18,// enumerable:true, // 控制属性是否可以枚举,默认值为false// writable:true, // 控制属性是否可以被修改,默认值是false// configurable:true, // 控制属性是否可以被删除,默认值是false

这些是数据描述符的典型配置项,适用于直接定义静态值的属性:

  • value:属性的值。若使用此选项,则不能同时使用get/set
  • enumerable:是否可枚举。
    • 若为false(默认),则该属性不会出现在for...in循环、Object.keys()JSON.stringify()中。
    • 示例中未显式设置,因此age默认不可枚举。
  • writable:是否可写。
    • 若为false,则person.age = 20会静默失败(严格模式下抛错)。
  • configurable:是否可配置。
    • 若为false,则无法删除该属性,也无法再次修改其描述符(包括转为 getter/setter)。

关键点:一旦使用get/set(存取描述符),就不能再使用valuewritable,否则会报错。

4.2 被注释掉的旧式 getter 写法

// get:function(){// //return 'hello'// console.log('有人读取age属性了')// return number// }

这是 ES5 风格的函数写法,功能与下方的简写形式完全一致。现代开发中通常使用 ES6 的方法简写:

get(){console.log('有人读取age属性了')returnnumber}

两者等价,后者更简洁。

4.3 实际启用的 getter

get(){//return 'hello'console.log('有人读取age属性了')returnnumber}
  • 当代码执行person.age时,自动调用此函数。
  • 函数体中:
    • console.log(...)用于追踪访问行为(模拟 Vue 的依赖收集日志)。
    • return number返回真实存储的值。
    • 注释掉的//return 'hello'表明:你可以返回任意值,不一定要与原变量一致(可用于计算属性或格式化)。

4.4 实际启用的 setter

set(value){console.log('有人修改了age属性,且值是:',value)number=value}
  • 当执行person.age = newValue时,自动调用此函数,value即为传入的新值。
  • 函数体中:
    • 打印日志,记录修改行为(模拟 Vue 的派发更新通知)。
    • 将新值赋给闭包变量number,确保后续get能返回最新值。
  • 注意:setter 不返回任何值,其作用是副作用(side effect)。

5. 最终日志输出与行为验证

console.log(person)

5.1 控制台初始输出

运行页面后,控制台首先显示:

{ name: "张三", sex: "男" }
  • age未显示,因为其enumerable默认为false
  • 此时未触发getset,因为只是打印对象引用,未实际访问age

5.2 手动测试 getter/setter(在控制台执行)

测试 1:读取age
person.age

输出

有人读取age属性了 18

→ 触发get,返回number的当前值。

测试 2:修改age
person.age=30

输出

有人修改了age属性,且值是: 30

→ 触发set,将number更新为 30。

测试 3:再次读取
person.age

输出

有人读取age属性了 30

get返回更新后的值。


6. 与 Vue 2 响应式系统的关联

上述代码正是 Vue 2 实现响应式的核心简化版:

  • get→ 收集依赖(如 Watcher)
  • set→ 通知依赖更新(触发 re-render)
  • 闭包变量number→ 对应组件实例的_data.age
  • 不可枚举性→ 避免干扰普通属性遍历

这也解释了为什么 Vue 2 无法检测到:

  • 新增属性(需Vue.set
  • 删除属性(需Vue.delete
  • 数组索引直接赋值(因无法拦截)

因为Object.defineProperty只能拦截已知属性的读写。


7. 总结

本文不仅展示了Object.defineProperty的基本用法,更完整解读了原始代码中的每一处注释和设计意图

  • 数据描述符(value,writable,enumerable,configurable)的作用与限制;
  • 存取描述符(get/set)如何实现属性拦截;
  • 闭包变量在状态管理中的关键角色;
  • 控制台输出的行为逻辑及测试方法;
  • 与 Vue 2 响应式原理的直接对应关系。

通过这种“带注释的代码 + 逐行讲解”的方式,我们不仅能学会如何使用Object.defineProperty,更能理解其在框架底层中的工程价值。这对于深入前端原理、排查响应式 bug、乃至面试进阶都具有重要意义。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/9 23:45:08

手把手教程:高速信号走线长度匹配实现

高速PCB设计的灵魂&#xff1a;走线长度匹配实战全解析你有没有遇到过这样的情况&#xff1f;电路板焊接完成&#xff0c;上电后系统却频繁死机、内存初始化失败&#xff0c;或者高速接口&#xff08;比如HDMI、PCIe&#xff09;传输误码率高得离谱——而所有电源和逻辑都“看起…

作者头像 李华
网站建设 2026/4/14 11:36:45

赡养老人税收优惠:Qwen3Guard-Gen-8B核实被赡养人资格

赡养老人税收优惠&#xff1a;Qwen3Guard-Gen-8B核实被赡养人资格 在智能税务服务日益普及的今天&#xff0c;一个看似简单的问题——“我爸妈都70岁了&#xff0c;能扣多少税&#xff1f;”——背后可能隐藏着复杂的合规挑战。如果用户接着问&#xff1a;“那我把朋友的老爸写…

作者头像 李华
网站建设 2026/4/15 9:41:12

企业级微信自动化:Wechaty在客户服务的落地案例

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个企业微信客服系统&#xff0c;基于Wechaty实现&#xff1a;1.自动识别客户意图并分类&#xff08;咨询/投诉/售后&#xff09;2.智能路由到对应人工客服3.自动生成工单并同…

作者头像 李华
网站建设 2026/4/8 17:45:15

MOBSF vs 人工审计:安全测试效率提升300%的秘诀

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 构建一个MOBSF效率分析工具&#xff0c;功能包括&#xff1a;1)自动化测试流程编排 2)与人工审计结果对比模块 3)可视化效率指标仪表盘 4)测试用例管理。需要实现&#xff1a;自动…

作者头像 李华
网站建设 2026/4/8 9:15:34

告别手动操作:Excel合并单元格效率提升300%的秘诀

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个Excel合并单元格效率工具&#xff0c;支持以下功能&#xff1a;1) 批量选择相同格式区域自动合并&#xff1b;2) 记忆常用合并模式&#xff1b;3) 快捷键快速操作&#xf…

作者头像 李华
网站建设 2026/4/12 9:41:51

AI一键生成Docker+Nginx配置,告别手动编写

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 请生成一个完整的DockerNginx部署方案&#xff0c;包含&#xff1a;1) 基于Alpine的轻量级Dockerfile 2) Nginx配置支持反向代理和静态文件服务 3) 包含健康检查的docker-compose.…

作者头像 李华