Как сделать свойство / метод доступным или нет?

Я хочу добиться этой функциональности:

  1. У меня есть объект var obj = {};
  2. У меня есть три свойства на этом объекте, obj.zero & obj.one& obj.binaryString

    • obj.zero & obj.one методы в то время как obj.binaryString это строка

Когда я объединяю свойства в цепочку, я хочу, чтобы они добавили соответствующую цифру к binaryString, Так, например:

obj.one.zero.zero.one => делает obj.binaryString знак равно 1001

obj.one.zero.one.one.zero => делает obj.binaryString знак равно 10110

Я достиг вышеуказанной функциональности с этим:

function Binary () {
    var obj = { binaryString: '' };

    Object.defineProperty(obj, 'zero', {
        get: function() {
            obj.binaryString += '0';
            return obj;
        }
    });

    Object.defineProperty(obj, 'one', {
        get: function() {
            obj.binaryString += '1';
            return obj;
        }
    });

    return obj;
}

var binary = new Binary();
binary.one.zero.zero.one  // => obj.binaryString becomes '1001'

Теперь я хочу выйти из завершенного binaryString, плюс и additionalString что я сделал с кодом ниже:

// placed inside Binary constructor function
Object.defineProperty(obj, 'log', {
    get: function() {
        return function(additionalString) {
            console.log(obj.binaryString + additionalString);
        };
    }
});

Так что с этим текущим кодом я могу сделать это:

binary.one.zero.one.zero.one.log(' is the answer');
// logs out `10101 is the answer`

Что я хочу сделать, это избавиться от log и сделать one а также zero методы, вызываемые или нет, поэтому я могу достичь этой функциональности:

binary.one.one.zero.one(' is the result')
// => logs out `1101 is the result`

Как я могу это сделать?

Я считаю, что это будет похоже на функционал Chalk:

chalk.blue.bold('Hello world!');
// `blue` is not invoked here but it adds the color blue to the style

chalk.blue('Hello world!');
// `blue` IS invoked here.  It adds blue to the style and returns the stylized string

2 ответа

Решение

Просто сделайте объект как функцию и напечатайте то, что вы хотите.

function Binary () {
    var obj = function(msg){ console.log(msg+this.binaryString ) };
    obj.binaryString = ''

    Object.defineProperty(obj, 'zero', {
        get: function() {
            obj.binaryString += '0';
            return obj;
        }
    });

    Object.defineProperty(obj, 'one', {
        get: function() {
            obj.binaryString += '1';
            return obj;
        }
    });

    return obj;
}

var binary = new Binary();
binary.one.zero.zero.one.zero(" is the result ")

Я хотел бы отметить, что то, что вы делаете, является очень плохой / опасной идеей: злоупотребление свойствами чтения для изменения самого объекта вызывает проблемы. Вы можете не видеть это сейчас, но это приведет к боли и душевной боли по линии в виде трудно обнаруживаемых ошибок и запутанных паттернов.

То, что вы можете сделать, это, что не так опасно, вместо того, чтобы мутировать сам объект, вернуть новый экземпляр Binary с каждым звонком #one или же #zero, Например:

function Binary(s) {
  this.binaryString = s || ''
}
Object.defineProperty(Binary.prototype, 'zero', {
  get: function() {
    return new Binary(this.binaryString + '0')
}})
Object.defineProperty(Binary.prototype, 'one', {
  get: function() {
    return new Binary(this.binaryString + '1')
}})

Это подход, принятый Chalk, и он будет намного безопаснее и менее подвержен ошибкам.

ОБНОВЛЕНИЕ:

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

function bin(str) {
  if(!str) str = ''
  function f(msg) { return str + ' ' + msg }
  return Object.defineProperties(f, {
    zero: {
      get: function() {
        return bin(str + '0')
      },
    },
    one: {
      get: function() {
        return bin(str + '1')
      },
    },
  })
}

И если вы можете использовать ES6 (он же ES2015), вы можете сделать его намного более компактным:

function bin(str = '') {
  return Object.defineProperties(msg => `${str} ${msg}`, {
    zero: { get() { return bin(str + '0') } },
    one: { get() { return bin(str + '1') } },
  })
}

Вы бы использовали это так:

bin().one.zero.one.zero('is the answer') // '1010 is the answer'
Другие вопросы по тегам