前端练习47 自动绑定实例方法
利用Proxy自动绑定实例方法
知识点
- class内部默认是严格模式
class
定义的原型方法的可枚举行- Proxy
题目
首先看这样一个引子:
1 | const name = 'window'; |
两次执行,分别会输出什么?
显然,第一次会打印出jay
,第二次是window
(,如果在严格模式下会报错),是因为this
指向调用者,第二次的调用者是window
在构建类的时候,同样有这个问题:
1 | class Person { |
注意,这里面是直接报错,因为this
是指向了undefined
而不是window
,因为==在类和模块的内部,默认就是严格模式==
所以在类似于React.js的组件的事件监听当中我们总是需要手动地进行bind(this)
操作。为了简化这样的操作,请你完成一个方法autoBind
,它可以接受一个类作为参数,并且返回一个类。返回的类的实例和原来的类的实例功能上并无差别,只是新的类的实例所有方法都会自动 bind 到实例上。例如:
1 | const BoundPerson = autoBind(Person) |
注意,如果autoBind
以后给原来的类新增方法,也会自动反映在实例上,例如:
1 | Person.prototype.sayGood = function () { |
实现
一上来我就想到了可以使用Proxy来拦截new
的操作符,后来又试了试用extends
方法,都可以实现一半,但是后一半,也就是“自动反映在实例上”这个要求没办法实现
先讲一下我用Proxy的实现,利用handler.construct
方法,拦截了new
的操作
1 | const autoBind = (ToBindClass) => new Proxy(ToBindClass, { |
在构造函数的方法中,使用了Object.getOwnPropertyNames(targets.prototype)
对原型上的方法遍历进行绑定
要注意的是,==class里面定义的原型方法是不可枚举的==,这一点与直接定义在prototype
是不同的,直接定义在prototype
是可枚举的
所以遍历class的原型方法不能使用Objecet.keys
方法,可以使用Object.getOwnPropertyNames
但是,这种方法没办法动对新增的方法进行处理。
看了看评论区,可以使用双层的Proxy实现,外层的Proxy不同,里面不直接返回实例,而是用Proxy再次进行处理的实例,对实例的get
方法进行拦截,每次访问的时候再去原型链上找,然后进行绑定。
1 | const autoBind = (ToBindClass) => new Proxy(ToBindClass, { |
外层的Proxy可以用函数自己去拦截构造器,所以上面也可以改写成:
1 | const autoBind = (ToBindClass) => { |
太笨了。