[译] ECMAScript 类 —— 定义私有属性

栏目: JavaScript · 发布时间: 4年前

内容简介:像往常一样,我们将从一些理论知识开始介绍。ES 的类是 JavaScript 中新的语法糖。它提供了一种简洁的编写方法,并且实现了与我们使用原型链相同的功能。唯一的区别是,它看起来更像是面向对象编程了,而且,如果你是 C# 或 Java 开发者,感觉会更友好。有人可能会说它们不适合 JavaScript,但对我来说,使用类或 ES5 的原型都没有问题。它提供了一种更简单的方式来封装和定义多个属性,这些属性可以在具体的实例对象上被访问到。事实上,我们可以通过类的方式编写更少的代码来实现更多的功能。有了类,Ja

像往常一样,我们将从一些理论知识开始介绍。ES 的类是 JavaScript 中新的语法糖。它提供了一种简洁的编写方法,并且实现了与我们使用原型链相同的功能。唯一的区别是,它看起来更像是面向对象编程了,而且,如果你是 C# 或 Java 开发者,感觉会更友好。有人可能会说它们不适合 JavaScript,但对我来说,使用类或 ES5 的原型都没有问题。

它提供了一种更简单的方式来封装和定义多个属性,这些属性可以在具体的实例对象上被访问到。事实上,我们可以通过类的方式编写更少的代码来实现更多的功能。有了类,JavaScript 正朝着面向对象的方式发展,通过使用类,我们可以实现面向对象编程,而不是函数式编程。不要误解我的意思,函数式编程并不是一件坏事,实际上,这是一件好事,它也有一些优于类的好处,但这应该是另一篇文章要讨论的主题。

举一个实际的例子,每当我们想在应用程序中定义来自真实世界的事物时,我们都会使用一个类来描述它。例如,building、car、motorcycle……它们代表一类真实的事物。

可访问范围

在后端语言中,我们有访问修饰符或可见性级别,如 publicprivateprotectedinternalpackage ……不幸的是,JavaScript 仅以自己的方式支持前两种方法。它不通过编写访问修饰符( publicprivate )来声明字段,JavaScript 在某种程度上假定所有的区域都是公共的,这就是我写这篇文章的原因。

注意,我们有一种方法可以在类上声明私有和公共的字段,但是这些字段声明方法还是实验性的特性,因此还不能安全的使用它。

class SimCard {
  number; // public field
  type; // public field
  #pinCode; // private field
}
复制代码

如果没有像 Babel 这样的编译器,就不支持使用上面这样的字段声明方式。

定义私有属性 —— 封装

封装是编程中的一个术语,比如它用来描述某个变量是受保护的或对外部是不可见的。为了保持数据私有并且只对内部可见,我们需要 封装 它。在本文中,我们将使用几种不同的方法来封装私有数据。让我们开始吧。

1. 习惯约定

这种方式只是假定数据或变量的 private 状态。实际上,它们是公开的,外部可以访问。我了解到的两种最常见的定义私有状态的习惯约定是 $_ 前缀。如果某个变量以这些符号作为前缀(通常在整个应用中会规定使用某一个),那么该变量应该作为非公共属性来处理。

class SimCard {
  constructor(number, type, pinCode) {
    this.number = number;
    this.type = type;
    
    // 这个属性被定义为私有的
    this._pinCode = pinCode;
  }
}

const card = new SimCard("444-555-666", "Micro SIM", 1515);

// 这里,我们将访问私有的 _pinCode 属性,这并不是我们预期的行为
console.log(card._pinCode); // 输出 1515
复制代码

2. 闭包

闭包对于控制变量的可访问性非常有用。它被 JavaScript 开发者使用了几十年。这种方法为我们提供了真正的私有性,数据对外部来说是无法访问的,它只能被内部访问。这里我们要做的是在类构造函数中创建局部变量,并用闭包捕获它们。要实现这个效果,方法必须定义在实例上,而不是在原型链上。

class SimCard {
  constructor(number, type, pinCode) {
    this.number = number;
    this.type = type;

    let _pinCode = pinCode;
    // 这个属性被定义为私有的
    this.getPinCode = () => {
        return _pinCode;
    };
  }
}

const card = new SimCard("444-555-666", "Nano SIM", 1515);
console.log(card._pinCode); // 输出 undefined
console.log(card.getPinCode()); // 输出 1515
复制代码

3. Symbols 和 Getters

Symbol 是 JavaScript 中一种新的基本数据类型。它是在 ECMAScript 6 中引入的。 Symbol() 返回的每个值都是唯一的,这种类型的主要目的是用作对象属性的标识符。

由于我们的意图是在类定义的外部创建 Symbol 变量,但也不是全局的,所以引入了模块。这样,我们能够在模块内部创建私有字段,将它们定义到类的构造函数中,并通过 getter 返回 Symbol 变量对应的值。注意,我们可以使用在原型链上创建的方法来代替 getter 。我选择了 getter 方法,因为这样我们就不需要调用函数来获取值了。

const SimCard = (() => {
  const _pinCode = Symbol('PinCode');

  class SimCard {
    constructor(number, type, pinCode) {
      this.number = number;
      this.type = type;
      this[_pinCode] = pinCode;
    }

    get pinCode() {
       return this[_pinCode];
    }
  }
  
  return SimCard;
})();

const card = new SimCard("444-555-666", "Nano SIM", 1515);
console.log(card._pinCode); // 输出 undefined
console.log(card.pinCode); // 输出 1515
复制代码

这里需要指出的一点是 Object.getOwnPropertySymbols 方法,此方法可用于访问我们用来保存私有属性的 Symbol 变量。上面的类中的 _pinCode 值就可以这样被获取到:

const card = new SimCard("444-555-666", "Nano SIM", 1515);
console.log(card[Object.getOwnPropertySymbols(card)[0]]); // 输出 1515

复制代码

4. Map 和 Getters

ECMAScript 6 还引入了 MapWeakMap 。它们以键值对的形式存储数据,这使得它们非常适合存储我们的私有变量。在我们的示例中, Map 被定义在模块的内部,并且在类的构造函数中设置每个私有属性的键值。这个值被类的 getter 引用,同样,我们不需要调用函数来获取值。另外,请注意,考虑到 Map 本身的结构,我们不需要为每个私有属性定义 Map 映射。

const SimCard = (() => {
  const _privates = new Map();

  class SimCard {
    constructor(number, type, pinCode, pukCode) {
      this.number = number;
      this.type = type;
      _privates.set('pinCode', pinCode);
      _privates.set('pukCode', pukCode);
    }

    get pinCode() {
       return _privates.get('pinCode');
    }

    get pukCode() {
       return _privates.get('pukCode');
    }
  }
  
  return SimCard;
})();

const card = new SimCard("444-555-666", "Nano SIM", 1515, 45874589);
console.log(card.pinCode); // 输出 1515
console.log(card.pukCode); // 输出 45874589
console.log(card._privates); // 输出 undefined
复制代码

注意,在这种方法中,我们也可以使用普通对象而不是 Map ,并在构造函数中动态地为其分配值。


以上所述就是小编给大家介绍的《[译] ECMAScript 类 —— 定义私有属性》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ACM国际大学生程序设计竞赛

ACM国际大学生程序设计竞赛

俞勇 编 / 2012-12 / 29.00元

《ACM国际大学生程序设计竞赛:知识与入门》适用于参加ACM国际大学生程序设计竞赛的本科生和研究生,对参加青少年信息学奥林匹克竞赛的中学生也很有指导价值。同时,作为程序设计、数据结构、算法等相关课程的拓展与提升,《ACM国际大学生程序设计竞赛:知识与入门》也是难得的教学辅助读物。一起来看看 《ACM国际大学生程序设计竞赛》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具