JavaScript函数this指向
# this指向简介
- 函数在调用时,JavaScript会默认给this绑定一个值;
- this的绑定和定义的位置没有关系;
- this的绑定和调用方式以及调用的位置有关系;
- this是在运行时绑定的。
# this绑定的规则
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
# 规则一 默认绑定
当独立的函数被调用时,函数没有被绑定到某个对象上调用,this指向windos对象;严格模式下,独立调用函数中的this指向的是undefined
// 场景一
function foo(){
console.log(this)
}
foo()
// 场景二
function test1(){
console.log(this)
test2()
}
function test2(){
console.log(this)
test3()
}
function test3(){
console.log(this)
}
test1()
// 场景三
function foo(func){
func();
}
var obj = {
name: 'zs',
bar: function(){
console.log(this)
}
}
foo(obj.bar) //依然是独立函数调用,指向window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 规则二 隐式绑定
通过某个对象进行调用的方式
// 场景一
function foo(){
console.log(this)
}
var obj = {
name: 'zs',
foo: foo
}
obj.foo()
// 场景二
function foo(){
console.log(this)
}
var obj1 = {
name: 'obj1',
foo: foo
}
var obj2 = {
name: 'obj2',
obj1: obj1
}
obj2.obj1.foo()
// 场景三
function foo(){
console.log(this)
}
var obj1 = {
name: 'obj1',
foo: foo
}
var bar = obj1.foo
bar();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 规则三 显式绑定
隐式绑定有一个前提
- 必须在调用的对象内部有一个函数的引用,比如一个属性
- 如果没有这样的引用,在进行调用时,会找不到该函数的结果
- 正是通过这个引用,间接将this绑定到了这个对象上
如果不希望在对象内部包含这个函数的引用,同时又希望在这个对象上强制调用时需要使用如下方式。
在JavaScript中所有的函数都可以使用call
和apply
方法
func.apply(thisArg, [argArr])
func.call(thisArg, arg1, arg2,...)
1
2
2
- 第一个参数是相同的,要求传入一个对象,这个对象是给this准备的;在调用函数时,会将this绑定到这个对象上。
- 后面的参数,
apply
为数组,call
为参数列表。 apply
和call
都明确的绑定了this指向的对象,所以称之为显式绑定
# call、apply、bind
通过call
或者apply
绑定this对象,显式绑定后,this就会明确指向绑定的对象
function foo(){
console.log(this)
}
foo.call(window) // window
foo.call({name: 'zs'}) // {name: 'zs'}
foo.call(123) // 123
1
2
3
4
5
6
2
3
4
5
6
如果希望一个函数总是显式的绑定到一个对象上
- 使用
bind
方法,bind()
方法创建一个新的绑定函数(bounding function, BF) - 绑定函数是一个怪异函数对象
- 在
bind()
被调用时,这个新函数的this被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用 func.bind(thisArg[, arg1 [,arg2[,...]]])
var obj = {name: 'zs'}
function foo(){
console.log(this)
}
foo() // window
var bar = foo
bar() // window
var bar2 = foo.bind(obj)
bar2() // obj
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
// bind传递参数的案例
function foo(name, age, height, address) {
console.log(this);
console.log("参数:", name, age, height, address);
}
var obj = { name: "zs" };
var bar = foo.bind(obj, "kobe", 18, 1.88);
bar("US"); // 这里的参数是函数参数列表中一次向后补位的参数值
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 内置函数
有时候会调用一些JavaScript的内置函数,或者一些第三方库中的函数
- 这些内置函数要求传入另一个函数
- 我们不会显式的调用这些函数,JavaScript内部或者第三方库内部会自动执行
setTimeout
setTimeout(function(){
console.log(this)
}, 1000)
1
2
3
2
3
数组的forEach
var names = ['abc', 'cba', '123']
var obj = {name: 'zs'}
names.forEach(function(item){
console.log(this) // 输出三次全部指向obj
}, obj)
1
2
3
4
5
2
3
4
5
div点击
var box = document.querySelector('.box')
box.onclick = function(){
console.log(this === box)
}
1
2
3
4
2
3
4
# new 绑定
JavaScript中的函数可以当做一个类的构造函数来使用,也就是new
关键字
使用new
关键字会执行如下操作
- 创建一个新的对象
- 对象会被执行
prototype
连接 - 这个新对象会绑定到函数调用的this上,this绑定在这个步骤完成
- 如果函数没有返回其它对象,表达式会返回这新的对象
function Person(name){
console.log(this) // Person{}
this.name = name // Person {name: 'zs'}
}
var p = new Person('zs')
console.log(p)
1
2
3
4
5
6
7
2
3
4
5
6
7
# 规则优先级
- 默认规则的优先级最低,因为存在其他规则时,就会通过其他规则的方式来绑定this
- 显式绑定优先级高于隐式绑定
- new绑定优先级高于隐式绑定
- new绑定优先级高于bind
- new绑定和call, apply是不允许同时使用的,所以不存在谁的优先级更高
- new绑定可以和bind一起使用,new绑定优先级更高
- bind的优先级高于apply, call的优先级,bind只是比较少用
# this绑定 --- 忽略显式绑定
在显式绑定中,传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则
function foo(){
console.log(this)
}
var obj = {
name: 'why'
}
foo.call(obj) // obj
foo.call(null) // window
foo.call(undefined) // window
var bar = foo.bind(null)
bar() // window
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# this绑定 -- 间接函数引用
创建一个函数的间接引用,这种情况使用默认的绑定规则
比如,赋值(obj2.foo = obj1.foo)的结果是foo函数,foo函数被直接调用,那么是默认绑定
function foo(){
console.log(this)
}
var obj1 = {
name: 'obj1',
foo: foo
}
var obj2 = {
name: 'obj2'
}
obj1.foo() // obj1
(obj2.foo = obj1.foo)() // window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 箭头函数
注意点
- 箭头函数不会绑定
this
,arguments
属性。 - 箭头函数不能作为构造函数来使用(不能和new一起使用,没有原型,会抛出错误)
如果默认返回值是一个对象,那么这个对象那个必须加()
var arrFn = () => 123 // 简单数类型
var objFn = () => ({name: 'zs'}) // 返回对象
// 类似于
var objFn = () => {
return {
name: 'zs'
}
}
// var objFn = () => {} 这里的{}是执行体
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 箭头函数中的this使用
箭头函数中没有this,会到上层作用域中去查找;即使使用apply
调用,也不能绑定this
上次更新: 2022/10/07, 08:38:52