1. this 别名
这种方式一般就是在函数作用域顶端创建一个指向 this 的变量。
例如,在一个对象方法中在执行一个方法或者事件的时候:
1 | var obj = { |
或者在vue实例的created()方法中利用axios获取数据的时候:
1 | created() { |
2. call和apply
call和apply的区别在于,使用apply时,所有参数都应放在一个单独的数组参数中,而在使用call的时候,参数应该一次列出,并用逗号隔开。call和apply的详细作用可以阅读我原来的博文:重温——apply和call方法,里面详细介绍了apply和call的各种用法。这里只说它们的其中一种用法:改变this指向。
1 | //如果单纯只是在一个函数中调用另一个函数是没什么多大区别,apply / call 的最大作用就是改变上下文 |
3. bind(this)
ES5中的bind()方法,它会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。例如:
1 | window.color = 'green'; |
在这里sayColor()调用bind()并传入对象o,创建了objectSayColor()函数。objectSayColor()函数的this值等于o,因此即使是在全局作用域中调用这个函数,也会输出blue,而不是全局window对象中国的green。
bind()方法还有一种使用方式是在函数运行时将 this 注入到回调中,使回调中的 this 能指向正确的上下文(改方法跟别名方式的第二个例子是相同的效果),例如:
1 | this.setState({ loading: true }); |
在 JavaScript 中,所有函数都有 bind 方法,其允许你为 this 指定特定值。一旦函数被绑定,上下文就不能被覆盖,也就意味着 this 会指向正确的上下文。
4. ES6箭头函数
ES2015 规范引入了箭头函数,使函数的定义更加简洁。箭头函数会隐式返回一个值,但更重要的是,它是在一个封闭的作用域中使用this:
1 | this.setState({ loading: true }); |
不管嵌套多少层,箭头函数中的 this 总能指向正确的上下文,因为函数体内的 this 指向的对象,就是定义时所在的对象,而不是使用时所在的对象。但缺点就是,由于箭头函数不能命名,因而在调试时,堆栈信息给的标签是anonymous function。
如果你用 Babel 将 ES6 的代码转换成 ES5 的代码,就会发现两个有趣的现象:
- 在某些情况下,编译器能判断函数名是否被赋值给了某个变量
- 编译器使用 别名 来维护上下文
1 | const loaded = () => { |
5. ES7 的绑定语法
在 ES7 中,有一个关于 bind 语法 的提议,提议将 :: 作为一个新的绑定操作符,该操作符会将左值和右值(一个函数)进行绑定。
以 map 的实现为例:
1 | function map(f) { |
与 lodash 不同,我们不需要传递数据给 map 作为参数:
1 | [1, 2, 3]::map(x => x * 2) |
对下面的代码熟悉吗?
1 | [].map.call(someNodeList, myFn); |
ES7 的绑定语法允许你像使用箭头函数一样使用 map:
1 | someNodeList::map(myFn); |
6. 方法传参指定
一些函数允许为 this 传递一个明确的值,保证其指向正确的上下文,例如 map 函数则将 this 作为最后一个参数:
1 | items.map(function(x) { |
虽然代码能运行,但这不是函数的一致实现。大部分函数并不接受 this 参数,所以最好还是采用上文中的其它方式来绑定 this 。
参考文章: 6 Ways to Bind JavaScript‘s this Keyword in React, ES6 & ES7
完~