#84 自动绑定实例方法


  • 0
    administrators

    在 JavaScript 的类当中,类实例如果不通过实例进行调用,方法中的 this 就不会指向实例,例如:

    class Person {
      constructor (name) {
        this.name = name
      }
      sayHi () {
        console.log(`I am ${this.name}.`)
      }
    }
    const jerry = new Person('Jerry')
    const sayHi = jerry.sayHi
    sayHi() // => 报错
    

    所以在类似于 React.js 的组件的事件监听当中我们总是需要手动地进行 bind(this) 操作。为了简化这样的操作,请你完成一个方法 autoBind,它可以接受一个类作为参数,并且返回一个类。返回的类的实例和原来的类的实例功能上并无差别,只是新的类的实例所有方法都会自动 bind 到实例上。例如:

    const BoundPerson = autoBind(Person)
    
    const jerry = new BoundPerson('Jerry')
    const sayHi = jerry.sayHi
    sayHi() // => I am Jerry.
    
    const lucy = new BoundPerson('Lucy')
    const sayHi = lucy.sayHi
    sayHi() // => I am Lucy.
    

    注意,如果 autoBind 以后给原来的类新增方法,也会自动反映在实例上,例如:

    Person.prototype.sayGood = function () {
      console.log(`I am ${this.name}. I am good!`)
    }
    
    const sayGood = lucy.sayGood
    sayGood() // => I am Lucy. I am good!
    

    请你完成 autoBind 的编写。


  • 0

    @ScriptOJ
    这样为什么不行

    const autoBind = self => {

    for (const key of Object.getOwnPropertyNames(self.constructor.prototype)) {
    	const val = self[key];
    
    	if (key !== 'constructor' && typeof val === 'function') {
    		self[key] = val.bind(self);
    	}
    }
    
    return self;
    

    };


  • 0

    @ScriptOJ 可以帮忙看一下哪个例子没通过吗,谢谢


  • 0
    administrators

    @myboy 把题目中的例子跑通应该就可以了。


  • 0
    管理员

    const autoBind = (fn) => new Proxy(fn, {
      construct (target, args) {
        return new Proxy(new fn(...args), {
          get: (target, key) => {
            return typeof target[key] === 'function' ? target[key].bind(target) : target[key]
          }
        })
      }
    })
    

  • 0

    const autoBind = (ToBindClass) => {
      return class newClass extends ToBindClass {
        constructor(...arg) {
          super(...arg);
          const proto = ToBindClass.prototype;
          const props = Object.getOwnPropertyNames(ToBindClass.prototype);
          props.map(p => {
            if (typeof proto[p] === 'function') {
              this.proto[p] = this.proto[p].bind(this);
            }
          })
        }
      }
    }
    

    这样写为什么报错呢?
    运行信息: Cannot read property 'constructor' of undefined


  • 1

    考查的是Proxy的运用,有点小复杂,需要使用两次Proxy

    const autoBind = (ToBindClass) => new Proxy(ToBindClass, {
      construct: function(F, args) {
        let inst = new F(...args)
        return new Proxy(inst, {
          get: function(target, prop) {
            if(typeof target[prop] === 'function') {
              return target[prop].bind(target)
            }
            return target[prop]
          }
        })
      }
    })
    

    一个你用了还想用的前端表单验证工具 https://github.com/WLDragon/SMValidator


  • 0

    @陈小俊#84 自动绑定实例方法 中说:

    target[key].bind(new fn(...args))

    这样虽然通过了测试,但是绑定的并不是原来的对象,应该是bind(target)才对


  • 0
    管理员

    @WLDragon
    嗯,确实不应该多此一举再new一个,我改成target


登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待