前言
与我们常见的很多语言不同,JavaScript 函数中的 this 指向并不是在函数定义的时候确定的,而是在调用的时候确定的。换句话说,函数的调用方式决定了 this 指向。
JavaScript 中,普通的函数调用方式有三种:直接调用、方法调用和 new 调用。除此之外,还有一些特殊的调用方式,比如通过 bind() 将函数绑定到对象之后再进行调用、通过 call()、apply() 进行调用等。而 es6 引入了箭头函数之后,箭头函数调用时,其 this 指向又有所不同。下面就来分析这些情况下的 this 指向。
直接调用(全局环境下的this)
当在网页的全局作用域中调用函数时,this对象引用的就是window。
例1:1
2
3
4
5
6console.log(this);//Window
function f() {
console.log(this);
}
f();//Window 函数直接调用
例2:1
2
3
4
5
6
7
8var name = "window";
function sayName(){
var name = "fun";
alert(this.name);
}
sayName(); // "window" 在全局调用,this对象引用的就是window
方法调用(对象中的this)
将一个函数赋给对象,通过对象调用这个函数,它们的this是调用该函数的对象。1
2
3
4
5
6
7
8
9
10var name = "window";
var obj = {
name: "hehe",
sayName: function () {
return this.name;
}
};
obj.sayName();//hehe
将函数sayName赋给对象o,obj.sayName()被调用时,函数内部的this被绑定到obj
new 调用(构造函数中的this)
函数或方法之前带有关键字new,它就构成了构造函数调用。通过构造函数生成一个新的对象,this指向新对象
构造函数以大写字母开头,提醒调用者使用正确的方式调用1
2
3
4
5
6
7
8
9
10
11
12var name = "global"
function Person(name){
this.name = name,
this.sayName = function(){
alert(this.name);
}
}
var p = new Person("local");
p.sayName(); // "local"
console.log(p.name); // local
console.log(name); // global
apply和call调用对this的影响
apply和call是函数对象的的两个方法,它们可以修改函数执行的上下文环境,即this绑定的对象。apply和call的第一个参数就是this绑定的对象,若apply和call的参数为空,则默认调用全局对象。
apply和call的区别:
- 它们在功能上是没有区别的,都是改变this的指向,它们的区别主要是在于方法的实现形式和参数传递上的不同
- call与apply的第一个参数都是要传入给当前对象的对象
- apply第二个参数传入的是数组,而call传入的是序列项。
- fn.call(对象,arg1,arg2….)
- fn.apply(对象,[arg1,arg2,…])
1 | var name = "window" |
bind() 对直接调用的影响
这个方法会创建一个函数的实例,其 this 始终指向bind()绑定的对象1
2
3
4
5
6
7
8
9
10
11
12
13
var name = "window"
var obj = {
name: "object"
}
function sayName(){
alert(this.name);
}
var objSayName = sayName.bind(obj);
objSayName();//object
闭包中的this
闭包中使用this对象可能会导致一些问题,this对象在运行时是基于函数的执行环境对象的:在全局函数中,this等于window,而当函数被作为某个对象方法调用时,this等于那个对象。
匿名函数的执行环境具有全局性,因此其this对象通常指向window。1
2
3
4
5
6
7
8
9
10
11
12
13var name = "window";
var obj = {
name: "obj",
sayName: function(){
var test = function(){
alert(this.name); // this绑定到全局对象上
}
test();
}
}
obj.sayName(); // "window"
解决方法1
2
3
4
5
6
7
8
9
10
11
12
13
14var name = "window";
var obj = {
name: "obj",
sayName: function(){
var that = this; // 使用变量替代的方法,这样我们创建了一个局部变量that来指向obj对象
var test = function(){
alert(that.name);
}
test();
}
}
obj.sayName(); // "obj"
ES6中箭头函数中的this
箭头函数中的 this 在定义它的时候已经决定了,与如何调用以及在哪里调用它无关,包括 (call, apply, bind) 等操作都无法改变它的 this。
ES61
2
3
4
5
6
7
8
9
10
11
12var foo = (a) => {
console.log(a);
console.log(this);
}
foo(1);
// 1
// Window
var obj = {
name: 'hehe'
};
foo.call(obj, 2);
ES51
2
3
4
5
6
7
8
9
10
11var foo = function (a) {
console.log(a);
console.log(this);
}
foo(1);
// 1
// obj
var obj = {
name: 'hehe'
};
foo.call(obj, 2);