Javascript 如何在ES6中使用私有变量?

Javascript 如何在ES6中使用私有变量?,javascript,class,oop,ecmascript-6,Javascript,Class,Oop,Ecmascript 6,在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 meth

在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(){

    }
}
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];
  }
}
import {Vehicle} from './vehicle';
const vehicle1 = new Vehicle('Ford', 2015);
console.log(vehicle1.make); //Ford
console.log(vehicle1.year); // 2015
但是在ES6中,您不能再在构造函数之外声明变量,这实际上使得以面向对象的方式处理类更加困难

您可以使用此方法在构造函数中声明变量,但默认情况下,这会使它们公开。这很奇怪,因为ES6确实有一个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;
    }
}

与ES5中的方法相同:定义必须访问构造函数(而不是原型)中私有变量的方法,从而使它们成为特权方法

否则,就没有好办法允许原型方法访问私有数据,但仍然对外部隐藏它。你可以尝试符号、手势或握手,但在我看来,没有一种是完美的。请参阅以获取一些想法

但是在ES6中,您不能再在构造函数之外声明变量

你不需要这么做。您也没有在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
    }
}

ES6标准并没有提供定义私有变量的新方法

事实上,新的ES6类只是围绕常规的基于原型的构造函数的语法糖

get和set关键字提供了一种简化ES5自定义getter和setter定义的方法,这些getter和setter以前是用

你所能做的最好的事情就是将这些技术用于或

下面的示例以使用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写的一篇文章,文章中提出了使用weakmap的想法。

2016年1月更新-虽然我发现公认答案中给出的方法是正确的,但我想声明,在ES2015+中,使用模块和符号是一种有效的信息隐藏技术(但使用符号的类属性将被隐藏,而不是严格私有的)

通过ES2015模块(仅导出您声明为导出的内容)和ES2015的组合,可以实现有效、轻量级的信息隐藏。符号是一种新的内置类型。每个新符号值都是唯一的。因此可以用作对象上的键

如果客户端调用代码不知道用于访问该密钥的符号,则无法获取该符号,因为该符号未导出

使用您的代码的快速示例:

vehicle.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(){

    }
}
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];
  }
}
import {Vehicle} from './vehicle';
const vehicle1 = new Vehicle('Ford', 2015);
console.log(vehicle1.make); //Ford
console.log(vehicle1.year); // 2015
并使用模块vehicle.js

client.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(){

    }
}
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];
  }
}
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

Takeaway message-模块通常是隐藏某些内容的好方法,因为如果不导出,则无法在模块外部使用,并且与私有存储的符号一起用作键,则类属性也可以隐藏(但不一定是私有的).类声明在被认为是构造良好的模块(amd、commonjs或es6/2015)的一部分时特别适合。

这一点。_make=make;
的效果与
这一点相同。model=“Batmobile”你必须使用完全不同的技巧来定义一个私有变量,请参阅更多。是的,但是ES5示例中的速度是私有的。如何在ES6中实现这一点?谢谢链接!在我们考虑真正的OOP类之前,ES6类仍然有很长的路要走。HM,但是现在你在CONS中定义了所有的方法。tructor,这与其他OOP语言相比似乎非常奇怪。在构造函数之外,你不能以这种方式访问速度!@Kokodoko:当然,当你需要私有变量时,你就是这么做的。这与ES5中完全相同。如果你想使用原型(性能差异实际上可以忽略不计),您必须使用公共属性。@Kokodoko:“但现在您在构造函数中定义了所有方法”,这正是您在第一个示例(ES5)中所做的还有。是的,但这个例子并没有包含在另一个函数中。这样看来,你似乎在滥用类构造函数来定义整个类。这不是构造函数应该如何工作,至少在任何其他OOP语言中都不是。@Kokodoko:“这不是构造函数应该如何工作”我同意。但既然你已经这样做了“违反”那条规则"在ES5中,你也可以在ES6中这样做。或者不要这样做,也不要试图让JS做一些它不支持的事情。我想这意味着仍然不可能像在其他OOP语言中那样在ES6中编写类,这有点令人失望……我想这可能行得通,但我不确定这是否比使用其他OOP语言更好ES5的一种方式。当我希望ES6能够简化事情时,它看起来更复杂。@Kokodoko这取决于你做什么,新标准提供了许多其他好的功能,但不幸的是,真正的OOP类不在其中。使用ES6模块,数据封装变得容易多了,JavaScript肯定朝着正确的方向发展。是的,模块很好!ES6实际上删除了使var私有化的简单技巧,这看起来很奇怪!(在我的第一个示例中,var speed=10)。换句话说,它们使使用封装变得更难,而不是更容易。@Kokodoko实际上旧的ES5技巧仍然存在,我想你弄错了。你可以在构造函数内部定义变量,但难看的是,你还必须在那里定义一个自定义的getter/setter,从而增加m中实例的总指纹emory。请看是的,但就像我说的,现在你的构造函数中有了函数和变量初始化。这是可行的,但我认为这违背了用构造函数方法创建类的想法。在其他语言中,构造函数只是创建新实例时执行的函数。你甚至可以省略构造函数uctor!在我看来,这个ES5示例更清晰:
Obj