「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
对象属性有两种类型,我们平时使用到的都叫做数据属性;还有一种,访问器属性(accessor properties),它们本质上是用于获取和设置值的函数,但从外部代码来看就像常规属性。
“getter” 和 “setter”
例如,我们有一个具有 name
和 surname
属性的对象 user
let user = {
name: "John",
surname: "Smith"
};
如果你现在还想添加一个 fullName
属性,该属性值由name和surname组成,你可以这样做
上面我们已经能获取到user.fullName
的值了,之所以能正常 读取 :就是因为有getter 在幕后运行。但是当你尝试给这个新属性赋值时
你会发现报错了,因为当前的fullName
只有一个 getter
。(注意,如果不是严格模式,不会提示这个错误);
所以你如果需要赋值,那么就应该对应的在加上一个setter
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
},
set fullName(value) {
[this.name, this.surname] = value.split(" ");
}
};
现在可以在来试试结果
这样,就实现了一个可读且可写的“虚拟”属性。
访问器描述符
我们前面已经说过属性的描述符是什么,那么【访问器属性】的描述符与【数据属性】的描述符一样吗?
答案是:不。
对于访问器属性,没有 value
和 writable
,但是有 get
和 set
函数。
所以访问器描述符可能有:
get
—— 一个没有参数的函数,在读取属性时工作,set
—— 带有一个参数的函数,当属性被设置时调用,enumerable
—— 与数据属性的相同,configurable
—— 与数据属性的相同。
“getter” 和 “setter” 的高级应用
你还可以把getter/setter 用作“真实”属性值的包装器,进行值的限制。
示例1:假如你想禁止太短的 user
的 name,可以创建一个 setter name
,并将值存储在一个单独的属性 _name
中,即
let user = {
get name() {
return this._name;
},
set name(value) {
if (value.length < 4) {
console.log("名字太多了,至少4个字符");
return;
}
this._name = value;
}
};
这个时候你在对name进行设置
可以看到,只有满足条件的才可以设置成功。
示例中name 被存储在
_name
属性中,并通过 getter 和 setter 进行访问。从技术上讲,外部代码可以使用user._name
直接访问 name。但是,这儿有一个众所周知的约定,即以下划线"_"
开头的属性是内部属性,不应该从对象外部进行访问。
你还可以利用 getter 和 setter 替换“正常的”数据属性,来控制和调整这些属性的行为。
示例2:假如你开始是使用数据属性 name
和 age
来实现 user 对象
后面你对象里又不想要age
了,想要改成birthday
这个时候存在一个问题,之前用到age属性的地方怎么办?
你可以找到所有的age,然后修改它,但是很明显这太麻烦了。这个时候你就可以使用getter来优雅的解决
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
// 年龄是根据当前日期和生日计算得出的
Object.defineProperty(this, "age", {
get() {
let todayYear = new Date().getFullYear();
return todayYear - this.birthday.getFullYear();
}
});
}
现在你不但成功添加了birthday
,同时age
也仍然可以正常访问。
总结
getter
get
语法将对象属性绑定到查询该属性时将被调用的函数。
语法:
{get prop() { ... } }
{get [expression]() { ... } }
getter
使用场景
-
需要允许访问返回动态计算值的属性。
-
需要反映内部变量的状态,而不需要使用显式方法调用。
setter
当尝试设置属性时,set
语法将对象属性绑定到要调用的函数。
语法:
{set prop(val) { . . . }}
{set [expression](val) { . . . }}
setter
使用场景
- 试着改变一个伪属性的值。(就像我们上面示例中的fullName)
参考资料:
🎨【点赞】【关注】不迷路,更多前端干货等你解锁
往期推荐