问题来自于codewars The builder of things
要求我们实现一个Thing类,其中一点要求如下所示:
describe('#can', function(){
describe('jane.can.speak(phrase => `${name} says: ${phrase}!`)', function(){
it('should create a speak method on jane', function(){
const jane = new Thing('Jane');
jane.can.speak(phrase => `${name} says: ${phrase}!`);
expect(jane.speak('hello')).to.equal('Jane says: hello!');
});
});
难点是这里的name
的值从哪里找啊?
我想到的一个方案是使用with
,但是codewars上使用的是严格模式,不能使用with
。
class Thing {
// TODO: Make the magic happen
/*
const jane = new Thing('jane');
console.log(jane.name) => 'jane'
*/
constructor(name) {
this.name = name;
/*
can
jane.can.speak(phrase => `${name} says: ${phrase}!`)
jane.speak('Hello') => 'jane says: Hello!'
where to find name ? => this
*/
this.can = {
speak: (callback) => {
this.speak = (...args) => {
let res;
with(this) {
res = callback(...args);
};
return res;
}
}
}
}
我有一计:
当然更好的做法是通过
Proxy
拦截can
的getter
,在得到speak
属性之前设置globalThis.name
,speak
函数调用之后还原globalThis.name
。也有其它做法:
Github gist: