avatar

this

一. 全局执行

1
console.log(this); // Window

二. 函数中执行

  1. 非严格模式中
1
2
3
4
5
function func () {
console.log(this);
}
func();
// Window
  1. 严格模式
    1
    2
    3
    4
    5
    6
    "use strict";
    function func() {
    console.log(this);
    }
    func();
    // undefined

三. 作为对象的方法调用

当一个函数被当作一个对象的方法调用的时候,this 指向当前的对象 obj

1
2
3
4
5
6
7
8
var obj = {
name: 'kk',
func: function() {
console.log(this.name);
}
}
obj.func();
// kk

如果把对象的方法赋值给一个变量,调用该方法时,this 指向 Window:

1
2
3
4
5
6
7
8
9
var obj = {
name: 'kk',
func: function() {
console.log(this);
}
}
var test = obj.func;
test();
// Window

四. 作为构造函数使用

在 JS 中,为了实现类,我们需要定义一些构造函数,在调用一个构造函数的时候加上 new 这个关键字:

1
2
3
4
5
6
7
function Person(name) {
this.name = name;
console.log(this);
}
var p1 = new Person('hk');
// Person
// this 指向这个构造韩式调用的时候实例化出来的对象

如果构造函数当做普通函数来调用, this则指向Window

1
2
3
4
5
6
function Person(name) {
this.name = name;
console.log(this);
}
var p1 = Person('hk');
// Window

五. 在定时器中使用

1
2
3
4
setInterval(function() {
console.log(this);
}, 1000)
// Window

如果没有特殊指向,setInterval 和setTimeout 的回调函数中 this 的指向都是 Window 。这是因为 JS 的定时器方法是定义在 Window 下的。

六. 箭头函数

全局环境下调用

1
2
3
4
5
let func = () => {
console.log(this);
}
func();
// Window

作为对象的一个函数调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var obj = {
name: 'hh',
func: function () {
console.log(this);
}
}
obj.func();
// obj

var obj = {
name: 'hh',
func: () => {
console.log(this);
}
}
obj.func();
// Window

特殊情况:结合定时器调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var obj = {
name: 'hh',
func: function() {
setTimeout(function() {
console.log(this);
}, 0)
}
}
obj.func();
// Window

var obj = {
name: 'hh',
func: function() {
setTimeout(() => {
console.log(this);
}, 0)
}
}
obj.func();
// obj

若在对象的函数中,普通函数作为定时器延时执行的函数调用,this 指向 Window;箭头函数作为定时器延时执行的函数调用, this 指向定义时所在的对象,也就是 func 中的 this,即 obj。

箭头函数中 this 的值取决于该函数外部非箭头函数的 this 的值,且不能通过 call() 、 apply() 和 bind() 方法来改变 this 的值。

七. call, apply, bind

call

1
fun.call(thisArg[, arg[, arg2[, ...]]]);

它会立即执行函数, 第一个函数是指执行函数中的上下文, 后面的参数是执行函数需要传入的参数

apply

1
fun.apply(thisArg, [argsArray]);

它也会立即执行函数,第一个参数是指定执行函数中 this 的上下文,第二个参数是一个数组,是传给执行函数的参数(与 call 的区别)

bind

1
var foo = fun.bind(thisArg[, arg[, arg2[, ...]]]);

它不会执行函数,而是返回一个新的函数,这个新的函数被指定了 this 的上下文,后面的参数是执行函数需要传入的参数

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name, age) {
this.name = name;
this.age = age;
console.log(this);
}
var obj = {
name: 'hk',
age:18
};
Person.call(obj, 'mm', 10); // obj, {name: 'mm', age: 10}

Person.apply(obj, ['mm', 10]); // obj, {name: 'mm', age: 10}

var p1 = Person.bind(obj, 'mm', 10);
var p2 = new p1(); // Person {name: 'mm', age: 10}

示例中,call、apply 和 bind 的 this 都指向了 obj,都能正常运行;call、apply 会立即执行函数,call 和 apply 的区别就在于传递的参数,call 接收多个参数列表,apply 接收一个包含多个参数的数组;bind 不是立即执行函数,它返回一个函数,需要执行 p2 才能返回结果,bind 接收多个参数列表。

应用: 改变this的指向

使用es6的箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var name = 'hk';
var obj = {
name: 'hh',
func1: function() {
console.log(this.name);
},
func2: function() {
setTimeout(function() {
this.func1();
}, 1000);
}
};
obj.func2();
// Uncaught TypeError: this.func1 is not a function
// 这时会报错, 因为setTimeout里面函数的this指向Window, 而Window对象上没有func1这个函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var name = 'hk';
var obj = {
name: 'hh',
func1: function() {
console.log(this.name);
},
func2: function() {
setTimeout(() => {
this.func1();
}, 1000);
}
};
obj.func2();
// hh
// 此时没有报错, 因为箭头函数里的this的值取决于该函数外部非箭头函数的this的值, 也就是func2的this的值, 即obj, obj.name 为hh

在函数内部使用_this = this 略

使用call/apply/bind

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
var name = 'hk';
var obj = {
name: 'hh',
func1: function() {
console.log(this.name);
},
func2: function() {
setTimeout(function() {
this.func1();
}.call(obj), 1000);
},
func3: function() {
setTimeout(function() {
this.func1();
}.apply(obj), 1000);
},
func4: function() {
setTimeout(function() {
this.func1();
}.bind(obj)(), 1000);
}
};
obj.func2(); // hh
obj.func3(); // hh
obj.func4(); // hh

new 实例化一个对象

文章作者: Kwin
文章链接: http://huangkun.host/2020/03/25/20181128-this/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Kwin 's Blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论