JavaScript私有类字段和隐私的需要
闭包是保护变量不被访问的唯一JavaScript原生机制。
闭包是许多类似私有模式的基础,比如流行的模块模式。但在ECMAScript 2015 classes近年来接管之后,开发人员感到有必要对classes成员的隐私进行更多的控制。
class field提案(在第三阶段写作时)试图通过引入私有类字段来解决这个问题。
让我们看看它们是什么样的。
JavaScript私有类字段,一个例子
这里有一个带有私有字段的JavaScript类,注意,与“公共”成员不同,每个私有字段必须在访问之前声明:
代码语言:javascript复制class Person {
#age;
#name;
#surname;
constructor(name, surname, age) {
this.#name = name;
this.#surname = surname;
this.#age = age;
}
getFullName() {
return `${this.#name} ${this.#surname}`;
}
}
私有类字段不能从类外部访问:
代码语言:javascript复制class Person {
#age;
#name;
#surname;
constructor(name, surname, age) {
this.#name = name;
this.#surname = surname;
this.#age = age;
}
getFullName() {
return `${this.#name} ${this.#surname}`;
}
}
const marta = new Person("Marta", "Cantrell", 33);
console.log(marta.#age); // SyntaxError
这才是真正的“隐私”。现在,如果你使用了一些TypeScript,你可能会问“原生”私有字段和TypeScript中的私有修饰符有什么共同之处。
答案是:什么都没有。但是为什么呢?
TypeScript中的私有修饰符
来自传统背景的开发者应该熟悉TypeScript中的私有修饰符。简而言之,关键字意味着拒绝类成员从类外部访问。
但别忘了,TypeScript是在JavaScript之上的一层,TypeScript编译器应该去掉所有花哨的TypeScript注释,包括private。
这意味着下面的类不会做你认为它会做的事情:
代码语言:javascript复制class Person {
private age: number;
private name: string;
private surname: string;
constructor(name: string, surname: string, age: number) {
this.name = name;
this.surname = surname;
this.age = age;
}
getFullName() {
return `${this.name} ${this.surname}`;
}
}
const liz = new Person("Liz", "Cantrill", 31);
// @ts-ignore
console.log(liz.age);
没有// @ts-ignore,访问liz。age只会在TypeScript中抛出错误,但编译后你会得到以下JavaScript代码:
代码语言:javascript复制"use strict";
var Person = /** @class */ (function () {
function Person(name, surname, age) {
this.name = name;
this.surname = surname;
this.age = age;
}
Person.prototype.getFullName = function () {
return this.name " " this.surname;
};
return Person;
}());
var liz = new Person("Liz", "Cantrill", 31);
console.log(liz.age); // 31
不出所料,我们可以随意刊登莉兹的年龄。这里的主要观点是,TypeScript中的private并不是那么私密,它只在TypeScript级别上使用,而不是“真正的隐私”。
现在让我们来看看要点:TypeScript中的“原生”私有类字段。
TypeScript中的私有类字段
TypeScript 3.8增加了对ECMAScript私有字段的支持,不要与TypeScript私有修饰符混淆。
下面是TypeScript中一个带有私有类字段的类:
代码语言:javascript复制class Person {
#age: number;
#name: string;
#surname: string;
constructor(name:string, surname:string, age:number) {
this.#name = name;
this.#surname = surname;
this.#age = age;
}
getFullName() {
return `${this.#name} ${this.#surname}`;
}
}
除了类型注释之外,它与普通的JavaScript并没有什么不同。不能从外部访问成员。但TypeScript中私有字段的真正问题在于它们在底层使用了WeakMap。
要编译这段代码,我们需要调整tsconfig.json 中的目标编译版本,必须至少是ECMAScript 2015:
代码语言:javascript复制{
"compilerOptions": {
"target": "es2015",
"strict": true,
"lib": ["dom","es2015"]
}
}
这可能是一个取决于目标浏览器的问题,除非您打算为WeakMap提供一个腻子,如果仅仅是为了编写华丽的新语法,在这一点上就会产生太多的工作。
在JavaScript中总是存在这种紧张,您确实想使用新的语法,但另一方面,又不想让大量的腻子脚本让用户体验失望。
另一方面,我认为您不应该过多地担心私有类字段,即使您想要发布到更新的浏览器。至少现在是这样。对私有字段的支持几乎不存在。甚至Firefox也没有实施这个提议。
让我们看看未来会发生什么。
结论
在我写这篇文章的时候,JavaScript类字段仍然是一个提议,它很有趣,但是浏览器供应商的支持很差。你对这个功能有什么看法?
这是我的:
- 我喜欢ES私有类字段(尽管我不喜欢#)
- 我会一直等到私有类字段出现在所有主流浏览器中
- 因为弱映射,我今天不会在TS中使用私有类字段
- private在TypeScript中似乎是一个更好的选择,但只能在静态级别上工作
- TypeScript 3.8私有字段的官方声明。