你有没有注意到 Angular 代码示例中出现了一个哈希符号?如果没有,您可能很快就会看到它。的目的是什么#,什么时候应该使用它?

该#符号最近被添加到 JavaScript 中以表示私有类属性。将类变量设为私有意味着只能在其类中访问该变量。这使我们能够封装我们只想在服务中访问的数据。

但是我们的类字段不是已经有一个私有访问器了吗?是的!


【资料图】

那么为什么我们需要新的哈希语法呢?

让我们先看一下私有访问器,然后检查#语法以及为什么在我们的 Angular 应用程序中它是更好的选择。

(更|多优质内|容:java567 点 c0m)

公共类财产的危险

让我们从在服务中创建一个属性开始,并尝试从我们的组件访问它。对于这个例子,我们有一个产品服务和一个产品组件。

在产品服务中,我们为将用于获取产品数据的 URL 创建一个属性。还有一个products属性来保存我们检索到的产品数组。

// Product Service @Injectable({   providedIn: 'root' }) export class ProductService {   productUrl = 'api/products';   products = [];  }

为了验证 URL 的值,让我们创建一个方法来记录它:

// Product Service logUrl() {   console.log('Url:', this.productUrl); }

然后我们将在 Product 服务构造函数中调用该方法:

// Product Service constructor() {   this.logUrl(); }

默认情况下,我们在类中定义的变量是公共的,这意味着我们应用程序中的任何其他代码都可以访问它们。所以我们应该能够从我们的组件访问我们的产品服务属性。

试一试吧。在 Product 组件中,我们首先注入服务。在这个例子中,我们使用新inject函数来进行依赖注入而不是构造函数。并添加inject到导入语句 from @angular/core。

然后我们添加一个构造函数。因为默认情况下类的任何属性或方法都是公共的,所以我们可以更改我们在服务中定义的 URL。为了确认,我们将调用服务方法来记录 URL。

// Product Component productService = inject(ProductService);  constructor() {   this.productService.productUrl = `api/nefarious`;    this.productService.logUrl(); }

如果我们运行应用程序并打开开发人员工具,我们首先会看到服务记录 URL,然后我们会看到组件的已更改 URL。

好吧……那可不好。我们的组件能够更改服务中定义的 URL。

TypeScript 的私有可访问性功能

为了更好地保护我们的服务属性不在服务之外被修改,我们使用private accessibility。

私有可访问性是 TypeScript 的一项功能。它标记一个类属性或方法,以便只能从类内部访问它。该属性或方法不可从任何其他组件或服务获得。

private要使用私有可访问性,我们在变量名前添加关键字。

// Product Service private productUrl = 'api/products';

由于我们当前正在组件中修改此属性,因此组件代码现在会生成一个错误:Property 'productUrl' is private and only accessible within class 'ProductService'.太棒了!我们的组件无法再从我们的服务访问私有财产。

通过在服务中的属性前面添加 TypeScript 私有可访问性关键字,该变量只能从该服务访问。

但是,回到组件,如果我们尝试做这样的事情会怎样:

// Product Component constructor() {   for (let i in this.productService) {     console.log('properties:', i);   }    this.productService.logUrl(); }

循环for...in遍历对象的属性。在此示例中,我们将每个属性显示到控制台。

请注意,它显示了我们的公共和私有属性。现在我们可以看到私有属性的名称,我们可以使用它来更新该私有属性。

// Product Component constructor() {   for (let i in this.productService) {     console.log('properties:', i);   }    this.productService['productUrl']= 'api/nefarious';   this.productService.logUrl(); }

哎呀!我们再次修改了我们组件的服务属性。我们的私人财产不是那么私人。

这是为什么?这是因为private关键字是 TypeScript 的一部分,而不是 JavaScript。这意味着私有可访问性仅在开发期间作为类型检查的一部分和编译期间强制执行。我们在开发和编译期间收到通知,我们无法从其类外部访问私有属性。

但是当我们的 TypeScript 代码被转换为 JavaScript 并执行时,private 关键字就消失了。这意味着 JavaScript 运行时构造(例如我们的for...in循环或简单的属性查找)仍然可以访问使用关键字定义的属性或方法private。换句话说,组件可以在运行时访问我们服务中的私有属性。哎呀!

JavaScript 的私有类成员 (#)

使用 JavaScript#语法可以解决这个问题。最近,JavaScript 添加了私有类属性和方法,用#. 由于#是 JavaScript 的一部分,它表示我们的属性和方法在开发、编译和运行时是私有的。

在产品服务中,让我们删除private关键字并添加#. 是#变量本身的前缀,并成为变量名称的一部分。所以我们需要在访问它的任何地方更改变量名称,例如在我们的logUrl方法中。

// Product Service @Injectable({   providedIn: 'root' }) export class ProductService {   #productUrl = 'api/products';   products = [];    constructor() {      this.logUrl();   }    logUrl() {     console.log('Url:',this.#productUrl);   } }

我们现在在访问 Product 组件中的属性时看到错误:Property 'productUrl' does not exist on type 'ProductService'. Did you mean '#productUrl'?

我们可以尝试更改组件中的属性查找代码以#也包含一个。

// Product Component constructor() {   for (let i in this.productService) {     console.log('properties:', i);   }    this.productService['#productUrl']= 'api/nefarious';   this.productService.logUrl(); }

但仍未找到该属性:Property '#productUrl' does not exist on type 'ProductService'。我们服务中的私有属性现在从我们的组件中正确隐藏了。我们需要删除访问#productUrl我们的代码才能成功编译的属性查找行。

查看控制台,注意我们for...in loop现在找到了公共products属性,但没有找到私有productsUrl属性。我们的私有财产是私有的和隐藏的,正确地封装在我们的服务中。

包起来

作为 Angular 开发人员,我们一直在使用 Typescriptprivate可访问性关键字来将属性或方法设为私有。但这只保护开发和编译类型的属性,而不是运行时。

现在我们可以使用 JavaScript 私有类属性语法(用 符号表示#)使私有属性和方法真正私有并从代码的其他部分隐藏。

(更|多优质内|容:java567 点 c0m)

推荐内容