JavaScript学习笔记

JavaScript学习笔记7_对象_3存取器属性和属性特性

2019-11-15  本文已影响0人  菜出意料

概述

对象属性是由名字(key)、值(value)和一组特性(值、可写性、可枚举性和可配置性)构成的。在ECMAScript5中,属性值可以使用getter和setter替代。由getter和setter定义的属性被称作“存取器属性”。当访问存储器属性时,会调用对应的getter方法,getter是无参方法,返回值就是属性的值。当程序设置存取器属性时,会调用对应的setter方法,并将赋值表达式右侧的值当作参数传递给setter方法,无(忽略)返回值。

注意: 存取器属性不具有可写性。如果属性同时具有getter和setter方法,那么它是读/写属性。如果只有getter方法,那么是只读属性。如果只有setter方法,是只写属性,读取只写属性只会得到undefined。

简单示例

var p = {
    x: 0,
    y: 0,
    get s() {return this.x + this.y}, // 注意getter和setter里的this关键字
    set s(v) {
        this.x += v
        this.y += this.x
    },
    get t() {return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2))}
}

p.s = 3 // 调用setter
p.s     // 6 调用getter
p.t     // 4.242640687119285
p.t = 12// 不起任何作用 无setter方法

存取器属性可被继承

var q = Object.create(p)
q.x = 2, q.y = 3
q.s     // 5
q.t     // 3.605551275463989

当需要对取值和赋值做一些特殊处理时,可以使用存取器属性,能起到类似过滤器/拦截器的作用。

属性的特性

属性除了名字(key)和值(value)之外,还包含一些标识它们可写、可枚举和可配置的特性。在ECMAScript3中无法设置这些特性,创建的所有属性都是可写、可枚举和可配置的,并且无法对特性进行修改。ECMAScript5允许对特性进行操作。
存取器属性不具有值(value)特性和可写性,它们的可写性是由setter方法存在与否决定的。因此存取器属性的的4个特性是读取(get)、写入(set)、可枚举性和可配置性。

查询属性特性--Object.getOwnPropertyDescriptor()

getOwnPropertyDescriptor获得对象指定自有属性的特性,继承属性或不存在的属性都返回undefined。

// 获取x属性的特性
Object.getOwnPropertyDescriptor({x:1}, 'x') // { value: 1, writable: true, enumerable: true, configurable: true }
Object.getOwnPropertyDescriptor({}, 'toString') // undefined toString是继承来的属性,不是自有属性
Object.getOwnPropertyDescriptor(Object.create({x:1}), 'x')  // undefined x是继承来的属性
// x是存取器属性,没有value和writable特性,有get和set特性
Object.getOwnPropertyDescriptor({get x(){return 1}}, 'x')   //{get: [Function: get x], set: undefined, enumerable: true, configurable: true}

设置属性特性--Object.defineProperty()

该方法要么修改已有的自有属性,要么新建自有属性,不能修改继承属性。对于新建属性的特性值默认为false或undefined。

var o = {x: 1}
Object.defineProperty(o, 'x', {value: 2, writable: true, enumerable: false, configurable: true})
o.x     // 2
o.propertyIsEnumerable('x')  // false 不可枚举
Object.keys(o) // [] 不可枚举
Object.defineProperty(o, 'x', {writable: false}) // 设置属性x不可写
o.x = 3  // 不起作用,在严格模式下报错
o.x     // 2
// 虽然可写性设置为了false,仍可通过下面的方式对其进行修改
Object.defineProperty(o, 'x', {value:5}) 
o.x // 5
Object.defineProperty(o, 'x', {get: function(){return 10;}}) // 将x设置为存取器属性
o.x // 10
Object.defineProperty(o, 'y', {})
console.log(Object.getOwnPropertyDescriptor(o, 'y')) // {value: undefined, writable: false, enumerable: false, configurable: false
o.y = 1 // 不起作用,因为writable为false
o.y // undefined
}

如果要同时修改或创建多个属性,需要使用Object.defineProperties()。

var p = Object.defineProperties({}, {
    x: {value: 1}, // 定义不可枚举、不可写、不可配置的属性x
    y: {value: 2, writable: true, enumerable: true}, // 创建不可配置的属性y,即不能被delete操作符删除
    z: {value: 3, writable: true, enumerable: true, configurable: true},
    r: {get: function(){return 4}, enumerable: true, configurable: true} // 存取器属性
})
Object.keys(p)  // [y, z, r] x是不可枚举的
delete p.y  // false,不起作用,因为y是不可配置的
p.y     // 2
delete p.z // true 删除属性z成功
p.z // undefined
Object.defineProperty(p, 'x', {get: function(){return 10}}) // TypeError,x是不可配置的,因此不能转为存取器属性,可参考下面的使用规则。

Object.defineProperty()和Object.defineProperties()使用规则

  • 如果对象是不可扩展的(参考对象的扩展性章节),可以编辑已有的自有属性,但不能给该对象添加属性。
  • 如果对象的属性是不可配置的,则不能修改它的可配置性(configurable)和可枚举性(enumerable)。
  • 如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将其转为数据属性(设置其value特性)。
  • 如果数据属性是不可配置的,则不能将其转为存取器属性。
  • 如果数据属性是不可配置的,则不能将它的可写性从false转为true,但可以从true转为false。
  • 如果数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(实际上是将其先改为可写,修改值,再转换为不可写)。
    违反以上规则,会抛出TypeError异常!!!
上一篇 下一篇

猜你喜欢

热点阅读