这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
1. ES5 中读写属性
ES5 中通过“this.属性”的方式读写一个属性。
2. ES6 中读写属性
ES6 中可以轻松地实现对属性的读写操作,同时可以对属性进行保护和只读。
如果设置对象的属性为只读,可以这样写:
class Animal {
constructor (type) {
this.type = type
}
// age 属性只提供 get,就相当于设置为了只读
get age () { // 函数前加 get 或 set 就变成了属性,ES6 中允许把属性放在类的最顶层(没有被嵌套到构造函数里)
return 4
}
eat () {
console.log('I am eating food...')
}
}
let dog = new Animal('dog')
console.log(dog.age)
dog.age = 5 // 修改 age 属性的值
console.log(dog.age)
/* 运行结果:
4
4
*/
可以看到,age 属性设置为只读后,我们尝试重新赋值,age 的值并没有改变。
如果我们还想让 age 可写,可以这样做:
class Animal {
constructor (type) {
this.type = type
}
get age () {
return 4
}
set age (val) {
this.realAge = val // 注意:这里不能写成 this.age 否则就导致 this.age 和 set age (val) 形成死循环了。
}
// 注意:上面的两个 age 可以理解为对外的出入口名称,而不是实例对象的属性名。
eat () {
console.log('I am eating food...')
}
}
let dog = new Animal('dog')
console.log(dog.age)
dog.age = 5
console.log(dog.realAge)
/* 运行结果:
4
5
*/
可以看到,dog.age 赋值为 5 后,realAge 也被成功修改了。
注意,在写 set 的时候,不能写成这样:
set age (val) {
this.age = val
}
为什么呢?因为上述代码中,当我们给 this.age 赋值时,会再次进入 set age (val) 中,这不就形成死循环了吗?所以不能这么写。
我们还可以结合私有属性的概念,做出如下修改:
let _age = 4
class Animal {
constructor (type) {
this.type = type
}
// 利用闭包实现对 _age 这一私有属性的保护
get age () { // 函数前加 get 或 set 就变成了属性,ES6 中允许把属性放在类的最顶层
return _age // 注意:返回值和“出入口”的名字不能一样(比如这里如果写成 return age 就会导致死循环了)
}
set age (val) {
if (val > 4 && val < 7) {
_age = val
}
}
// 注意:上面的两个 age 可以理解为访问时的出入口,而不是实例对象的属性名。
eat () { // 定义实例对象的方法
console.log('I am eating food...')
}
}
let dog = new Animal('dog')
console.log(dog.age)
dog.age = 5
dog.age = 8
console.log(dog.age) // set 和 get 本身是函数,但是调用它们时是按属性调用的,所以这里的 age 后面不加括号
console.log(dog._age)
/* 运行结果:
4
5
undefined
*/
上面的代码中,为什么把对 _age 的声明放在 class 外面,而不是 class 里面,比如说放在 constructor 中呢?这是因为现在的语法还不支持私有属性,我们只能用闭包1的方式去做。_age 通过 dog 这个实例是取不到的,因为我们暴露的是 Animal 这个类的实例,而 _age 这个变量不在这个实例中,所以拿不到,因此上面的代码最后打印 dog._age 的结果是 undefined。但是,在 get 和 set 中可以拿到 _age,因为它们在相同的顶层作用域中。
总结:
ES5中通过“this.属性”的方式读写一个属性,但是做不到有条件地读写;而ES6中通过set和get的方式能让我们在属性的读写上有更大的操作权,实现有条件的读写。
Footnotes
-
闭包是指能够访问另一个函数作用域中的变量的函数。在
JavaScript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数”。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 ↩