this全面解析(你不知道的javaScript,笔记)
(二)重新开始认识this
1.理解调用位置,决定了this的绑定
调用位置就是函数在代码被调用的位置,而不是声明的位置,分析调用栈获取。
2.绑定规则
2.1默认绑定
foo的是不带任何修饰的函数引用进行调用的,this使用默认绑定规则指向全局对象(非严格模式)
2.2隐式绑定
当函数引用有上下文对象时,隐式绑定会把函数调用中的this绑定到这个上下文对象。调用位置会使用obj上下文来引用函数,函数被调用时obj对象“拥有”或“包含”它。
但是对象属性引用链中只有最顶层或最后一层会影响调用位置
隐式丢失问题
1.被隐式绑定的函数对象会丢失绑定对象运用默认绑定,绑定到全局对象(非严格模式)或者undefined(严格模式)上
这个需要了解引用类型的数据,赋值的是引用地址,所以bar是obj.foo的引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
2.另一种丢失发生在传入回调函数时:
参数传递其实就是隐式赋值,因此我们传入函数时也会被隐式赋值,和1的结果一样。
2.3显式绑定
函数call,apply,bind方法
显式绑定的硬绑定解决丢失问题
function foo(){
console.log(this.a)
}
var obj={
a:2
}
var bar=function(){
foo.call(obj)
}
bar() ///2
setTimeout(bar,100) //2
//硬绑定的bar不可能再修改它的this
bar.call(window) //2
forEach第二个参数可指定this绑定对象
2.4 new绑定
优先级
new绑定,显式绑定,隐式绑定,默认绑定
规则应用的例外
把null或undefined作为this的绑定对象传入call,apply,bind,这些值在被调用时会被忽略,应用的是默认绑定规则。
应用:使用apply来展开一个数组
function foo(a,b){
console.log("a":+a+",b:"+b)
}
foo.apply(null,[2,3]) //a:2,b:3 ES6 中可以扩展运算符...,foo(...[2,3])
使用bind()进行柯里化
var bar=foo.bind(null,2);
bar(3) //a:2,b:3
更安全的做法是传入一个空对象,不会对全局对象有影响
创建空对象:Object.create(null),不会创建Object.prototype
间接引用
箭头函数
foo内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法修改。