Возникли проблемы с созданием статических полей (не методов, примитивов) в классе ES6?

Я хотел бы создать класс BankAccount, в котором новый экземпляр отслеживает проверку и сохранение нового экземпляра. Однако всякий раз, когда кто-то создает новый экземпляр, мне нужен статический метод, который вызывает статическое поле, привязанное исключительно к классу BankAccount, где он отслеживает, сколько банковских счетов открыто (что-то вроде поведения синглтона). Это выполнимо в С#/java, но с трудом воссоздает предполагаемое поведение в Javascript.

Я пытался сделать это и в ES5, но потерпел неудачу, самое близкое к тому поведению, которое я искал, используя функцию в качестве оболочки для инкапсуляции:

function BankAccountMaker() {
    var countOfAccounts = 0;
    function IncrementcountOfAccounts() {
        countOfAccounts += 1;
    }

    function BankAccount(c = 0) {
        this.checking = 0;
    }

    return {
        makeBankAccount: function (c) {
            IncrementcountOfAccounts();
            console.log(countOfAccounts)
            return new BankAccount(c);
        }
    }
}

В конце концов, некоторые спрашивают:

  1. Может ли кто-нибудь написать код, эквивалентный ES6 вышеизложенному?
  2. Кроме того, есть ли лучший способ сделать это в ES5, где мне не нужна оболочка?
  3. Почему в ES5 мы можем установить метод прототипа в примитив, но не похоже, что мы можем сделать это с синтаксисом ES6? (Я использую Node 6.1 и Babel между прочим)

person mche    schedule 30.05.2017    source источник
comment
статическое поле, привязанное исключительно к классу BankAccount, где отслеживается, сколько банковских счетов открыто – Не делать. Именно поэтому (глобальные/статические, изменяемые) синглтоны плохи. Это приводит к утечке памяти и является немодульным (непроверяемым). Сохраняйте записи в методе, в котором вы создаете экземпляры. Точно так же, как вы сделали со своим BankAccountMaker.   -  person Bergi    schedule 30.05.2017
comment
Почему в ES5 мы можем установить примитивный метод прототипа, но не похоже, что мы можем сделать это с синтаксисом ES6?. Задайте для этого отдельный вопрос и предоставьте пример кода для чего. ты имеешь в виду. Кстати, методы не являются примитивами.   -  person Bergi    schedule 30.05.2017
comment
Улучшения вашего кода: 1) встроенный IncrementcountOfAccounts 2) Поместите BankAccount вне BankAccountMaker, это не замыкание, которому нужен доступ к счетчику - это позволит избежать повторного создания идентичных классов. Затем, чтобы преобразовать его в ES6, просто сделайте BankAccount class.   -  person Bergi    schedule 30.05.2017


Ответы (1)


Я добавил идентификатор к каждому банковскому счету. Таким образом, вы можете перебирать созданные вами учетные записи. incrementcountAccounts — плохая идея, потому что вы не знали, действительно ли был создан банковский счет.

Вы не можете этого сделать: параметры BankAccount(c = 0) не поддерживаются в ES5.

Некоторые фрагменты:

/**
 * Bank
 */
class Bank {
  constructor(name, id) {
    this.countOfAccounts = 0;
    this.id = id;
    this.name = name;
    
    console.log('--- ' + this.name + ' ---');
  }

  incrementcountOfAccounts() {
    this.countOfAccounts += 1;
  }
  
  addBankAccount(...data) {
    this.incrementcountOfAccounts();
    
    return new BankAccount(this.id, ...data);
  }
}

/**
 * BankAccount
 */
class BankAccount {
  /**
   * Constrctor
   * @param  {Number} bankId     
   * @param  {Number} [amount=0]   
   * @param  {Number} [checking=0]            
   */
  constructor(bankId, amount = 0, checking = 0) {
    if(!bankId) {
      throw Error('no bank id');
    }
    
    this.account = {
      bankId,
      checking, 
      amount
    };
  }
  
  /**
   * Get bank id
   * @return {number}
   */
  get bankId() {
    return this.account.bankId;
  }

  /**
   * Set amount
   * @param  {number} value
   * @return {number}       
   */
  set amount(value) {
    this.account.amount = value;
  }  

  /**
   * Get ammunt
   * @return {number}
   */
  get amount() {
    return this.account.amount;
  }

  /**
   * set checking
   * @param  {number} value
   * @return {number}     
   */
  set checking(value) {
    this.account.checking = value;
  }  

  /**
   * get checking
   * @return {number} 
   */
  get checking() {
    return this.account.checking;
  }
}

const FirstBank = new Bank('First Bank', 1);


const bankAccount1 = FirstBank.addBankAccount(300);
const bankAccount2 = FirstBank.addBankAccount(4000);


console.log('Account 1: ' + bankAccount1.amount + ' - ' + bankAccount1.checking + ' - ' + bankAccount1.bankId);
console.log('Account 2: ' + bankAccount2.amount + ' - ' + bankAccount1.checking + ' - ' + bankAccount1.bankId);


console.log('Accounts first Bank: ' + FirstBank.countOfAccounts);

const SecondBank = new Bank('Second Bank', 4);
const bankAccount3 = SecondBank.addBankAccount(0, 1);
console.log('Account 3: ' + bankAccount3.amount + ' - ' + bankAccount1.checking + ' - ' + bankAccount1.bankId);    
console.log('Accounts second Bank: ' + SecondBank.countOfAccounts);

ES5:

var BankAccountMaker = function () {
  this.countOfAccounts = 0;
  
  this.IncrementcountOfAccounts = function () {
    this.countOfAccounts += 1;
  }
  
  this.BankAccount = function () {
    this.checking = 0;
  }
  
  this.makeBankAccount = function (c) {
    this.IncrementcountOfAccounts();

    return new this.BankAccount(c);
  }
}

const Bank = new BankAccountMaker();

console.log(Bank.makeBankAccount(3));
console.log(Bank.makeBankAccount(3));
console.log(Bank.makeBankAccount(3));
console.log(Bank.countOfAccounts);

ES5 Prototype:

function BankAccountMaker() {
  this.countOfAccounts = 0;

}

BankAccountMaker.prototype.IncrementcountOfAccounts = function() {
  this.countOfAccounts += 1;
}

BankAccountMaker.prototype.BankAccount = function() {
  this.checking = 0;
}

BankAccountMaker.prototype.IncrementcountOfAccounts = function() {
  this.countOfAccounts += 1;
}

BankAccountMaker.prototype.makeBankAccount = function(c) {
  this.IncrementcountOfAccounts();
  console.log(this.countOfAccounts);
  
  return new this.BankAccount(c);
}

const Bank = new BankAccountMaker();

console.log(Bank.makeBankAccount(3));
console.log(Bank.makeBankAccount(3));
console.log(Bank.makeBankAccount(3));
console.log(Bank.countOfAccounts);

person Phil    schedule 30.05.2017
comment
Спасибо за подробную запись. Я думаю, что мне не удалось достаточно хорошо сформулировать свой первоначальный вопрос - я искал поведение статического поля, подобное тому, которое вы найдете в C#/Java. Тем не менее, основываясь на ваших ответах, а также на ответах Берги, это просто не функция языка ES6. - person mche; 02.06.2017