likes
comments
collection
share

js 对象中属性的两种类型:数据属性、访问器属性

作者站长头像
站长
· 阅读数 14

前言

在理解vue底层响应式原理时,了解到,原来对象中的属性,不单单从表面看起来那么简单是key:value形式,而是还有隐藏的内部特性

其中对象内的属性 分为两种类型的属性:数据属性访问器属性

ECMAScript 规范中定义:对象是一种无序属性的集合,每个属性都是一个键值对,其中键是字符串或 Symbol 类型,值可以是数据值或访问器函数

其中对象是 有序 还是 无序 的问题,可以移步我的其他的文章参考

这里主要讲到 数据属性访问器属性 是什么,有什么作用

数据属性

数据属性是日常默认使用的类型,就是我们常见的方式

使用 对象字面量 或者 new Object 方式创建

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

而这个数据属性有以下4个描述其行为的特性。分别是:

[[Configurable]]:是否可配置,该属性是否可以被删除或修改特性,当修改这个特性为false时,不能通过delete删除属性,同时也不能再次修改其他的特性,包括不能改为访问器属性

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

[[Enumerable]]:是否可枚举,如果为不可枚举,则不能通过 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)) // 小涛 []

[[Writable]] 是否可修改

const obj = {}
Object.defineProperty(obj, 'name', {
    value: '小涛',
    writable: false // 不可修改
})
obj.name = '测试'
console.log(obj.name, Object.keys(obj)) // {name: '小涛'} '小涛'

访问器属性

访问器属性是对象属性中,另外一种类型,在对象中使用 get/set 创建

它也有一下4个描述其行为的特性。分别是:

[[Configurable]]:是否可配置,该属性是否可以被删除或修改特性,当修改这个特性为false时,不能通过delete删除属性,同时也不能再次修改其他的特性,包括不能改为访问器属性

[[Enumerable]]:是否可枚举,如果为不可枚举,则不能通过 for-in 循环或者 Object.keys() 返回该属性

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

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

在vue2中,正是利用 访问器属性,通过 Object.defineProperty 把对象中的属性 全部转化为访问器属性中的 getter/setter,来实现响应式

可以直接在 对象中使用get/set 或者通过 Object.defineProperty定义get/set 两种方式来使用

对象中使用

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'))

js 对象中属性的两种类型:数据属性、访问器属性