JS的函数和this
背景
我没有系统性的从头开始学过一遍JS,全凭之前学的其它语言,尤其是Python,直接上手操作了,所以留了不少的坑。
虽然对我来说是一个坑,但我觉得本文更适合放到学习的分类里。
给出下列代码。这里是对原问题的一个抽象,只是把问题的核心单独摘出来了:
1  | function each(arr, action) {  | 
这个函数它的功能就是遍历一遍数组,然后把每个元素传给action参数。到目前为止是没有问题的。
问题复现
我这里自作聪明,把上面的第9行改了一下,简化代码:
1  | each(arr1, arr2.push)  | 
然后就顺利的报错了,这里给出错误信息:
1  | action(item)  | 
这里是node的报错,当时在浏览器里内容不太一样,但也提到了undefined相关的内容。
原理
原理很简单,就是action(item)这样调用的时候,传给action的this是undefined。
新建一个文件,写入下列代码足以验证。这里的foo是obj对象的实例方法,es6语法:
1  | 
  | 
这里要是严格模式,否则this会指向global(node)或者window(浏览器)。
这里扯一下Python,同样的代码它运行出来结果就会不一样了。如果你对Python没有兴趣可以略过这里的对比:
1  | def call(f):  | 
这里的原因就是,当我们使用obj.bar这样获得方法的话,Python会给我们把obj和第一个参数self绑定上。
解决方案
我们需要进行一个操作,如果也想像Python那样: Function.prototype.bind()
bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。来源: MDN
所以说我们把上面的JS测试代码改成这样,就可以了:
1  | call(obj.foo.bind(obj))  | 
但是回到我们实际应用场景,还是这样写更好点:
1  | call(() => obj.foo())  | 
或许还有更多的方法。至于如何选择,就仁者见仁、智者见智了。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 喵喵小窝!