详解JS对象中属性的两种类型:数据属性与访问器属性

作者:青柠时间:2026-10-30 19:12:08浏览:549

本文深入解析JavaScript中对象的两种核心属性类型:数据属性和访问器属性。详细阐述数据属性的四个特性(Configurable、Enumerable、Writable、Value)及访问器属性的Get/Set机制,并结合Vue2源码中利用Object.defineProperty实现响应式的案例,说明两者在底层实现中的关键作用与区别。

前言

在深入理解Vue底层响应式机制时,我们会发现对象中的属性并非表面看起来那样简单的key:value形式,其背后还隐藏着更为复杂的内部特性。

具体而言,对象内部的属性主要被划分为两种类型:数据属性和访问器属性。

根据ECMAScript规范的定义,对象本质上是一个无序属性的集合,其中每个属性都表现为一个键值对。这里的键可以是字符串或Symbol类型,而值则可以是具体的数据值或用于访问的函数。

关于对象属性是有序还是无序的讨论,感兴趣的朋友可以参考我撰写的其他相关文章。

本文的重点在于厘清数据属性和访问器属性的具体定义及其各自的功能作用。

数据属性

数据属性是我们在日常开发中最常使用的属性类型,其表现形式符合我们常规的认知。

通常,我们可以通过对象字面量的方式或者使用new Object构造函数来创建这类属性。

// 对象字面量
const obj = {
  name: '小涛' // 这个name就是数据属性
}
// new Object
const obj2 = new Object({
  name: '小涛'  // 这个name就是数据属性
})

针对数据属性,ECMAScript规范定义了四个描述其行为特性的内部属性,具体包括:

[[Configurable]]:表示属性是否可配置。该特性决定了属性能否被删除或修改其特性。一旦将此特性设置为false,属性将无法通过delete语句删除,同时也禁止再次修改其他特性(例如将其转换为访问器属性)。

注意:一旦将属性的 configurable 特性定义为 false ,即不可配置的,该属性就不能再改回可配置的了。此后,再调用 Object.defineProperty() 方法修改除了 writable 特性的特性都会导致错误。(JavaScript 高级程序设计)

[[Enumerable]]:表示属性是否可枚举。若该特性为false(不可枚举),则该属性不会出现在for-in循环中,也不会被Object.keys()方法返回。

[[Writable]]:表示属性值是否可修改。该特性决定了是否允许更改属性的值。

[[Value]]:存储属性的实际数据值。当向属性写入值时,数据会保存于此;读取属性值时,则从此处读取。该特性的默认值为undefined。

当我们通过对象字面量或new Object方式创建对象时,其所有属性的上述特性默认值均为true。

若使用Object.defineProperty()方法显式定义新属性,对于未明确指定的特性,其默认值均为false。

接下来,我将通过Object.defineProperty()方法分别演示这些特性的具体行为。

[[Configurable]] 是否可配置

const obj = {}

Object.defineProperty(obj, 'name', {
    configurable: false, // 不可配置
    value: '小涛'
})

delete obj.name // 删除无效
console.log(obj, obj.name) // {name: '小涛'} '小涛'

// 除了writable,无法重新配置
Object.defineProperty(obj, 'name', { // 报错: Cannot redefine property: name atFunction.defineProperty
    enumerable: true
})

[[Enumerable]] 是否可枚举

const obj = {}
Object.defineProperty(obj, 'name', {
    enumerable: false, // 不可枚举
    value: '小涛'
})

console.log(obj.name, Object.keys(obj)) // 小涛 []

访问器属性

访问器属性是对象属性的另一种重要类型,在对象中通常通过get和set关键字来创建。

同样地,访问器属性也拥有四个描述其行为的内部特性,具体如下:

[[Configurable]]:含义与数据属性中的定义一致,即是否可配置。若设为false,则无法删除属性或修改其他特性(包括转为访问器属性)。

[[Enumerable]]:含义与数据属性中的定义一致,即是否可枚举。若为false,则无法通过for-in循环或Object.keys()获取该属性。

[[Get]]:这是一个用于读取属性值的函数。如果属性没有定义getter函数,则该特性值为undefined。

[[Set]]:这是一个用于设置属性值的函数。如果属性没有定义setter函数,则该特性值为undefined。

在Vue2的实现中,正是利用了访问器属性的特性。通过Object.defineProperty方法,Vue将对象中的所有属性都转化为带有getter和setter的访问器属性,从而实现了数据的响应式更新。

在实际使用中,我们既可以直接在对象字面量中使用get/set语法,也可以通过Object.defineProperty方法来定义getter和setter。

对象中使用

const obj = {
  _value: '',
  get value() {
      return this._value
  },
  set value(newVal) {
      this._value = newVal
  }
}

console.log(obj.value)

此时,obj.value即成为一个响应式属性。

Object.defineProperty 中使用

const obj = {}
Object.defineProperty(obj, 'value', {
    get() {
        return '小涛测试'
    },
    set(newValue) {
        console.log('获取更新', newValue)
    }
})
obj.value = '1111'

怎么获取属性描述符/特性

若需判断对象内属性的具体特性,可以使用Object.getOwnPropertyDescriptor()获取单个属性的描述符,或使用Object.getOwnPropertyDescriptors()获取全部属性的描述符。

const obj = {}
Object.defineProperty(obj, 'name', {
    enumerable: false, // 不可枚举
    writable: true, // 可修改
    value: '小涛'
})

console.log(Object.getOwnPropertyDescriptor(obj, 'name'))

前言

以上就是对JavaScript对象中数据属性和访问器属性的详细解析,更多相关技术资料欢迎持续关注本站的其他文章。

作者最新文章