Javascript 如何在es6类中声明私有变量和私有方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34869352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to declare private variables and private methods in es6 class
提问by manas
in es5 we use constructor function
在 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());
My question is how to declare a private variable and private method in es6 class
我的问题是如何在es6类中声明私有变量和私有方法
回答by arcseldon
One way to achieve this is using another ES2015feature known as modules.
实现此目的的一种方法是使用另一个称为modules 的ES2015功能。
You may already be familiar with AMDmodules, or commonJSmodules (used by Nodejs). Well ES6 / ES2015 brings a standard for JS - we'll call them ES6 modulesbut they are part of the JS language now. Once you have modules, you have the ability to do information hiding for both private functions and object variables. Bear in mind, only what you "export" is visible to client calling code.
您可能已经熟悉AMD模块或commonJS模块(由 Nodejs 使用)。ES6 / ES2015 为 JS 带来了一个标准——我们将它们称为ES6 模块,但它们现在是 JS 语言的一部分。一旦有了模块,就可以对私有函数和对象变量进行信息隐藏。请记住,只有您“导出”的内容对客户端调用代码可见。
Lets work through your example code. Here is a first cut:
让我们完成您的示例代码。这是第一次剪辑:
person.js
人物.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
客户端.js
import {Person} from './person';
const manas = new Person('Manas', 'male');
console.log(manas.name); // this calls what was your getName function
Now, the getNameWithInitialfunction is effectively private, as it is not exported, so client.jscannot see it.
现在,getNameWithInitial函数实际上是私有的,因为它没有被导出,所以client.js看不到它。
However, we still have a problem for the Person class, since this is exported. At the moment you can just walk up to manas object and do:
然而,我们仍然有 Person 类的问题,因为它是导出的。目前,您可以走到 manas 对象并执行以下操作:
manas._name = 'Joe'
With properties like _name, we can combine modules and symbols. This is a powerful yet lightweight information hiding technique available with ES6+/ES2015.
使用_name 之类的属性,我们可以组合模块和符号。这是 ES6+/ES2015 提供的一种强大而轻量级的信息隐藏技术。
Symbolis a new built-in type. Every new Symbol value is unique. Hence can be used as a key on an object.
Symbol是一种新的内置类型。每个新的 Symbol 值都是独一无二的。因此可以用作对象上的键。
If the client calling code doesn't know the symbol used to access that key, they can't get hold of it since the symbol is not exported.
如果客户端调用代码不知道用于访问该密钥的符号,则他们无法获得它,因为该符号未导出。
Let's see our modified code to make use of symbols and modules to hide Class attributes.
让我们看看我们修改后的代码,以利用符号和模块来隐藏类属性。
person.js
人物.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);
}
}
So, now a client cannot just do:
所以,现在客户不能只做:
manas._name = 'Joe'
because _nameis not being used as the key for the name value.
因为_name没有被用作 name 值的键。
However, symbols are exposed via reflection features such as Object.getOwnPropertySymbols so be aware they are not "completely' private using this technique.
但是,符号是通过反射功能(例如 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';
Takeaway message - Modules in general are a great way to hide something because if not exported then not available for use outside the module, and used with privately stored Symbols to act as the keys, then class attributes too can become hidden (but not strictly private). Using modules today is available with build tools eg. webpack / browserify and babel.
外卖信息 - 模块通常是隐藏某些东西的好方法,因为如果不导出,则不能在模块外部使用,并且与私有存储的 Symbols 一起用作键,然后类属性也可以隐藏(但不是严格私有的) )。今天使用模块可以与构建工具一起使用,例如。webpack/browserify 和 babel。
回答by Norguard
If you would like an analogue to the ES5 solution, it's quite simple; the constructor
simply becomes what holds the closure, and you add any methods/objects which should remember the private state in there.
Prototyped methods have no access to the closure of the initial constructor, without using some privileged getters:
如果你想要一个类似于 ES5 的解决方案,它很简单;在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();
}
}
If you look at what this nets you, you'll note that it's really not much different than your example (just using "cleaner" bells and whistles; especially when adding prototype/static methods). It's still prototype underneath.
如果你看看这给你带来了什么,你会注意到它与你的例子没有太大不同(只是使用“更干净”的花里胡哨;特别是在添加原型/静态方法时)。它仍然是下面的原型。
If you have the luxury of using any kind of module/export (ES6 being the ideal), then with one other data-type, you can have true privacy and not have to clean up after yourself.
如果您有幸使用任何类型的模块/导出(ES6 是理想的),那么使用另一种数据类型,您就可以拥有真正的隐私,而不必自己清理。
It's a little hackey-looking. It'll probably get less ugly, and hopefully be the basis for something cleaner, in the future, but if you want instance-based, private access, even for prototyped methods, then make one WeakMap
, inside of the module that you're exporting your class from.
它看起来有点像黑客。它可能会变得不那么难看,并希望成为未来更清晰的东西的基础,但是如果你想要基于实例的私有访问,即使是原型方法,然后在你要导出的模块内部创建一个WeakMap
你的课从。
Use this
as your key.
Rather than making privileged functions which have closure access, now all prototype methods have closure access to the weakmap...
...the downside being that any time you want private variables, you have to look them up in the WeakMap
rather than pulling them off of / out of this
.
使用this
为您的钥匙。而不是让它们具有封闭的访问特权功能,现在所有的原型方法必须在weakmap封闭接入...
...的缺点是,你需要私有变量任何时候,你要看看他们的WeakMap
,而不是拉动它们关闭出/出this
。
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;
As long as you aren't losing the reference inside of this
, this should just work.
Unlike using Symbol
, you can't get a reference to the private object, no matter how hard you try.
If you know the symbols on the object, you can look up the properties using the symbols.
And getting the list of symbols on any object is just a function call away.
Symbol
isn't about keeping things private; it's about keeping things safe from naming collisions, and defining common symbols that can be used on any object/function, but won't be picked up in loops, won't be called or overwritten accidentally, et cetera.
只要您没有丢失 内部的引用this
,这应该可以正常工作。
与 using 不同Symbol
,无论您多么努力,都无法获得对私有对象的引用。
如果您知道对象上的符号,则可以使用符号查找属性。
获取任何对象上的符号列表只是一个函数调用。
Symbol
不是要保密;它是关于保护事物免受命名冲突的影响,并定义可用于任何对象/函数的通用符号,但不会在循环中被拾取,不会被意外调用或覆盖,等等。
Storing the private bag of data in a weakmap with this
as a key gives you access to a completely hidden dataset, which is totally unaccessible outside of that module.
What's better, the key/value in weakmaps don't prevent the GC from cleaning them up.
Normally, if they were left in an array, they'd stay there. If the last place an object is used is as a key in a weakmap, then it gets collected and the weakmap value is erased automatically (in native ES6; the memory bonuses can't be polyfilled, but the object can).
将私有数据包存储在weakmap 中,this
作为键,您可以访问完全隐藏的数据集,该数据集在该模块之外是完全无法访问的。
更好的是,弱图中的键/值不会阻止 GC 清理它们。
通常,如果将它们留在阵列中,它们会留在那里。如果对象的最后一个位置是作为弱映射中的键,那么它会被收集并自动擦除弱映射值(在原生 ES6 中;内存奖励不能被 polyfill,但对象可以)。
回答by andre mcgruder
here is a really good post on the subject. I didn't know much about doing this in ES6 before your question but after reviewing this it looks really cool. So you create a symbol that is indexed to the function.
这是一个关于这个主题的非常好的帖子。在您提出问题之前,我对在 ES6 中执行此操作知之甚少,但在查看此内容后,它看起来非常酷。因此,您创建了一个索引到该函数的符号。
here is the code straight from their sit.
这是直接来自他们的代码。
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');
回答by jdlm
You may accomplish it using Symbol
.
您可以使用Symbol
.
const _name = Symbol();
class Person {
constructor(name) {
this[_name] = name;
}
}
const person = new Person('John');
alert(person.name);
// => undefined