js的属性描述符

目录

  • 属性描述符
  • 数据属性描述符
    • writable
    • enumerable
    • configurable
    • value
  • 存取属性描述符
    • get
    • set
    • 关于get与set
  • 通过Object.defineProperty实现响应式

属性描述符

ES5之前,我们虽然能通过字面量的形式直接在对象上添加或修改属性,但终究不能对其进行更加精细的管理,如此属性是否可重写可否被枚举等等
于是在ES5中推出了属性描述符属性描述符用于描述一个对象上指定的属性的特性或功能,属性描述符本身也是一个对象
属性描述符具体可分为两类,一类为数据属性描述符,一类为存取属性描述符
我们可以通过Object.getOwnPropertyDescriptor来获取一个指定对象上指定属性属性描述符

var obj = {
    name: '张三',
    age: 18
}
let desc = Object.getOwnPropertyDescriptor(obj, 'name')
console.log(desc)

js的属性描述符_第1张图片
Object.getOwnPropertyDescriptor需要传入两个参数,一个是指定的对象,一个是对象上的属性名,返回一个对象
如果想要设置属性描述符的话则需要使用Object.defineProperty

var obj = {
    name: '张三',
    age: 18
}
Object.defineProperty(obj, 'name', {
    value: '李四',
})
let desc = Object.getOwnPropertyDescriptor(obj, 'name')
console.log(desc)

js的属性描述符_第2张图片
Object.defineProperty需要传入三个参数,第一个是指定的对象,第二个是指定的属性名,第三个就是该属性的属性描述符

数据属性描述符

假如我们有这么一个对象,这个对象存储着一个商品的信息,其中name为商品名,price为商品售价,purchase为进价,count为商品的数量

var goods = {
    name: "apple",
    price: 10,
    count: 10,
    purchase: 5
}

writable

现在我们希望name属性不能被重写,我们就可以通过属性描述符实现

Object.defineProperty(goods, "name", {
    writable: false
})

writable即表示此属性能否被重写,如果为false就不能被重写

goods.name = "banana"
console.log(goods.name)

结果
我们可以看到赋值无效

enumerable

现在我们觉得purchase这个属性并不适合展示出来,我们就可以这么修改属性描述符

Object.defineProperty(goods, "purchase", {
    enumerable: false
})

enumerable即表示此属性能否被for...inObject.keys遍历到,如果为false则遍历不到

for (const key in goods) {
    console.log(key)
}
console.log(Object.keys(goods))

js的属性描述符_第3张图片

configurable

现在我们觉得price这个属性已经配置的很好了,希望以后这个属性的属性描述符不会再改变,我们就可以这么修改属性描述符

Object.defineProperty(goods, "price", {
    configurable: false
})

configurable即表示这个属性的属性描述符在此次修改之后能否再次被修改,如果为false则此次修改之后之后再无法修改此属性的属性描述符

Object.defineProperty(goods, "price", {
    configurable: true
})

结果
我们发现如果想再次修改属性描述符的话控制台会直接报错

value

最后再来谈谈value属性,value就是此属性的,嗯,没了

存取属性描述符

我们还是有一个商品对象

var goods = {
    name: "apple",
    price: 10,
    count: 10,
    purchase: 5
}

现在我们同样需要price属性不能被修改,不仅不能被修改,还需要在修改的时候报错,这时候我们如果仅仅使用数据属性描述符是无法实现的,需要使用存取属性描述符

get

get也被称为getter,如果配置了get方法,那么当用户访问此属性时会调用get方法,如果没有配置get则为undefined

var price = goods.price

Object.defineProperty(goods, "price", {
    get() {
        return price
    }
})

set

set也被称之为setter,如果配置了set方法,那么当用户设置此属性时会调用set方法,如果没有配置set则为undefinedset方法会有一个参数,这个参数就是你设置此属性时传递的,如

goods.price = 2

这里的2就会被传入set

var price = goods.price

Object.defineProperty(goods, "price", {
    set(val) {
        price = val
    }
})

setget合起来被称之为访问器,无论是get还是set,他们都是对象属性上的一种绑定机制,这个机制能让函数与属性关联起来,无论这个属性在之前是否有定义,或是否有值,在定义了getset的那一刻,它就成了一个特殊的属性
现在我们回到最开始的问题,如果我们希望price不能被修改并且在尝试修改price时会报错的话就可以这么写

var price = goods.price

Object.defineProperty(goods, "price", {
    get() {
        return price
    },
    set(val) {
        throw new Error("不允许修改价格")
    }
})
console.log(goods.price)
goods.price = 20
console.log(goods.price)

结果
结果

关于get与set

getset中不能访问当前设定的属性,如果访问了的话会无限递归,直到撑爆执行栈,强制报错

var price = goods.price

Object.defineProperty(goods, "price", {
    get() {
        return goods.price
    },
    set(val) {
        throw new Error("不允许修改价格")
    }
})
console.log(goods.price)
goods.price = 20
console.log(goods.price)

js的属性描述符_第4张图片

通过Object.defineProperty实现响应式

具体可以看我这篇文章
未动笔,未来可寄

你可能感兴趣的:(网页,javascript,前端,开发语言)