持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
本文的翻译于<<Effective TypeScript>>, 特别感谢!! ps: 本文会用简洁, 易懂的语言描述原书的所有要点. 如果能看懂这文章,将节省许多阅读时间. 如果看不懂,务必给我留言, 我回去修改.
技巧56:不要依赖private来隐藏信息
js一直都缺少隐藏class属性的方法,通常的解决办法在非公有的字段前面加下划线:
class Foo {
_private = 'secret123';
}
但是这种方法很容易绕开:
const f = new Foo();
f._private; // 'secret123'
ts添加了public,protected,private字段用来强制隐藏信息:
class Diary {
private secret = 'cheated on my English test';
}
const diary = new Diary();
diary.secret
// ~~~~~~ Property 'secret' is private and only
// accessible within class 'Diary'
但是关键字private是类型系统的功能。当js运行时,该功能就会消失。当编译成js后,变成了这样:
class Diary {
constructor() {
this.secret = 'cheated on my English test';
}
}
const diary = new Diary();
diary.secret;
private关键字只是不鼓励你获取该属性,但是无法阻止你。加上断言后,ts甚至都不厚警告你了:
class Diary {
private secret = 'cheated on my English test';
}
const diary = new Diary();
(diary as any).secret // OK
换句话说,不要依赖private来隐藏信息。那么我们该怎么做?传统最可靠隐藏js的方法是:闭包。 你可以这样做:
eclare function hash(text: string): number;
class PasswordChecker {
checkPassword: (password: string) => boolean;
constructor(passwordHash: number) {
this.checkPassword = (password: string) => {
return hash(password) === passwordHash;
}
}
}
const checker = new PasswordChecker(hash('s3cret'));
checker.checkPassword('s3cret'); // Returns true
js没有办法在constructor外获取到 passwordHash这个变量。当然这种方法也有问题:
- 任何想获取passwordHash变量的方法只能写在constructor里面。
- 实例化一个class就需要复制一份写在constructor的方法
- 防止了同一class其他实例访问data
闭包或许不方便,但是能让你的数据保证安全。
更新的方法就是使用私有字段,这一语言特性正在被巩固。在这项提议中,想让字段变得私有,在前面加#:
class PasswordChecker {
#passwordHash: number;
constructor(passwordHash: number) {
this.#passwordHash = passwordHash;
}
checkPassword(password: string) {
return hash(password) === this.#passwordHash;
}
}
const checker = new PasswordChecker(hash('s3cret'));
checker.checkPassword('secret'); // Returns false
checker.checkPassword('s3cret'); // Returns true
字段 #passwordHash无法在class外获取该字段。和闭包方法相比:class内的方法,和同类的其他实例可以获取该属性。js原生不支持私有字段,一种应变的方法使用WeakMaps来实现。该提议正在步骤3,当本书印刷出来,该提议也应该被接受。如果要使用该提议,建议先查阅ts release notes,看其是否可用。