news 2026/1/11 4:56:09

【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/1/7 10:13:11

计算机网络期末考试专项突破:数据链路层三大基本问题全解析(封装成帧、透明传输、差错检测|附30+高频真题精讲)

计算机网络期末考试专项突破&#xff1a;数据链路层三大基本问题全解析&#xff08;封装成帧、透明传输、差错检测&#xff5c;附30高频真题精讲&#xff09;适用对象&#xff1a;计算机科学、网络工程、信息安全、通信工程等专业本科生 关键词&#xff1a;数据链路层、封装成帧…

作者头像 李华
网站建设 2026/1/9 3:30:12

MCP认证必看:Azure Stack HCI 部署全流程实战(从规划到上线全解析)

第一章&#xff1a;MCP认证与Azure Stack HCI概述Microsoft Certified Professional&#xff08;MCP&#xff09;认证是IT专业人员在微软技术生态中建立权威性的重要里程碑。它不仅验证了个人对微软解决方案的掌握程度&#xff0c;也为深入理解如Azure Stack HCI等混合云架构奠…

作者头像 李华
网站建设 2026/1/9 0:49:03

JLink下载与虚拟机环境下驱动兼容性研究

JLink下载与虚拟机环境下的驱动协同实战指南你有没有遇到过这样的场景&#xff1a;手头的嵌入式项目必须在 Linux 下编译调试&#xff0c;但你的主力电脑是 Windows&#xff1f;于是你果断启用了 VMware 或 VirtualBox 跑起 Ubuntu&#xff0c;工具链装好、代码拉下、GDB 配置完…

作者头像 李华
网站建设 2026/1/10 14:51:33

ESP32固件库下载实战案例:从环境搭建到首次下载

从零开始玩转ESP32固件下载&#xff1a;一次搞懂环境搭建、烧录流程与启动机制你有没有过这样的经历&#xff1f;手里的ESP32开发板插上电脑&#xff0c;满心期待地运行烧录命令&#xff0c;结果终端却报出一连串红色错误&#xff1a;A fatal error occurred: Failed to connec…

作者头像 李华
网站建设 2026/1/8 22:19:15

LLAMAFACTORY vs 传统开发:效率对比分析

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 生成一个对比分析报告&#xff0c;展示使用LLAMAFACTORY和传统手动开发方式完成同一个项目&#xff08;如一个简单的电商网站&#xff09;的时间、代码行数和错误率。报告需包含图…

作者头像 李华