实现此目的的一种方法是使用另一个 ES2015 功能,称为 modules。
您可能已经熟悉 AMD 模块或 commonJS 模块(由 Nodejs 使用)。 ES6 / ES2015 为 JS 带来了一个标准——我们将它们称为 ES6 模块,但它们现在是 JS 语言的一部分。一旦有了模块,您就可以对私有函数和对象变量进行信息隐藏。请记住,只有您“导出”的内容对客户端调用代码可见。
让我们完成您的示例代码。这是第一个剪辑:
person.js
const getNameWithInitial = function () {
let initial = this._gender === 'male' ?
'Mr. ' :
'Mrs. ';
return initial + this._name;
}
export class Person {
constructor(name, gender) {
this._name = name;
this._gender = gender;
}
get name() {
return getNameWithInitial.call(this);
}
}
}
client.js
import {Person} from './person';
const manas = new Person('Manas', 'male');
console.log(manas.name); // this calls what was your getName function
现在,getNameWithInitial 函数实际上是私有的,因为它没有被导出,所以 client.js 看不到它。
但是,Person 类仍然存在问题,因为它是导出的。目前,您可以走到 manas 对象并执行以下操作:
manas._name = 'Joe'
通过像 _name 这样的属性,我们可以组合模块和symbols。这是 ES6+/ES2015 提供的一种强大而轻量级的信息隐藏技术。
Symbol 是一种新的内置类型。每个新的符号值都是唯一的。因此可以用作对象的键。
如果客户端调用代码不知道用于访问该密钥的符号,他们就无法获取它,因为该符号没有被导出。
让我们看看我们修改后的代码,利用符号和模块来隐藏类属性。
person.js
const s_name = Symbol();
const s_gender = Symbol();
const getNameWithInitial = function () {
let initial = this[s_gender] === 'male' ?
'Mr. ' :
'Mrs. ';
return initial + this[s_name];
}
export class Person {
constructor(name, gender) {
this[s_name] = name;
this[s_gender] = gender;
}
get name() {
return getNameWithInitial.call(this);
}
}
所以,现在客户不能只做:
manas._name = 'Joe'
因为 _name 没有用作名称值的键。
但是,符号是通过 Object.getOwnPropertySymbols 等反射功能暴露的,因此请注意,使用此技术它们不是“完全”私有的。
import {Person} from './person';
const manas = new Person('Manas', 'male');
const vals = Object.getOwnPropertySymbols(manas);
manas[vals[0]] = 'Joanne';
manas[vals[1]] = 'female';
外卖消息 - 模块通常是隐藏某些内容的好方法,因为如果不导出,则无法在模块外部使用,并且与私有存储的符号一起用作键,然后类属性也可以隐藏(但是不是严格私人的)。今天使用模块可以通过构建工具获得,例如。 webpack / browserify 和 babel。