如何使用Traceur在ES6类中实现私有方法[重复]

问题描述 投票:0回答:9

我现在使用 Traceur Compiler 来利用 ES6 功能。

我想从 ES5 实现这些东西:

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

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

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

目前 Traceur 不支持

private
public
关键字(来自 Harmony)。 ES6 类语法不允许在类主体中使用简单的
var
(或
let
)语句。

我发现的唯一方法是在类声明之前模拟私有。比如:

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

class Animal {
...

总比什么都不做要好,但正如预期的那样,如果每次都没有

this
-ing 或
apply
-ing ,则无法将正确的
bind
传递给私有方法。

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

javascript class ecmascript-5 ecmascript-6 traceur
9个回答
243
投票

当前

ECMAScript 6 规范
中没有
private
public
protected 关键字。

所以 Traceur 不支持

private
public
。 6to5(目前称为“Babel”)出于实验目的实现了此提案(另请参阅此讨论)。但这毕竟只是提议。

所以现在你可以通过

WeakMap
模拟私有属性(参见here)。另一种选择是
Symbol
- 但它不提供实际的隐私,因为可以通过
Object.getOwnPropertySymbols
轻松访问该财产。

恕我直言,目前最好的解决方案是使用伪隐私。如果您经常在您的方法中使用

apply
call
,那么此方法是非常特定于对象的。因此,值得在您的类中使用下划线前缀来声明它:

class Animal {

    _sayHi() {
        // do stuff
    }
}

90
投票

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

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

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

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

63
投票

虽然目前无法将方法或属性声明为私有,但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

24
投票

您可以使用符号

var say = Symbol()

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

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

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

其实你可以用

var say = String(Math.random())
代替 Symbol

在 ES6 中:

var say = Symbol()

class Cat {

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

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

}

20
投票

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

我。在IIFE(立即调用函数表达式)中声明变量、函数,这些只能在匿名函数中使用。 (当您需要更改 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"

13
投票

您考虑过使用工厂函数吗? 它们通常是 Javascript 中类或构造函数的更好的替代品。 以下是其工作原理的示例:

function car () { var privateVariable = 4 function privateFunction () {} return { color: 'red', drive: function (miles) {}, stop: function() {} .... } }

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


11
投票
正如 alexpods 所说,ES6 中没有专门的方法来做到这一点。然而,对于那些感兴趣的人来说,还有一个关于

bind 运算符 的建议,它支持这种语法:

function privateMethod() { return `Hello ${this.name}`; } export class Animal { constructor(name) { this.name = name; } publicMethod() { this::privateMethod(); } }

再次强调,这只是一个建议。您的里程可能会有所不同。


4
投票
正如

Marcelo Lazaroni 已经说过的那样,

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

但是他的示例没有显示私有方法如何访问类实例的成员。

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

function myPrivateFunction(myClass) { console.log("My property: " + myClass.prop); } class MyClass() { constructor() { this.prop = "myProp"; } testMethod() { myPrivateFunction(this); } } module.exports = MyClass;

具体采用哪种方式取决于个人喜好。


4
投票
很难理解为什么 ES6 给了我们蹩脚的类语法,而我们可以在普通 JS 中做得更好:

  • 不需要“this._”、that/self、weakmaps、符号等。清晰直接的“类”代码

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

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

  • 公共接口清晰且与实现分离

function Counter(seed=0) { // define public interface const self = Object.assign(this, { advance, // advance counter and get new value reset, // reset value value // get value }) // init private state // any parameters passed to the function itself are also part of it's private state let count=seed; // call constructor if needed constructor() //logic (private & public methods) function constructor() { console.log('new Counter') } function advance() { return ++count } function reset(newCount) { count=(newCount || 0) } function value() { return count } return self } let counter=new Counter() console.log(counter instanceof Counter) // true counter.reset(100) console.log('Counter next = '+counter.advance()) // 101

© www.soinside.com 2019 - 2024. All rights reserved.