APP下载

Javascript基础:this究竟是什么

消息来源:baojiabao.com 作者: 发布时间:2024-05-20

报价宝综合消息Javascript基础:this究竟是什么

普通函式与箭头函式

普通函式指的是用function定义的函式:

var hello = function () {

console.log("Hello, itzou!");

}

箭头函式指的是用=>定义的函式:

var hello = () => {

console.log("Hello, itzou!");

}

JavaScript箭头函式与普通函式不只是写法上的区别,它们还有一些微妙的不同点,其中一个不同点就是this。

箭头函式没有自己的this值,箭头函式中所使用的this来自于函式作用域链。

这句话很简单,不过听着稍微有点莫名其妙,得从头说起。

this到底是什么?

关于this的文章也够多了,有时候越描越黑,我就不再添乱了,我只负责搬运一下MDN文件:this,感兴趣的可以仔细阅读一下,我摘录一些最重要的话就好了。

A function’s this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.

JavaScript是一门比较奇特的语言,它的this与其他语言不一样,并且它的取值还取决于程式码是否为严格模式(“use strict”)。

this的值是什么?

The JavaScript context object in which the current code is executing.

this就是程式码执行时当前的context object。

Global context

In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.

程式码没有在任何函式中执行,而是在全域性作用域中执行时,this的值就是global物件,对于浏览器来说,this就是window。

这一条规则还是比较容易接受的。

Function context

Inside a function, the value of this depends on how the function is called.

函式中的this值取决于这个函式是怎样被呼叫的,这一条规则就有点变态了,也是很容易出BUG的地方。

另外,this的值还与函式是否为严格模式(“use strict”)有关,这就非常的丧心病狂了…

大家如果好奇的话,出门左转看MDN文件,我多说无益,只说明一种简单的情况。

As an object method

When a function is called as a method of an object, its this is set to the object the method is called on.

当函式作为物件的方法被呼叫时,它的this值就是该物件。

var circle = {

radius: 10,

getRadius() {

console.log(this.radius);

}

};

circle.getRadius(); // 打印 10

self = this?

当我们需要在物件方法中巢状一个内层函式时,this就会给我们带来实际的困扰了,大家应该写过这样的程式码:

// 使用临时变数self

var circle = {

radius: 10,

outerDiameter() {

var self = this;

var innerDiameter = function() {

console.log(2 * self.radius);

};

innerDiameter();

}

};

circle.outerDiameter(); // 打印20

outerDiameter函式是circle物件的方法,因此其this值就是circle物件。

那我们直接写this.radius多好啊,可惜不能这么写,因为内层函式innerDiameter并不会继承外层函式outerDiameter的this值。outerDiameter函式的this值就是circle物件,this.radius等于10。

但是,innerDiameter函式的this值不是circle物件,那它到底是啥?它是innerDiameter函式执行时当前的context object,这个context object又是啥?其实我也晕了,所以不妨测试一下:

// innerDiameter函式中的this是window

var circle = {

radius: 10,

outerDiameter() {

var innerDiameter = function() {

console.log(this === window);

};

innerDiameter();

}

};

circle.outerDiameter(); // 打印true

innerDiameter函式中的this是window,为啥是window这个不去管它,反正不是circle物件。

因此,如果我们直接在innerDiameter函式中使用this的话,就出问题了:

// 使用普通函式

var circle = {

radius: 10,

outerDiameter() {

var innerDiameter = function() {

console.log(2 * this.radius);

};

innerDiameter();

}

};

circle.outerDiameter(); // 打印NaN

于是,我们不得不使用一个临时变数self将外层函式outerDiameter的this值搬运到内层函式innerDiameter。

.bind(this)

我们也可以使用.bind(this)来规避this变来变去的问题:

// 使用.bind(this)

var circle = {

radius: 10,

outerDiameter() {

var innerDiameter = function() {

console.log(2 * this.radius);

};

innerDiameter = innerDiameter.bind(this);

innerDiameter();

}

};

circle.outerDiameter(); // 打印20

但是,无论是使用临时变数self,还是使用.bind(this),都不是什么很简洁的方式。

总之,普通函式的this取值多少有点奇怪,尤其当我们采用面向物件的方式程式设计时,很多时候都需要用到this,大多数时候我们都不会去使用.bind(this),而是使用临时变数self或者that来搬运this的取值,写起来当然不是很爽,而且一不小心就会写出BUG来。

正如MDN文件所说:

Until arrow functions, every new function defined its own this value based on how the function was called。This proved to be less than ideal with an object-oriented style of programming.

箭头函式

箭头函式的this取值,规则非常简单,因为this在箭头函式中,可以看做一个普通变数。

An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules.

箭头函式没有自己的this值,箭头函式中所使用的this都是来自函式作用域链,它的取值遵循普通普通变数一样的规则,在函式作用域链中一层一层往上找。

有了箭头函式,我只要遵守下面的规则,this的问题就可以基本上不用管了:

对于需要使用object.method()方式呼叫的函式,使用普通函式定义,不要使用箭头函式。物件方法中所使用的this值有确定的含义,指的就是object本身。其他情况下,全部使用箭头函式。// 使用箭头函式

var circle = {

radius: 10,

outerDiameter() {

var innerDiameter = () => {

console.log(2 * this.radius);

};

innerDiameter();

}

};

circle.outerDiameter(); // 打印20

对于内层函式innerDiameter,它本身并没有this值,其使用的this来自作用域链,来自更高层函式的作用域。innerDiameter的外层函式outerDiameter是普通函式,它是有this值的,它的this值就是circle物件。因此,innerDiameter函式中所使用的this来自outerDiameter函式,其值为circle物件。

结论

JavaScript是Brendan Eich花了10天时间设计出来的,因此各种莫名其妙的特性,this也算是其中一个奇葩。好在这些年ECMAScript标准发展很快也很稳定,每年撸一个新的标准,多少可以弥补一下JS的先天不足。

箭头函式对于this取值规则的简化,其实也就是为了少给大家添乱,谁能记得住普通函式this取值的那么多条条框框啊。。。

另外,MDN文件绝对是一个宝藏,大家可以多看看。

2019-06-28 00:49:00

相关文章