如何在 ES6 中使用私有变量? [复制]
Posted
技术标签:
【中文标题】如何在 ES6 中使用私有变量? [复制]【英文标题】:How to work with private variables in ES6? [duplicate] 【发布时间】:2016-03-28 20:17:49 【问题描述】:在 ES5 中,您可以模拟具有私有和公共变量的类,如下所示:
car.js
function Car()
// using var causes speed to be only available inside Car (private)
var speed = 10;
// public variable - still accessible outside Car
this.model = "Batmobile";
// public method
this.init = function()
但是在 ES6 中,您不能再在构造函数之外声明 var,这实际上使得以 OOP 方式处理类变得更加困难!?
您可以使用 this 在构造函数中声明变量,但默认情况下会公开它们。这很奇怪,因为 ES6 DOES 有一个 get / set 关键字!
class Vehicle
constructor(make, year)
// the underscore is nice, but these are still public!
this._make = make;
this._year = year;
// get and set can be handy, but would make more sense
// if _make and _year were not accessible any other way!
get make()
return this._make;
get year()
return this._year;
【问题讨论】:
this._make = make;
与this.model = "Batmobile";
的效果相同,你必须使用完全不同的技巧来定义私有变量,更多信息请参见What? Wait. Really? Oh no! (a post about ES6 classes and privacy)。
是的,但是 ES5 示例中的速度是私有的。如何在 ES6 中实现这一点?感谢您的链接!似乎 ES6 类在我们认为它们是真正的 OOP 类之前还有很长的路要走。
【参考方案1】:
ES6 标准没有提供定义私有变量的新方法。
事实上,新的 ES6 class 只是围绕常规基于原型的构造函数的语法糖。
get 和 set 关键字提供了一种简化 ES5 自定义 getter 和 setter 定义的方法,这些自定义 getter 和 setter 以前使用 Object.defineProperty() 描述符定义
你能做的最好的就是将这些技术与Symbols 或WeakMaps 一起使用
下面的例子展示了使用 WeakMap 来存储私有属性。
// myModule.js
const first_name = new WeakMap();
class myClass
constructor (firstName)
first_name.set(this, firstName);
get name()
return first_name.get(this);
export default myClass;
我指的是由 David Vujic What? Wait. Really? Oh no! (a post about ES6 classes and privacy) 撰写的文章,其想法是使用 WeakMaps。
【讨论】:
我想这可以工作,但我不确定这是否比 ES5 方式好得多。虽然我希望 ES6 能简化问题,但它似乎更令人费解。 @Kokodoko 这取决于你做什么,新标准提供了许多其他不错的功能,但不幸的是真正的 OOP 类不是其中之一。现在使用 ES6 模块,数据封装变得更加容易,javascript 肯定在朝着正确的方向发展。 是的,模块很好!看起来很奇怪,ES6 实际上删除了将 var 设为私有的简单技巧! (在我的第一个示例中,var speed=10)。换句话说,它们让封装的使用变得更难,而不是更容易。 @Kokodoko 实际上旧的 ES5 技巧仍然存在,我认为你理解错了。您可以在构造函数中定义变量,但丑陋的部分是您还必须在那里定义自定义 getter/setter,从而增加内存中实例的总指纹。请参阅Fiddle 是的,但就像我说的,现在你的构造函数中有函数和变量初始化。它有效,但我认为它违背了让类具有构造函数方法的想法。在其他语言中,构造函数只是一个在创建新实例时执行的函数。你甚至可以省略构造函数!在我看来,这个 ES5 示例更清晰:jsfiddle.net/35f9q7p6/2【参考方案2】:2016 年 1 月更新 - 虽然我发现接受的答案中给出的方法是正确的,但我想说在 ES2015+ 中使用模块和符号是一种有效的信息隐藏技术(但 Class使用符号的属性将被隐藏,而不是严格私有的)。
通过结合使用 ES2015 模块(只会导出您声明为导出的内容)和 ES2015 symbols,可以实现有效的轻量级信息隐藏。 Symbol 是一种新的内置类型。每个新的符号值都是唯一的。因此可以用作对象的键。
如果客户端调用代码不知道用于访问该密钥的符号,他们就无法获取它,因为该符号没有被导出。
使用您的代码的快速示例:
vehicle.js
const s_make = Symbol();
const s_year = Symbol();
export class Vehicle
constructor(make, year)
this[s_make] = make;
this[s_year] = year;
get make()
return this[s_make];
get year()
return this[s_year];
并使用模块vehicle.js
client.js
import Vehicle from './vehicle';
const vehicle1 = new Vehicle('Ford', 2015);
console.log(vehicle1.make); //Ford
console.log(vehicle1.year); // 2015
然而,符号虽然是独一无二的,但实际上并不是私有的,因为它们是通过 Object.getOwnPropertySymbols 等反射功能暴露出来的...
const vals = Object.getOwnPropertySymbols(vehicle1);
vehicle1[vals[0]] = 'Volkswagon';
vehicle1[vals[1]] = 2013;
console.log(vehicle1.make); // Volkswagon
console.log(vehicle1.year); // 2013
外卖消息 - 模块通常是隐藏某些内容的好方法,因为如果不导出,则无法在模块外部使用,并且与私有存储的符号一起用作键,然后类属性也可以隐藏(但是不一定是私人的)。类声明特别适合作为构造良好的模块(amd、commonjs 或 es6/2015)的一部分。
【讨论】:
Object.getOwnPropertySymbols(obj)
返回对象中使用的符号列表(就像Object.keys(obj)
一样)。那时,只需遍历列表即可。 Symbol
与保证完美隐私无关,更多的是保证每个引用都是唯一的,除非故意这样做,同时还要让它们远离循环和其他构造(同样,除非有意)。
@Norguard - 非常感谢您指出这一点。更新了我的答案 - 我坐在栅栏上,原始答案中的“信息隐藏”。 Babel 文档也说明了您提出的观点 - babeljs.io/docs/learn-es2015
感谢您对符号的非常清晰的解释!它与私有并不完全相同,但它肯定可以起到防止意外访问变量的目的。【参考方案3】:
但是在 ES6 中,你不能再在构造函数之外声明 vars
而且你不需要。您也没有在 ES5 构造函数中执行此操作。您可以将您的代码逐字翻译为
class Car
constructor()
// local variable
var speed = 10;
// public property
this.model = "Batmobile";
// public method
this.init = () =>
…
; // using an arrow function here simplifies things
【讨论】:
嗯,但是现在您在构造函数中定义了所有方法,与其他 OOP 语言相比,这似乎很奇怪。在构造函数之外,您无法以这种方式访问速度! @Kokodoko:当然,当您需要私有变量时,您会这样做。它与 ES5 中的完全相同。如果要使用原型(实际上性能差异可以忽略不计),则必须使用公共属性。 @Kokodoko: "但是现在你在构造函数内部定义了所有方法"这正是你在第一个示例 (ES5) 中所做的。 是的,但该示例并未包含在另一个函数中。这样,您似乎在滥用类构造函数来定义整个类。构造函数不应该是这样工作的,至少在任何其他 OOP 语言中都不应该这样。 @Kokodoko:“构造函数不应该这样工作”我同意。但是由于您已经在 ES5 中“违反”了该“规则”,因此您不妨在 ES6 中这样做。或者不做也不要试图让 JS 做它不支持的事情。【参考方案4】:与 ES5 中的方法相同:在构造函数而不是原型中定义必须访问私有变量的方法,从而使它们成为特权方法。
否则就没有好的方法允许原型方法访问私有数据,但仍将其隐藏在外部。您可以尝试符号、弱图或握手,但 IMO 没有一个是完美的。请参阅accessing private member variables from prototype-defined functions 了解一些想法。
【讨论】:
我想这意味着仍然无法像在其他 OOP 语言中那样在 ES6 中编写类,学习起来有点令人失望......以上是关于如何在 ES6 中使用私有变量? [复制]的主要内容,如果未能解决你的问题,请参考以下文章