6、setter和getter
之前说过,常规情况下,类是没办法直接实现变量的。
有一种变相的做法,是用es5的setter和getter特性来实现。
但这种办法并不是完美的,有两个缺陷:
- setter和getter,就功能来说更强大,但对于一般需求来说,又过于复杂了;
- setter和getter本身只是起到一个代理的作用,本身并不能真正存储变量,还是需要通过一个间接的变量来存储他;
- 这个用于存储的间接的变量,是可以被直接访问到的。
但setter和getter也有优点:
引自《 API design for C++ 》
- 有效性验证(可以在setter里检查设置的值是否在许可区间里)
- 惰性求值(比如一个成员计算过于耗时,而这个类的用户(这里的用户指其他程序员)不一定需要时,可以在getter方法调用的时候再计算)
- 缓存额外的操作(比如用户调用setter方法时,可以把这个值更新到配置文件里)
- 通知(其它模块可能需要在某个值发生变化的时候做一些操作,那么就可以在setter里实现)
- 调试(可以方便的打印设置日志,从而追踪错误)
- 同步(如果多线程访问需要加锁的话,setter里加锁不是很容易么)
- 更精细的权限访问(比如private变量只有getter没有setter,那客户对该变量就是只读了,而类的内部代码可以读写)
- 维护不变式关系(比如一个类内部要维持连个变量a和b有a = b * 2的关系,那么在a和b的setter里计算就能维持这样的关系)
以上引用内容复制自:
作者:浅墨
链接:https://www.zhihu.com/question/21401198/answer/37192335
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
对于js来说,有用的有:
- 常见情况下:1(超限则赋值无效)、5(很好用的说)、8(比如改了当前值后,顺便改了和他联动的另外一个值)
- 不常见情况有:2(类似的效果可以参考Vue的计算属性、4(比如关键属性被修改,log一发)、7(比如只允许读或只允许写)
关于class应用本特性的例子可以参考我的这篇博客:利用setter和getter实现数据校验
7、Generator函数
不懂Generator函数的,请从我的这篇博客开始阅读Generator函数(1)基本概念和示例。
没有基础的话,直接阅读本篇内容是很有可能看不懂的。
Generator函数在class里面的时候,在函数名之前加星号即可:
class Foo {
*g() {
yield "1";
yield "2"
return "3"
}
}
let p = new Foo()
let i = p.g()
i.next(); // {value: "1", done: false}
i.next(); // {value: "1", done: false}
i.next(); // {value: "3", done: true}
利用Generator函数,利用扩展运算符自动调用遍历器接口:
class Foo {
*[Symbol.iterator]() {
yield "1"
yield "2"
}
}
let p = new Foo()
console.log([...p]) // ["1", "2"]
8、async函数
既然支持Generator函数,当然也支持async函数啦。
使用方法和Generator函数的套路是一样的,在函数名前加async就行了。
示例代码如下:
function delay(msg) {
return new Promise(resolve => {
setTimeout(function () {
resolve(msg)
}, 1000)
})
}
class Foo {
async foo() {
let r1 = await delay('1').then(msg => {
console.log(msg)
return msg
})
console.log(r1)
await delay('2').then(msg => {
console.log(msg)
})
}
}
let p = new Foo()
// "1" 第一个await表达式里then的log
// "1" r1的log
// "2" 第二个await表达式里then的log