目录

JavaScript函数this指向

# this指向简介

  1. 函数在调用时,JavaScript会默认给this绑定一个值;
  2. this的绑定和定义的位置没有关系;
  3. this的绑定和调用方式以及调用的位置有关系;
  4. this是在运行时绑定的。

# this绑定的规则

  1. 默认绑定
  2. 隐式绑定
  3. 显式绑定
  4. 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

# 规则二 隐式绑定

通过某个对象进行调用的方式

// 场景一
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

# 规则三 显式绑定

隐式绑定有一个前提

  • 必须在调用的对象内部有一个函数的引用,比如一个属性
  • 如果没有这样的引用,在进行调用时,会找不到该函数的结果
  • 正是通过这个引用,间接将this绑定到了这个对象上

如果不希望在对象内部包含这个函数的引用,同时又希望在这个对象上强制调用时需要使用如下方式。

在JavaScript中所有的函数都可以使用callapply方法

func.apply(thisArg, [argArr])
func.call(thisArg, arg1, arg2,...)
1
2
  • 第一个参数是相同的,要求传入一个对象,这个对象是给this准备的;在调用函数时,会将this绑定到这个对象上。
  • 后面的参数,apply为数组,call为参数列表。
  • applycall都明确的绑定了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

如果希望一个函数总是显式的绑定到一个对象上

  • 使用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
// 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

image

# 内置函数

有时候会调用一些JavaScript的内置函数,或者一些第三方库中的函数

  • 这些内置函数要求传入另一个函数
  • 我们不会显式的调用这些函数,JavaScript内部或者第三方库内部会自动执行

setTimeout

setTimeout(function(){
    console.log(this)
}, 1000)
1
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

div点击

var box = document.querySelector('.box')
box.onclick = function(){
    console.log(this === box)
}
1
2
3
4

# new 绑定

JavaScript中的函数可以当做一个类的构造函数来使用,也就是new关键字

使用new关键字会执行如下操作

  1. 创建一个新的对象
  2. 对象会被执行prototype连接
  3. 这个新对象会绑定到函数调用的this上,this绑定在这个步骤完成
  4. 如果函数没有返回其它对象,表达式会返回这新的对象
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

# 规则优先级

  1. 默认规则的优先级最低,因为存在其他规则时,就会通过其他规则的方式来绑定this
  2. 显式绑定优先级高于隐式绑定
  3. new绑定优先级高于隐式绑定
  4. new绑定优先级高于bind
    1. new绑定和call, apply是不允许同时使用的,所以不存在谁的优先级更高
    2. new绑定可以和bind一起使用,new绑定优先级更高
  5. 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

# 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

# 箭头函数

注意点

  • 箭头函数不会绑定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

# 箭头函数中的this使用

箭头函数中没有this,会到上层作用域中去查找;即使使用apply调用,也不能绑定this

上次更新: 2022/10/07, 08:38:52
最近更新
01
防抖和节流
02-06
02
正则表达式
01-29
03
async_await函数
12-30
更多文章>