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

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

我想实现 ES5中的这些东西:

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


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


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

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

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

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


class Animal {
...

总比什么都没有好,但是正如预期的那样,如果每次没有 apply-ing 或 bind-ing,就不能将正确的 this传递给私有方法。

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

255575 次浏览

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

所以 Traceur 不支持 privatepublic。6to5(目前称为“ Babel”)实现 这个提议用于实验目的(也参见 这个讨论)。但这毕竟只是求婚。

所以现在您只需要通过 WeakMap模拟私有属性(参见 给你)。另一个选择是 Symbol-但它不提供实际的隐私,因为属性可以很容易地通过 Object.getOwnPropertySymbols访问。

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

class Animal {


_sayHi() {
// do stuff
}
}

你可以随时使用普通函数:

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


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


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

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

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


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

再说一次,这只是一个建议。你的情况可能会有所不同。

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

可以使用“符号”

var say = Symbol()


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


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

附注: Alexpods 是不对的,他得到的是保护而不是私人财产,因为继承是一种名称冲突

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

ES6:

var say = Symbol()


class Cat {


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


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


}

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

生活(立即调用函数表达式)中声明 vars、函数,这些函数只能在匿名函数中使用。(当您需要更改 ES6的代码时,使用“ let,const”关键字而不使用“ var”会比较好。)

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

WeakMap 对象有助于解决内存泄漏问题。

当实例被删除时,WeakMap 中存储的变量将被删除

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"

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

  • 不需要“ this. _”、“ that/self”、弱映射、符号等

  • 私有变量和方法实际上是私有的,并且具有正确的“ 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>

see New for the code and more elaborate examples including constructor and composition

Marcelo Lazaroni已经说过了,

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

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

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


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

你选择哪种方式实际上取决于你的个人偏好。

你有没有考虑过使用工厂函数? 它们通常是 Javascript 中的 更好地替代类或构造函数。 这里有一个例子来说明它是如何工作的:

function car () {


var privateVariable = 4


function privateFunction () {}


return {


color: 'red',


drive: function (miles) {},


stop: function() {}


....


}


}

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