Maison  >  Article  >  interface Web  >  Quelle est la magie de ceci en JavaScript ?

Quelle est la magie de ceci en JavaScript ?

藏色散人
藏色散人avant
2021-09-19 17:11:481850parcourir
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提供了两个方法callapply,传入的第一个参数是一个对象,会把this绑定到这个对象。如果是传入的是一个原始值(字符串、数字、布尔),会被转换成它的对象形式(new String(), new Boolean(), new Number())。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 1
};
foo.call(obj); // 1

虽然我们可以使用callapply显式指定this的指向,但是还是会存在丢失绑定的问题。可以通过所谓的硬绑定(bind函数)来解决,这里就不过多赘述了。

4. new

最后要介绍的是使用newcela ne pointe pas réellement vers la fonction elle-même
.

    Pointer vers la portée ?
  1. Un autre malentendu courant est que cela indique la portée de la fonction.
  2. function Foo(a) {
        this.a = a;
    }
    
    var bar = new Foo(2);
    bar.a; // 2
  3. Dans ce code, bar est exécuté dans foo et la sortie de this.a est indéfini. En d’autres termes,
  4. cela n’indique pas la portée de la fonction.
Ce n’est pas ça, ce n’est pas ça, qu’est-ce que c’est ? 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 contraignante

Cette 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

est un appel de fonction indépendant. En mode non strict, il pointe vers window ; en mode strict, il pointe vers undefined. Les fonctions indépendantes mentionnées ici peuvent être comprises comme des appels de fonctions généraux, à l'exception des trois situations suivantes. rrreeeDans le code ci-dessus, Willem est affiché dans l'environnement normal, indiquant qu'il s'agit bien de l'objet window pointé. Une chose qui nécessite une attention particulière est la suivante : pointant vers undefined en mode strict fait référence au fait que le mode strict est activé dans le corps de la fonction, pas lorsqu'elle est appelée.
2. Liaison implicite

La liaison implicite signifie si appartient ou est inclus par un objet lorsque la fonction est exécutée. En d'autres termes, lorsque la fonction est en cours d'exécution, il n'est pas très clair si elle est exécutée en tant qu'attribut d'un objet : 🎜rrreee🎜Dans l'exemple, foo est exécuté en tant qu'attribut d'obj. , obj sert de contexte à la fonction, et cela pointe vers obj. this.a est équivalent à obj.a. Dans l'appel de la chaîne de propriétés de l'objet, seul le dernier calque affectera la position appelante, ce qui signifie que le dernier calque affectera ce point. 🎜🎜De nombreux amis front-end ont peut-être vu cette question lors d'entretiens : 🎜rrreee🎜C'est le problème le plus courant avec la liaison implicite, 🎜Perte implicite : les fonctions implicitement liées perdront l'objet lié 🎜. Bien que bar soit une référence à obj.foo, elle fait en fait référence à la fonction foo elle-même. La fonction bar est un appel à une fonction indépendante. À ce stade, this pointe vers window|undefined<.> . 🎜🎜Il existe également une fonction de rappel classique, ce problème de pointage qui est également implicitement perdu. 🎜rrreee🎜Résumé : Dans la liaison implicite, lors de l'attribution de valeurs (les rappels sont des affectations implicites), vous devez accorder une attention particulière à la question de la perte implicite. 🎜🎜3. Afficher la liaison🎜🎜La fonction en JavaScript fournit deux méthodes <code>call et apply Le premier paramètre transmis est un objet, et ce sera Lié à cet objet. Si une valeur primitive (chaîne, nombre, Booléen) est transmise, elle sera convertie en sa forme objet (new String(), new Boolean(), new Number()). 🎜rrreee🎜Bien que nous puissions utiliser call et apply pour spécifier explicitement le point de ceci, il reste toujours le problème de la perte de liaison. Cela peut être résolu via ce que l'on appelle la liaison dure (fonction de liaison), je n'entrerai donc pas dans les détails ici. 🎜🎜4. new🎜🎜La dernière chose que je veux présenter est d'utiliser new pour modifier la liaison de ceci. Les chaussures pour enfants qui ont implémenté manuellement new devraient être plus claires sur new in js et new in. d'autres langues. Complètement différent. 🎜Nouveau processus d'exécution : 🎜🎜🎜Créer un objet vide 🎜🎜L'objet vide actuel effectue un ancrage du prototype 🎜🎜Renvoyer le résultat de l'exécution de la fonction ou l'objet vide actuel 🎜🎜rrreee🎜Lors de l'utilisation de new pour appeler une fonction, nous construirons un nouveau object et liez-le à ceci dans l’appel de fonction. 🎜🎜Priorité🎜🎜Enfin, parlons brièvement de la relation de priorité : nouvelle liaison d'affichage > liaison implicite > liaison par défaut. 🎜🎜Apprentissage recommandé : "🎜🎜Tutoriel sur les bases de JavaScript🎜🎜"🎜🎜🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer