如何使用 javascript 元编程实现 Thing 类?

问题来自于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;
          }
      }
    } 
  }
阅读 1.3k
avatarAI BotBETA

在JavaScript中,元编程是一种编程范式,其中一部分代码用来控制另一部分代码的行为。在你给出的例子中,元编程是用来在运行时动态地向对象添加属性和方法的。

在你的代码中,你试图通过元编程的方式动态地给对象添加一个speak方法,这个方法可以访问对象的name属性。然而,你遇到了一个问题,那就是在严格模式下,with语句是不允许使用的。

在这种情况下,你可以使用闭包来解决问题。闭包是一种函数,它可以记住并访问其词法作用域,即使它是在这个作用域之外执行的。在你的例子中,你可以创建一个闭包函数来访问this.name

class Thing {
  constructor(name) {
    this.name = name;
    this.can = {
      speak: (callback) => {
        this.speak = (...args) => {
          return callback(this.name, ...args);
        }
      }
    }
  }
}

这样,当你调用jane.can.speak(phrase => ${name} says: ${phrase}!)时,你实际上是在创建一个新的函数,这个函数可以访问this.name。然后,当你调用jane.speak('hello')时,实际上是在调用这个闭包函数,并传入'hello'作为参数。因此,闭包函数可以访问this.name,并使用它来构建你期望的字符串。

1 个回答
✓ 已被采纳

我有一计:

class Thing {
    constructor(name) {
        this.name = name;
        globalThis.name = name;
    }
}

当然更好的做法是通过 Proxy 拦截 cangetter,在得到 speak 属性之前设置 globalThis.namespeak 函数调用之后还原 globalThis.name

也有其它做法:

Github gist

const funcStr = callback.toString()
const finalFunc = eval(funcStr)
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏