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

Gle*_*ift 134 javascript class ecmascript-5 ecmascript-6 traceur

我现在使用Traceur Compiler来获得ES6功能.

我想从ES5实现这些东西:

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

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

    this.hi = function() {/* ... */}
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

class Animal {
...
Run Code Online (Sandbox Code Playgroud)

没有什么比通过预期的更好,this没有apply-ing或bind-ing它每次都不能将正确的方法传递给私有方法.

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

ale*_*ods 212

有没有private,public或者protected在现有的关键字的ECMAScript 6规范.

所以Traceur不支持privatepublic.6to5(目前它被称为"Babel")实现了这个提议用于实验目的(另见本讨论).但毕竟这只是提案.

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

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

class Animal {

    _sayHi() {
        // do stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,许多语言的字段隐私*是*伪隐私.使用Java - 您始终可以使用反射获取对象的"私有"字段的值.在这个意义上的隐私实际上只是一种设计模式 - 它为消费者提供了一个易于理解的工具/编译器可强制执行的接口,不应该调用哪些方法.使用下划线的前置方法是这种接口的完美合理的实现,即使它只是一个约定而不是语言规范. (70认同)
  • @CarlosAraya那是在ES6之前写的.他基本上说"不要使用通用约定来编写类,因为类不是JS中的东西." 除了现在它们是一个东西,所以使用它们的约定现在是有道理的. (38认同)
  • "不要使用_ _underbar_作为名字的第一个或最后一个字符.它有时用于表示隐私,但它实际上并不提供隐私.如果隐私很重要,请使用关闭.避免使用缺乏能力的惯例." [JavaScript编程语言的代码约定](http://javascript.crockford.com/code.html) - **Douglas Crockford** (15认同)
  • 对于任何类型的函数迭代都不太好,特别是如果人们选择不同的方式来标记哪些函数是私有的.`_id`,`id_`,`p_id`,`privateId`,`s_id` ....函数的迭代示例,`Promise.promisifyAll(SomeClass.prototype)`. (3认同)
  • 这是每个人都讨厌的匈牙利表示法吗? (2认同)

Max*_*Max 70

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

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

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

new MyClass(); // 'My property: myProp'
Run Code Online (Sandbox Code Playgroud)

  • Lambdas*不会*自​​动绑定`this`.因为他们根本没有"这个"(即你不能绑定一个lambda).资料来源:http://blog.getify.com/arrow-this/ (7认同)
  • 您的第二个代码示例不支持多个实例; 只有一个`myPrivateFunction`实例. (5认同)
  • 不工作的例子.虽然可以用于'myPrivateFunction.call(this)' (3认同)

Mar*_*oni 53

虽然目前无法将方法或属性声明为私有,但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; 
Run Code Online (Sandbox Code Playgroud)

在另一个文件中

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
Run Code Online (Sandbox Code Playgroud)

  • 如果你想在私有方法中使用类上下文```(this)```,你应该在类中使用```tryMe1(1).bind(this)```.但如果您使用箭头功能,这将失败. (4认同)

Max*_*mus 22

你可以使用Symbol

var say = Symbol()

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

Cat.prototype[say] = function(){ alert('im a private') }
Run Code Online (Sandbox Code Playgroud)

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

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

在ES6中:

var say = Symbol()

class Cat {

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

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

}
Run Code Online (Sandbox Code Playgroud)

  • @novaline私有变量不是黑客的保护,而是防止用子类意外覆盖属性. (5认同)

Son*_*gHo 14

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

I.声明vars,IIFE内部的函数(立即调用函数表达式),这些函数只能在匿名函数中使用.(当您需要更改ES6的代码时,不使用'var'就可以使用"let,const"关键字.)

let Name = (function() {
  const _privateHello = function() {
  }
  class Name {
    constructor() {
    }
    publicMethod() {
      _privateHello()
    }
  }
  return Name;
})();
Run Code Online (Sandbox Code Playgroud)

II.WeakMap对象可以很好地解决内存漏洞问题.

将删除实例时,将删除WeakMap中的存储变量.看看这篇文章.(管理ES6类的私有数据)

let Name = (function() {
  const _privateName = new WeakMap();
})();
Run Code Online (Sandbox Code Playgroud)

III.让我们把所有的东西放在一起.

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"
Run Code Online (Sandbox Code Playgroud)

  • 关于该解决方案工作原理的一些细节会有所帮助.只提供可能正确的代码并不能真正回答问题.我建议编辑您的答案,以包含有关该解决方案工作原理的更多详细信息,并解释您建议的代码. (2认同)

jam*_*sso 9

正如alexpods所说,在ES6中没有专门的方法来做到这一点.但是,对于那些感兴趣的人,还有一个绑定运算符的提议,它启用了这种语法:

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

export class Animal {
  constructor(name) {
    this.name = name;
  }
  publicMethod() {
    this::privateMethod();
  }
}
Run Code Online (Sandbox Code Playgroud)

再一次,这只是一个提案.你的旅费可能会改变.


Nic*_*tti 6

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

function car () {

    var privateVariable = 4

    function privateFunction () {}

    return {

        color: 'red',

        drive: function (miles) {},

        stop: function() {}

        ....

    }

}
Run Code Online (Sandbox Code Playgroud)

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

  • 使用工厂函数是使用便于创建私有/公共方法的类的有效替代方法.如果未来的读者没有找到令人满意的课程的解决方案,我认为他们知道他们有一个解决问题的替代方案将是有价值的. (5认同)
  • 对我来说,这是最糟糕的解决方案。您不是在这里创建实际的 ES6 类,只是返回一个 POJO。另外,每次调用工厂时都会创建私有闭包,从而导致更高的内存占用和更慢的性能。 (3认同)
  • 重点是避免创建一个类。事实上,许多 js 开发人员认为在 JavaScript 中创建类是一种反模式;由于语言的本质以及关键字“this”在 js 中引入的风险。就性能而言,除非您一次创建成千上万个这样的对象,否则它并不重要。在这种情况下,即使使用类,您也可能会遇到性能问题。 (2认同)

kof*_*fus 5

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

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

  • 私有变量和方法是真正私有的,并且具有正确的“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"]
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdn.rawgit.com/kofifus/New/7987670c/new.js"></script>
Run Code Online (Sandbox Code Playgroud)

请参阅代码和更详细的示例,包括构造函数和组合