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

时间:2015-12-22 14:23:56

标签: 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 method
    this.init = function(){

    }
}

但是在ES6中,你不能再在构造函数之外声明变量了,这使得它实际上更难以以OOP方式使用类!

您可以使用此方法在构造函数中声明变量,但这会使它们默认公开。这非常奇怪,因为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;
    }
}

4 个答案:

答案 0 :(得分:6)

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

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

获取 set 关键字为ES5自定义getter和setter的简化定义提供了一种方法,这些getter和setter之前使用Object.defineProperty()

您可以做的最好的事情就是将这些技巧与SymbolsWeakMaps

一起使用

以下示例介绍如何使用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的文章。

答案 1 :(得分:3)

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

否则,没有好的方法允许原型方法访问私有数据,但仍然可以从外部隐藏它。您可以尝试符号,弱图或握手,但IMO没有一个是完美的。有关一些想法,请参阅accessing private member variables from prototype-defined functions

答案 2 :(得分:3)

  

但是在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
    }
}

答案 3 :(得分:2)

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

通过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)的一部分时,类声明特别适合。