问题
I want to achieve this functionality:
- I have an object
var obj = {};
I have three properties on that obj,
obj.zero
&obj.one
&obj.binaryString
obj.zero
&obj.one
are methods whileobj.binaryString
is a string
When I chain the properties, I want them to add their respective digit to the binaryString
. So for example:
obj.one.zero.zero.one
=> makes obj.binaryString
= 1001
obj.one.zero.one.one.zero
=> makes obj.binaryString
= 10110
I have achieved the above functionality with this:
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'
Now I want to log out the completed binaryString
, plus and additionalString
which I have accomplished with the code below:
// placed inside Binary constructor function
Object.defineProperty(obj, 'log', {
get: function() {
return function(additionalString) {
console.log(obj.binaryString + additionalString);
};
}
});
So with this current code I can do this:
binary.one.zero.one.zero.one.log(' is the answer');
// logs out `10101 is the answer`
What I want to do is get rid of the log
and make the one
and zero
methods invokable or not so I can achieve this functionality:
binary.one.one.zero.one(' is the result')
// => logs out `1101 is the result`
How can I do this?
I believe it would be similar functionality to how Chalk works:
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
回答1:
Just Make the obj as function , and print what ever you want .
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 ")
回答2:
I would like to point out that what you're doing is a very bad/dangerous idea: abusing read properties to mutate the object itself is asking for trouble. You may not see it now, but it's going to lead to pain and heartache down the line in the form of difficult-to-find bugs and convoluted patterns.
What you can do is, which is not so dangerous, is instead of mutating the object itself, return a new instance of Binary
with every call to #one
or #zero
. For example:
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')
}})
This is the approach taken by Chalk, and will be much safer and less error-prone.
UPDATE:
After thinking about your problem, and seeing your question, I think the best approach at all is not to use classes at all. You can solve this problem with a pure function-based approach. It's immutable, it's safe, and I believe it's less confusing. Here it is in 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')
},
},
})
}
And if you can use ES6 (aka ES2015), you can make it much more compact:
function bin(str = '') {
return Object.defineProperties(msg => `${str} ${msg}`, {
zero: { get() { return bin(str + '0') } },
one: { get() { return bin(str + '1') } },
})
}
You would use it like this:
bin().one.zero.one.zero('is the answer') // '1010 is the answer'
来源:https://stackoverflow.com/questions/43923053/how-to-make-a-property-method-invokable-or-not