155

我现在使用 Traceur Compiler 来获得 ES6 特性的优势。

我想从 ES5 实现这些东西:

function Animal() {
    var self = this,
        sayHi;

    sayHi  = function() {
        self.hi();
    };

    this.hi = function() {/* ... */}
}

目前 traceur 不支持privatepublic关键字(来自和声)。并且 ES6 类语法不允许在类主体中使用简单var(或let)语句。

我找到的唯一方法是在类声明之前模拟私有。就像是:

var sayHi = function() {
    // ... do stuff
};

class Animal {
...

总比没有好,但正如预期的那样,如果每次都没有-ing 或-ing就无法将正确的方法传递this给私有方法。applybind

那么,是否有可能在与 traceur 编译器兼容的 ES6 类中使用私有数据?

4

9 回答 9

241

当前的ECMAScript 6 规范private中没有publicprotected关键字。

所以 Traceur 不支持privateand public。6to5(目前称为“Babel”)出于实验目的实现了此提议(另请参阅此讨论)。但毕竟这只是提议。

所以现在你可以通过WeakMap(见这里)模拟私有属性。另一种选择是Symbol- 但它不提供实际的隐私,因为可以通过Object.getOwnPropertySymbols.

恕我直言,此时最好的解决方案 - 只需使用伪隐私。如果您经常使用applycall与您的方法一起使用,那么此方法是非常特定于对象的。所以值得在你的类中用下划线前缀声明它:

class Animal {

    _sayHi() {
        // do stuff
    }
}
于 2015-01-09T04:04:51.757 回答
91

您始终可以使用正常功能:

function myPrivateFunction() {
  console.log("My property: " + this.prop);
}

class MyClass() {
  constructor() {
    this.prop = "myProp";
    myPrivateFunction.bind(this)();
  }
}

new MyClass(); // 'My property: myProp'
于 2016-02-20T08:53:32.427 回答
60

尽管目前没有办法将方法或属性声明为私有,但ES6 模块不在全局命名空间中。因此,您在模块中声明且未导出的任何内容都将不可用于程序的任何其他部分,但在运行时仍可用于您的模块。因此,您拥有私有属性和方法:)

这是一个示例(在test.js文件中)

function tryMe1(a) {
  console.log(a + 2);
}

var tryMe2 = 1234;

class myModule {
  tryMe3(a) {
    console.log(a + 100);
  }

  getTryMe1(a) {
    tryMe1(a);
  }

  getTryMe2() {
    return tryMe2;
  }
}

// Exports just myModule class. Not anything outside of it.
export default myModule; 

在另一个文件中

import MyModule from './test';

let bar = new MyModule();

tryMe1(1); // ReferenceError: tryMe1 is not defined
tryMe2; // ReferenceError: tryMe2 is not defined
bar.tryMe1(1); // TypeError: bar.tryMe1 is not a function
bar.tryMe2; // undefined

bar.tryMe3(1); // 101
bar.getTryMe1(1); // 3
bar.getTryMe2(); // 1234
于 2016-04-14T14:38:03.663 回答
24

您可以使用符号

var say = Symbol()

function Cat(){
  this[say]() // call private methos
}

Cat.prototype[say] = function(){ alert('im a private') }

PS alexpods 不正确。他得到保护而不是私有,因为继承是名称冲突

实际上你可以使用var say = String(Math.random())Symbol

在 ES6 中:

var say = Symbol()

class Cat {

  constructor(){
    this[say]() // call private
  }

  [say](){
    alert('im private')
  }

}
于 2016-06-11T04:55:05.663 回答
18

我希望这会有所帮助。:)

I. 在IIFE(Immediately-invoked function expression)中声明 vars、functions ,只能在匿名函数中使用。(当您需要更改 ES6 的代码时,最好使用“let, const”关键字而不使用 'var'。)

let Name = (function() {
  const _privateHello = function() {
  }
  class Name {
    constructor() {
    }
    publicMethod() {
      _privateHello()
    }
  }
  return Name;
})();

二、WeakMap 对象可以很好地解决内存泄漏问题。

当实例被移除时,WeakMap 中存储的变量也会被移除。检查这篇文章。(管理 ES6 类的私有数据

let Name = (function() {
  const _privateName = new WeakMap();
})();

三、让我们把所有东西放在一起。

let Name = (function() {
  const _privateName = new WeakMap();
  const _privateHello = function(fullName) {
    console.log("Hello, " + fullName);
  }

  class Name {
    constructor(firstName, lastName) {
      _privateName.set(this, {firstName: firstName, lastName: lastName});
    }
    static printName(name) {
      let privateName = _privateName.get(name);
      let _fullname = privateName.firstName + " " + privateName.lastName;
      _privateHello(_fullname);
    }
    printName() {
      let privateName = _privateName.get(this);
      let _fullname = privateName.firstName + " " + privateName.lastName;
      _privateHello(_fullname);
    }
  }

  return Name;
})();

var aMan = new Name("JH", "Son");
aMan.printName(); // "Hello, JH Son"
Name.printName(aMan); // "Hello, JH Son"
于 2016-08-13T15:58:54.787 回答
12

您是否考虑过使用工厂功能?它们通常是Javascript中类或构造函数的更好替代方案。这是它如何工作的示例:

function car () {

    var privateVariable = 4

    function privateFunction () {}

    return {

        color: 'red',

        drive: function (miles) {},

        stop: function() {}

        ....

    }

}

由于闭包,您可以访问返回对象内的所有私有函数和变量,但不能从外部访问它们。

于 2016-11-03T20:26:59.570 回答
10

正如 alexpods 所说,在 ES6 中没有专门的方法可以做到这一点。然而,对于那些感兴趣的人,还有一个关于绑定运算符的提议,它支持这种语法:

function privateMethod() {
  return `Hello ${this.name}`;
}

export class Animal {
  constructor(name) {
    this.name = name;
  }
  publicMethod() {
    this::privateMethod();
  }
}

再一次,这只是一个建议。你的旅费可能会改变。

于 2016-02-29T19:14:55.547 回答
5

我想出了一个我认为更好的解决方案,允许:

  • 不需要'this._'、that/self、weakmaps、symbols等。清晰直接的'class'代码

  • 私有变量和方法是真正私有的并且具有正确的“this”绑定

  • 完全不使用“this”,这意味着更不容易出错的清晰代码

  • 公共接口清晰并与实现分离,作为私有方法的代理

  • 允许轻松组合

有了这个你可以做到:

function Counter() {
  // public interface
  const proxy = {
    advance,  // advance counter and get new value
    reset,    // reset value
    value     // get value
  }
	
  // private variables and methods
  let count=0;
    
  function advance() {
    return ++count;
  }
    	
  function reset(newCount) {
    count=(newCount || 0);
  }
    	
  function value() {
    return count;
  }
    
  return proxy;
}
    	
let counter=Counter.New();
console.log(counter instanceof Counter); // true
counter.reset(100);
console.log('Counter next = '+counter.advance()); // 101
console.log(Object.getOwnPropertyNames(counter)); // ["advance", "reset", "value"]
<script src="https://cdn.rawgit.com/kofifus/New/7987670c/new.js"></script>

有关代码,请参见New以及更详细的示例,包括构造函数和组合

于 2016-08-30T08:47:13.877 回答
4

正如马塞洛·拉扎罗尼(Marcelo Lazaroni)已经说过的,

尽管目前无法将方法或属性声明为私有,但 ES6 模块不在全局命名空间中。因此,您在模块中声明且未导出的任何内容都将不可用于程序的任何其他部分,但在运行时仍可用于您的模块。

但他的示例没有显示私有方法如何访问类实例的成员。Max向我们展示了一些很好的示例,说明如何通过绑定或在构造函数中使用 lambda 方法来访问实例成员,但我想添加一种更简单的方法:将实例作为参数传递给私有方法。这样做会导致 Max 的 MyClass 看起来像这样:

function myPrivateFunction(myClass) {
  console.log("My property: " + myClass.prop);
}

class MyClass() {
  constructor() {
    this.prop = "myProp";
  }
  testMethod() {
    myPrivateFunction(this);
  }
}
module.exports = MyClass;

你用哪种方式做这件事真的取决于个人喜好。

于 2016-08-31T14:11:09.923 回答