原来 js 跟 ts 也有相识之处

2021-04-22 11:28:31 浏览数 (1)

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私有字段的官方声明。

0 人点赞