你真的理解对象吗?(访问器属性)

242 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。 本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

前言

吃饱饭才有力气写代码~

上次聊了聊对象属性中的数据属性中的四类特性,除此之外属性还有一类是访问器熟悉,接下来记录总结一下。

访问器属性不包含数据值,它们包含一个获取函数(getter)和一个设置(setter)函数,但是它俩并不是必须的。获取函数是在读取访问器属性时调用,负责返回一个有效的值;在写入访问器属性时会调用设置函数传入新的值,这个函数决定对数据作出怎样的修改。访问器也有四个特性来描述各自的行为:

  • [[Configurable]] 表示属性是否可以通过delete删除并重新定义,是否可以修改它的特性以及是否可以把它改为访问器属性,默认情况下所有直接定义在对象上的属性的这个特性都是true。
  • [[Enumerable]] 表示属性是否可以通过for-in循环返回,默认情况下所有直接定义在对象上的属性的这个特性都是true。
  • [[Get]] 获取函数,在读取属性时调用,默认值为undefined。
  • [[Set]] 设置函数,在读取属性时调用,默认值为undefined。 和数据属性一样,访问器属性也是不能直接定义的,需要使用Object.defineProperty()方法,比如下面这个例子:
let book = {
    year_: 2017,//私有成员
    edition: 1 //公共成员
};
Object.defineProperty(book,"year",{
    get(){
        return this.year_;
    },
    set(){
        if(newValue > 2017){
            this.year_ = newValue;
            this.edition += newValue - 2017;
        }
    }
});
book.year = 2018;
console.log(book.edition)//2

在上面这个例子里,book 对象有两个默认属性:year_和edition(year_的下划线常用来表示这个属性不希望在对象方法的外部被访问);另一个属性year被定义为一个访问器属性,设置函数会做一些计算来决定edition的值,获取函数会返回year_的值,因此 book.year = 2018;会使year_的值变为2018,edition变为2。这就是访问器典型的使用场景,也就是设置一个属性的值,从而导致其它一些发生变化;

注意:

获取函数和设置函数不一定都要定义,只定义获取函数意味着属性只读,此时尝试修改属性会抛出错误;类似地只定义设置函数的属性不能读取。

定义多个属性的方法

Object.defineProperties()这个方法可以通过多个描述符一次性定义多个属性,接收两个参数:要添加或修改属性的对象和一个描述符对象:

let book = {};
Object.defineProperties(book,{
    year_: {
        value: 2017
    },
    edition: {
        value: 1
    },
    year:{
        get(){
            return this.year_;
        },
        set(){
            if(newValue > 2017){
                this.year_ = newValue;
                this.edition += newValue - 2017;
            }
        }
    },
});

读取属性特性的方法

就上面定义的对象读取它的相关属性,用到的方法是 Object.getOwnPropertyDescriptor(),比如:

let descriptor = Object.getOwnPropertyDescriptor(book,"year_");
console.log(descriptor.value);// 2017
console.log(descriptor.configurable);// false
console.log( typeof descriptor.get);// "undefined"

let descriptor = Object.getOwnPropertyDescriptor(book,"year");
console.log(descriptor.value);// undefined
console.log(descriptor.configurable);// false
console.log( typeof descriptor.get);// "function"

新增了Object.getOwnPropertyDescriptors()静态方法,这方法会在每个自有属性上调用 Object.defineProperties() 并在一个新对象中返回,如下:

//上述例子定义的book
console.log(Object.getOwnPropertyDescriptors(book));
//{
//    edition:{
//        configurable: false,
//        enumerable: false,
//        value: 1,
//        writeable: false
//   },
//    year:{
//        configurable: false,
//        enumerable: false,
//        get: f(),
//        set: f(newValue)
//    },
//    year_:{
//        configurable: false,
//        enumerable: false,
//        value: 2019,
//        writeable: false
//    },
//}

总结

还有很多方法,且听下回分解~