本文深入解析JavaScript原生私有类字段与TypeScript中private修饰符的本质区别。指出TypeScript的private仅编译时检查,编译后字段仍为公有;而JS原生私有字段(#前缀)通过WeakMap实现运行时真正隔离,但需ES2015+目标及polyfill支持,存在浏览器兼容性与开发成本权衡。
JavaScript私有类字段和隐私需求
在早期JavaScript中,缺乏保护变量不被外部直接访问的原生机制,除非利用闭包特性。
闭包构成了JavaScript中多种类似私有模式的基石,例如广受欢迎的模块模式。然而,随着ECMAScript 2015引入类语法,开发者对类成员访问权限的控制需求日益增强。
类字段提案(截至文章撰写时处于第3阶段)旨在通过引入私有类字段来解决这一痛点。
下面展示其具体形态。
一个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}`;
}
}
私有类字段无法从类外部直接访问:
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中的private修饰符有何异同。
答案是没有共同点。原因何在?
TypeScript中的private修饰符
拥有传统编程语言经验的开发者对TypeScript中的private关键字并不陌生。简言之,该关键字旨在阻止从类外部访问类成员。
但需注意,TypeScript是运行在JavaScript之上的类型层,TypeScript编译器会剥离所有TypeScript特有的注释,包括private关键字。
这意味着以下代码无法实现预期的私有效果:
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,在TypeScript环境中访问liz.age时会报错;但编译生成的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
如预期所示,我们可以从控制台输出liz.age。核心观点在于:TypeScript中的private并非真正的私有,它仅在TypeScript编译阶段提供便利,而非运行时隐私。
接下来讨论:TypeScript中支持的“原生”私有类字段。
TypeScript中的私有类字段
TypeScript 3.8开始支持ECMAScript私有字段,切勿将其与TypeScript的private修饰符混淆。
这是在TypeScript中使用私有类字段的类示例:
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:
{
"compilerOptions": {
"target": "es2015",
"strict": true,
"lib": ["dom","es2015"]
}
}
这可能导致兼容性问题。具体取决于目标浏览器,若需为WeakMap提供polyfill,则仅为使用新语法而增加的工作量可能得不偿失。
JavaScript中始终存在这种张力:既希望使用新语法,又不愿因大量polyfill影响用户体验。
另一方面,即使计划发布至较新浏览器,也无需过度担忧私有类字段。至少目前如此,甚至Firefox尚未完全实施该提案。
以上就是详解JavaScript私有类字段和TypeScript私有修饰符的详细内容,更多关于JavaScript私有类字段和TypeScript私有修饰符的资料请关注本站其它相关文章!