如何用Traceur在ES6类中实现私有方法

时间:2015-01-08 20:35:56

标签: javascript class ecmascript-5 ecmascript-6 traceur

我现在使用Traceur Compiler来获得ES6功能的优势。

我想从ES5实现这些东西:

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

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

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

目前,traceur不支持privatepublic个关键字(from harmony)。 ES6类语法不允许在类体中使用简单的var(或let)语句。

我找到的唯一方法是在课堂申报前模拟私立课程。类似的东西:

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

class Animal {
...

除了正如预期的那样,如果没有this - 或者apply每次都不能将正确的bind传递给私有方法,那就更好了。

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

8 个答案:

答案 0 :(得分:204)

当前ECMAScript 6 specification中没有privatepublicprotected个关键字。

因此,Traceur不支持privatepublic。 6to5(目前被称为" Babel")实现this proposal用于实验目的(另见this discussion)。毕竟,这只是提案。

所以现在你可以通过WeakMap模拟私有属性(参见here)。另一个替代方案是Symbol - 但它不提供实际隐私,因为可以通过Object.getOwnPropertySymbols轻松访问该属性。

恕我直言,此时最好的解决方案 - 只使用伪隐私。如果您经常在方法中使用applycall,则此方法非常特定于对象。因此,只需使用下划线前缀声明它在您的班级中是值得的:

class Animal {

    _sayHi() {
        // do stuff
    }
}

答案 1 :(得分:65)

您始终可以使用普通功能:

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

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

new MyClass(); // 'My property: myProp'

答案 2 :(得分:52)

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

这是一个例子 (在[20:15:15][Step 2/2] Using ChromeDriver directly... [20:15:15][Step 2/2] [launcher] Running 1 instances of WebDriver [20:15:15][Step 2/2] Started [20:15:15][Step 2/2] ................... [20:15:15][Step 2/2] [20:15:15][Step 2/2] [20:15:15][Step 2/2] 19 specs, 0 failures [20:15:15][Step 2/2] Finished in 0.82 seconds [20:15:15][Step 2/2] [launcher] 0 instance(s) of WebDriver still running [20:15:15][Step 2/2] [launcher] chrome #1 passed 文件中)

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; 

答案 3 :(得分:20)

您可以使用符号

var say = Symbol()

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

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

P.S。 alexpods不正确。他得到保护而非私人,因为继承是名称冲突

实际上,您可以使用var say = String(Math.random())代替符号

在ES6中:

var say = Symbol()

class Cat {

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

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

}

答案 4 :(得分:9)

正如alexpods所说,在ES6中没有专门的方法来做到这一点。但是,对于那些感兴趣的人,还有bind operator的提案,它提供了这种语法:

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

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

再一次,这只是一个提案。您的里程可能会有所不同。

答案 5 :(得分:5)

您是否考虑过使用工厂功能? 它们通常是Javascript中的much better alternative to classes or constructor functions。 以下是其工作原理的示例:

function car () {

    var privateVariable = 4

    function privateFunction () {}

    return {

        color: 'red',

        drive: function (miles) {},

        stop: function() {}

        ....

    }

}

感谢闭包,您可以访问返回对象内的所有私有函数和变量,但是您无法从外部访问它们。

答案 6 :(得分: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;

你这样做的方式实际上取决于个人偏好。

答案 7 :(得分:2)

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

  • 不需要'这个。',那个/自我,弱图,符号等。清晰明了的课程'代码

  • 私有变量和方法非常私密,并且具有正确的'这个'结合

  • 不使用'这个'所有这意味着明确的代码不易出错

  • 公共接口是明确的,并且与实现分离,作为私有方法的代理

  • 允许轻松合成

你可以这样做:



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>
&#13;
&#13;
&#13;

请参阅New以获取代码和更精细的示例,包括构造函数和组合