this指向
- 全局作用域下的this指向window
- 如果给元素的事件行为绑定函数,那么函数中的this指向当前被绑定的那个元素
- 函数中的this,要看函数执行前有没有
.
, 有.
的话,点前面是谁,this就指向谁,如果没有点,指向window
- 自执行函数中的this永远指向window
- 定时器中函数的this指向window
- 构造函数中的this指向当前的实例
- call、apply、bind可以改变函数的this指向
- 箭头函数中没有this,如果输出this,就会输出箭头函数定义时所在的作用域中的this
this的四个绑定规则
1、默认绑定
规则:非严格模式默认指向window,严格模式指向undefined。
最常用的函数调用类型:独立函数调用。可以把这条规则看作是无法应用其他规则时的默认规则。
- 不带任何修饰的函数引用进行调用(独立函数调用),指向window。
function foo() {console.log(this.a)
}
var a = 2
foo() // 2
解析:foo()
是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。foo
是属于独立函数调用的,触发了默认绑定,从而指向全局window。
- 函数调用链(一个函数又调用另外一个函数)
- 将函数作为参数,传入到另一个函数中,作为函数的参数,指向window
2、隐式绑定
隐式绑定的 this,指向调用函数的上下文对象
2.1 一般的对象调用
规则:会把函数调用中的 this
绑定到这个上下文对象。
function foo() {console.log(this.a)
}
const obj = {a: 2,foo: foo
}
// 通过 obj 对象调用 foo 函数
obj.foo() // 2
2.2 对象属性引用链
规则:对象属性引用链中只有上一层或者说最后一层在调用位置中起作用。
function foo() {console.log(this.a)
}
var obj2 = {a: 2,foo: foo
}
var obj1 = {a: 1,obj2: obj2
}
obj1.obj2.foo() // 2
2.3 隐式绑定丢失问题
- ①将对象里的函数赋值给一个变量
function foo() {console.log(this.a)
}
var obj = {a: 2,foo: foo
}
var bar = obj.foo // 函数别名!
var a = 'global' // a 是全局对象的属性
bar() // "global"
虽然 bar
是 obj.foo
的一个引用,但是实际上,它引用的是 foo
函数本身,因此此时的 bar()
其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
- ②传入回调函数时
function foo() {console.log(this.a)
}
function doFoo(fn) {// fn 其实引用的是 foofn() // <-- 调用位置!
}
var obj = {a: 2,foo: foo
}
var a = 'global'// a 是全局对象的属性
doFoo(obj.foo)// "global"
参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值,所以结果和上一 个例子一样。
3、显式绑定
直接指定 this 的绑定对象,因此我们称之为显式绑定
3.1 使用 call(…) 和 apply(…)
如果我们不想在对象内部包含函数引用,而想在某个对象上强制调用函数,该怎么做呢? 可以使用函数的 call(..)
和 apply(..)
方法
JavaScript 提供的绝大多数函数以及你自 己创建的所有函数都可以使用 call(..)
和 apply(..)
方法。
function foo() {console.log(this.a)
}
var obj = {a: 2
}
foo.call(obj) // 2
3.2 硬绑定-bind
硬绑定是指一个函数总是显示的绑定到一个对象上
由于硬绑定是一种非常常用的模式,所以 ES5 提供了内置的方法 Function.prototype.bind
, 它的用法如下
function foo(num) {console.log(this.a, num)return this.a + num
}
var obj = {
a: 2
}
// 调用 bind() 方法,返回一个函数,那么这个新函数的 `this`,永远指向我们传入的