如何在es6类中声明私有variables和私有方法

在es5中,我们使用构造函数

function Person(name,gender){ var initial =""; // we use var key word to make variable private function getNameWithInitial(){ // this is the private method to get name with initial console.log(this); initial = this.gender ==="male"?"Mr. ":"Mrs. "; return initial + this.name; } this.name = name; this.gender = gender; this.getName = function(){ return getNameWithInitial.call(this); } } var manas = new Person("Manas","male"); console.log(manas.getName()); 

我的问题是如何在es6类中声明私有variables和私有方法

达到此目的的一种方法是使用另一个称为模块的 ES2015function。

您可能已经熟悉AMD模块或commonJS模块(由Nodejs使用)。 那么ES6 / ES2015为JS带来了一个标准 – 我们称它们为ES6模块,但现在它们是JS语言的一部分。 一旦你有了模块,你就可以为私有函数和对象variables进行信息隐藏。 请记住,只有您“导出”是可见的客户端调用代码。

让我们通过您的示例代码工作。 这是第一次切割:

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._name = 'Joe' 

_name这样的属性,我们可以组合模块和符号 。 这是ES6 + / ES2015提供的强大而轻量的信息隐藏技术。

符号是一种新的内置types。 每个新的符号值都是唯一的。 因此可以用作对象上的键。

如果客户端调用代码不知道用于访问该密钥的符号,则由于该符号不被导出,所以它们不能得到它。

让我们看看我们修改后的代码,使用符号和模块来隐藏类属性。

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不被用作名称值的关键字。

但是,符号通过reflectionfunction暴露,如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'; 

外卖消息 – 一般来说,模块是隐藏某些东西的好方法,因为如果没有导出,那么不能在模块外部使用,并且与私有存储的符号一起用作键,那么类属性也可以隐藏起来(但不是严格私有的)。 现在使用模块可以使用构build工具,例如。 webpack / browserify和babel。

如果你想要一个类似于ES5的解决scheme,那很简单。 constructor简单地变成了持有闭包的东西,并且在那里添加了任何应该记住私有状态的方法/对象。
原型方法没有访问初始构造函数的闭包,没有使用一些特权的getter:

 class Person { constructor ({ name, age, deepDarkSecret }) { const bribe = () => console.log(`Give me money, or everybody will know about ${ redactRandom(deepDarkSecret) }`); Object.assign(this, { name, age }); // assigning publicly accessible values Object.assign(this, { bribe }); // assign "privileged" methods (functions with closure-reference to initial values) } recallSecret () { console.log("I'm just a prototyped method, so I know nothing about any secret, unless I use a privileged function..."); this.bribe(); } } 

如果你看看这个networking是什么,你会注意到它和你的例子没有多大区别(只是使用“更清晰”的铃声和哨声,特别是添加原型/静态方法时)。 它仍然是原型。

如果你有使用任何模块/导出(ES6是理想的)的豪华,那么与另一种数据types, 你可以有真正的隐私,不必自行清理

这是一个有点hackey看起来。 它可能会变得不那么丑陋,并希望在未来更干净的基础,但如果你想要基于实例的私人访问,即使是原型方法,然后在模块内部创build一个WeakMap从你的课堂出口。

this作为你的钥匙。 现在所有原型方法都可以通过闭包访问弱映射,而不是使用具有闭包访问的特权函数。
…缺点是,任何时候你想要私有variables,你必须在WeakMap查找它们,而不是把它们从这里拉出来。

 const personalBaggage = new WeakMap(); class Person { constructor ({ name, age, darkestMoment }) { const privates = { name, age, darkestMoment }; personalBaggage.add(this, privates); } recallDarkestHour () { const { darkestMoment } = personalBaggage.get(this); console.log(darkestMoment); } } export default Person; 

只要你不失去这个内部的参考,这应该只是工作。
与使用Symbol不同的是,无论您尝试多么艰难,都无法获得私有对象的引用。
如果您知道对象上的符号,则可以使用符号查找属性。
获取任何对象上的符号列表只是一个函数调用。 Symbol不是关于保密的东西; 它是关于避免命名冲突的安全措施,以及定义可用于任何对象/函数的通用符号,但不会被循环拾取,不会被意外调用或覆盖等等。

将这个私密数据包作为密钥存储在一个弱映射表中,可以访问完全隐藏的数据集,而这个数据集在该模块之外是完全无法访问的。
更好的是,weakmaps的关键/价值并不妨碍GC进行清理。
通常情况下,如果他们留在一个arrays,他们会留在那里。 如果最后一个对象被用作弱映射中的一个键,那么它将被收集,弱映射值会被自动擦除(在本地ES6中;内存奖励不能被多重填充,但对象可以)。

这是一个非常好的主题。 我不知道在你的问题之前,在ES6中做这个事情,但经过审查后,它看起来很酷。 所以你创build一个索引到函数的符号。

这里是直接从他们坐的代码。

 var Person = (function() { var nameSymbol = Symbol('name'); function Person(name) { this[nameSymbol] = name; } Person.prototype.getName = function() { return this[nameSymbol]; }; return Person; }()); var p = new Person('John'); 

JavaScript中的私有属性

您可以使用Symbol来完成它。

 const _name = Symbol(); class Person { constructor(name) { this[_name] = name; } } const person = new Person('John'); alert(person.name); // => undefined