ce mot-clé est l'un des mécanismes les plus complexes de JavaScript. Il s'agit d'un mot-clé très spécial qui est automatiquement défini dans le cadre de toutes les fonctions. Mais même les développeurs JavaScript très expérimentés ont du mal à dire exactement à quoi cela renvoie.
Qu'est-ce que c'est ?
Pointer sur la fonction elle-même ?
En regardant le sens littéral, il est facile pour les gens de penser que cela pointe vers la fonction elle-même. Est-ce vraiment le cas ? Nous pouvons regarder un exemple.
function foo() { this.count = this.count ? this.count + 1 : 1; } for (let i = 0; i < 5; i++) { foo(); } console.log(foo.count); // undefined
Vous pouvez voir que la sortie de foo.count n'est pas le 5
auquel nous nous attendions, mais le 0
attribué au début. En d’autres termes, 5
,而是一开始赋值的0
。也就是说this其实并没有指向函数本身。
指向作用域?
还有一种比较常见的误解是,this指向了函数的作用域。
function foo() { var a = 2; bar(); } function bar() { console.log(this.a); } foo(); // undefined
这段代码中,bar在foo中运行,输出this.a
得到的却是undefined
。也就是说this也不是指向函数的作用域的。
这也不是,那也不是,this到底是什么呢?在函数执行过程中,会创建一个执行上下文(一个记录),this就是这个上下文中的一个属性,在执行过程中用到。而this的指向则是取决于函数在哪里被调用。
this的绑定规则
this的绑定有四条可以遵循的规则,下面将一一介绍。
1.默认绑定
独立函数调用,非严格模式下,指向window;严格模式下指向undefined。
这里说的独立函数可以理解成除开后面三种情况的一般函数调用。
// 非严格模式 var name = 'Willem'; function foo() { console.log(this.name); } foo(); // Willem // 执行时启用严格模式 (function() { 'use strict'; foo(); // Willem bar(); // Cannot read property 'name' of undefined })(); // 函数体使用严格模式 function bar() { 'use strict'; console.log(this.name); }
上述代码中,分别在普通环境中输出Willem,说明指向的确实是window对象。需要特别注意的一点是:严格模式下指向undefined指的是函数体内启用了严格模式,而不是调用时。
2. 隐式绑定
隐式绑定说的是,在函数执行时,是否被某个对象拥有或包含
。换句话说,在函数运行时,是否是作为某个对象的属性的方式运行的,这样说还是不是很清楚,来个栗子:
function foo() { console.log(this.a); } var a = 1; var obj = { a: 2, foo }; obj.foo(); // 2 var obj2 = { a: 3, obj }; obj2.obj.foo(); // 2
示例中,foo被当做了obj的一个属性进行执行,此时obj作为了函数的上下文,此时this指向了obj,this.a
等价于obj.a
。在对象属性链式的调用中,只有最后一层会对调用位置产生影响,也就是说最后一层会影响this指向。
有很多前端的小伙伴面试时或许还见过这样的题:
function foo() { console.log(this.a); } var a = 1; var obj = { a: 2, foo }; var bar = obj.foo; bar(); // 1
这是隐式绑定最常见的一个问题,隐式丢失:被隐式绑定的函数会丢失绑定对象。虽然bar是对obj.foo的一个引用,但实际上引用的还是foo函数本身,bar函数就是一个独立函数的调用,参考第一条,此时this指向了window|undefined
。
还有一种经典的回调函数的this指向问题也是隐式丢失。
function foo() { console.log(this.a); } function doFoo(fn) { fn(); } var a = 1; var obj = { a: 2, foo }; doFoo(obj.foo); // 1
小结:在隐式绑定中,赋值的情况下(回调是隐式赋值)需要特别注意隐式丢失的问题 。
3. 显示绑定
JavaScript中的Function提供了两个方法call
和apply
,传入的第一个参数是一个对象,会把this绑定到这个对象。如果是传入的是一个原始值(字符串、数字、布尔),会被转换成它的对象形式(new String(), new Boolean(), new Number())。
function foo() { console.log(this.a); } var obj = { a: 1 }; foo.call(obj); // 1
虽然我们可以使用call
和apply
显式指定this的指向,但是还是会存在丢失绑定的问题。可以通过所谓的硬绑定(bind函数)
来解决,这里就不过多赘述了。
4. new
最后要介绍的是使用new
cela ne pointe pas réellement vers la fonction elle-même
.
- Pointer vers la portée ?
- Un autre malentendu courant est que cela indique la portée de la fonction.
function Foo(a) { this.a = a; } var bar = new Foo(2); bar.a; // 2
Dans ce code, bar est exécuté dans foo et la sortie de - cela n’indique pas la portée de la fonction.
this.a
est indéfini
. En d’autres termes, Lors de l'exécution de la fonction, un contexte d'exécution (un enregistrement) sera créé. Il s'agit d'un attribut dans ce contexte et est utilisé lors de l'exécution. L'intérêt de cela dépend de l'endroit où la fonction est appelée.
Cette règle contraignanteCette règle comporte quatre règles qui peuvent être suivies, qui seront présentées une par une ci-dessous. 1. La liaison par défaut