Как реализовать частный метод в классе ES6 с помощью Traceur

Я использую Traceur Compiler, чтобы иметь преимущество с функциями ES6.

Я хочу реализовать этот материал с ES5:

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

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

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

В настоящее время traceur не поддерживает private и public ключевые слова (из гармонии). И синтаксис класса ES6 не позволяет использовать простые выражения var (или let) в классе тела.

Единственный способ, которым я нахожу, - имитировать приватов перед объявлением класса. Что-то вроде:

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

class Animal {
...

Лучше тогда ничего, но, как и ожидалось, вы не можете передать правильный this приватный метод без apply -ing или bind -в его каждый раз.

Итак, есть ли возможность использовать частные данные в классе ES6, совместимом с компилятором traceur?

Ответ 1

В текущей спецификации ECMAScript 6 нет private, public или protected.

Итак, Traceur не поддерживает private и public. 6to5 (в настоящее время он называется "Babel" ) реализует это предложение для экспериментальной цели (см. Также эту дискуссию). Но это просто предложение, в конце концов.

Итак, теперь вы можете просто имитировать частные свойства через WeakMap (см. здесь). Другой альтернативой является Symbol - но это не подразумевает никакой конфиденциальности, поскольку свойство легко можно получить через Object.getOwnPropertySymbols.

ИМХО лучшее решение в это время - просто используйте псевдо-конфиденциальность. Если вы часто используете apply или call с помощью своего метода, этот метод очень специфичен для объекта. Поэтому стоит объявить его в своем классе только с префиксом подчеркивания:

class Animal {

    _sayHi() {
        // do stuff
    }
}

Ответ 2

Вы всегда можете использовать обычные функции:

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

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

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

Ответ 3

Хотя в настоящее время нет способа объявить метод или свойство как частные, модули 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

Ответ 4

Вы можете использовать Symbol

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()) вместо Symbol

В ES6:

var say = Symbol()

class Cat {

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

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

}

Ответ 5

Как сообщает alexpods, в ES6 нет специального способа сделать это. Однако для желающих есть предложение для оператора который позволяет использовать этот вид синтаксиса:

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

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

Еще раз, это всего лишь предложение. Ваш пробег может отличаться.

Ответ 6

Надеюсь, это может быть полезно.:)

я. Объявление vars, функции внутри IIFE (выражение с мгновенным вызовом функции), они могут использоваться только в анонимной функции. (Можно использовать слова "let, const" без использования "var", когда вам нужно изменить код для ES6.)

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

II. Объект WeakMap может быть полезен для проблем с памятью.

Сохраненные переменные в WeakMap будут удалены, когда экземпляр будет удален. Проверьте эту статью. (Управление частными данными классов ES6)

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

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"

Ответ 7

Я придумал то, что я чувствую, это гораздо лучшее решение, позволяющее:

  • не нужно "this._", это/я, слабые карты, символы и т.д. Четкий и простой код класса

  • частные переменные и методы действительно конфиденциальны и имеют правильную привязку '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>

Ответ 8

Считаете ли вы использование функций factory? Обычно они являются гораздо лучшей альтернативой классам или функциям конструктора в Javascript. Вот пример того, как он работает:

function car () {

    var privateVariable = 4

    function privateFunction () {}

    return {

        color: 'red',

        drive: function (miles) {},

        stop: function() {}

        ....

    }

}

Благодаря закрытию вы получаете доступ ко всем частным функциям и переменным внутри возвращаемого объекта, но вы не можете получить к ним доступ извне.

Ответ 9

Как Марсело Лазарони уже сказал,

Хотя в настоящее время нет способа объявить метод или свойство частным, модули ES6 не входят в глобальное пространство имен. Таким образом, все, что вы заявляете в своем модуле и не экспортируете, не будет доступно ни для какой другой части вашей программы, но все равно будет доступно вашему модулю во время выполнения.

Но в его примере не показано, как частный метод может обращаться к членам экземпляра класса. Max показывает нам некоторые хорошие примеры того, как члены экземпляра доступа через привязку или альтернативу использования лямбда-метода в конструкторе, но я хотел бы добавить еще один простой способ сделать это: передать экземпляр в качестве параметра для частного метода. Выполнение этого способа привело бы Max MyClass выглядеть следующим образом:

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

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

Каким образом вы это делаете, это действительно сводится к личным предпочтениям.