Как сделать свойство / метод доступным или нет?
Я хочу добиться этой функциональности:
- У меня есть объект
var obj = {};
У меня есть три свойства на этом объекте,
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'