JavaScript之this

前言

与我们常见的很多语言不同,JavaScript 函数中的 this 指向并不是在函数定义的时候确定的,而是在调用的时候确定的。换句话说,函数的调用方式决定了 this 指向。

JavaScript 中,普通的函数调用方式有三种:直接调用、方法调用和 new 调用。除此之外,还有一些特殊的调用方式,比如通过 bind() 将函数绑定到对象之后再进行调用、通过 call()、apply() 进行调用等。而 es6 引入了箭头函数之后,箭头函数调用时,其 this 指向又有所不同。下面就来分析这些情况下的 this 指向。

直接调用(全局环境下的this)

当在网页的全局作用域中调用函数时,this对象引用的就是window。
例1:

1
2
3
4
5
6
console.log(this);//Window

function f() {
console.log(this);
}
f();//Window 函数直接调用

例2:

1
2
3
4
5
6
7
8
var 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
10
var 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
12
var 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的区别:

  1. 它们在功能上是没有区别的,都是改变this的指向,它们的区别主要是在于方法的实现形式和参数传递上的不同
  2. call与apply的第一个参数都是要传入给当前对象的对象
  3. apply第二个参数传入的是数组,而call传入的是序列项。
  4. fn.call(对象,arg1,arg2….)
  5. fn.apply(对象,[arg1,arg2,…])
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);
}

sayName(); // window 直接调用函数sayName
sayName.call(obj); // object 调用call方法修改this的指向
sayName.call(); // window 当call方法的参数为空时,默认调用全局对象

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
13
var 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
14
var 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。
ES6

1
2
3
4
5
6
7
8
9
10
11
12
var foo = (a) => {
console.log(a);
console.log(this);
}
foo(1);
// 1
// Window

var obj = {
name: 'hehe'
};
foo.call(obj, 2);

ES5

1
2
3
4
5
6
7
8
9
10
11
var foo = function (a) {
console.log(a);
console.log(this);
}
foo(1);
// 1
// obj
var obj = {
name: 'hehe'
};
foo.call(obj, 2);

Buy me a cup of coffee,thanks!