Maison  >  Article  >  interface Web  >  Analyse complète de ceci en JavaScript

Analyse complète de ceci en JavaScript

韦小宝
韦小宝original
2017-11-30 10:41:301240parcourir

Les

Les objets en JavaScript sont bien sûr indispensables, et le mot clé this est indispensable ! Avec le mot-clé this, le code de JavaScript sera réduit. Aujourd'hui, nous allons analyser cela en JavaScript !

Liaison implicite

À ce sujet, de manière générale, celui qui appelle une méthode indiquera vers qui cette méthode pointe, comme :

function foo(){
    console.log(this.a)
}
var a = 3;
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 输出2,因为是obj调用的foo,所以foo的this指向了obj,而obj.a = 2

S'il y a plusieurs appels, seule la couche supérieure ou la dernière de la chaîne de référence de l'attribut de l'objet fonctionnera à l'emplacement appelant, par exemple :

function foo() {
    console.log( this.a )
}
var obj2 = { 
    a: 42,
    foo: foo
}
var obj1 = {
    a: 2,
    obj2: obj2
}
obj1.obj2.foo(); // 42

Perte implicite


L'un des problèmes de liaison les plus courants est que les fonctions implicitement liées seront perdues. Lier l'objet, ce qui signifie qu'il doit appliquer la liaison par défaut, la liant ainsi à l'objet global ou non défini, selon qu'il est en mode strict.

function foo() {
    console.log( this.a )
}
var obj1 = {
    a: 2,
    foo: foo
}
var bar = obj1.foo; // 函数别名!
var a = "oops, global"; // a是全局对象的属性
bar(); // "oops, global"

Bien que bar soit une référence à obj.foo, il fait en fait référence à la fonction foo elle-même, donc bar() à ce moment est en fait un appel de fonction sans aucune modification, donc la liaison par défaut est appliquée

Une situation plus subtile, plus courante et plus inattendue se produit lors du passage d'une fonction de rappel  :

function foo() {
    console.log( this.a )
}
function doFoo( fn ){
    // fn 其实引用的是 foo
    fn(); // <-- 调用位置!
}
var obj = {
    a: 2,
    foo: foo
}
var a = "oops, global"; // a是全局对象的属性
doFoo( obj.foo ); // "oops, global"

Le passage du paramètre est en fait une affectation implicite, donc lorsque nous passons une fonction, elle sera également implicitement attribuée, donc le résultat est le même que l'exemple précédent si la fonction est passée dans la fonction intégrée du langage au lieu de la fonction déclarée par vous-même (comme setTimeout, etc.) , le résultat est le même

Liaison explicite

Pour faire simple, précisez ceci, comme : appeler, appliquer, lier, nouveau Reliure, etc.

Reliure rigide

function foo( something ) {
    console.log( this.a, something)
    return this.a + something
}
var obj = {
    a: 2
}
var bar = function() {
    return foo.apply( obj, arguments)
}
var b = bar(3); // 2 3
console.log(b); // 5

Voici une brève explication : Dans la fonction bar, foo utilise la fonction apply pour lier obj, c'est-à-dire pour say This in foo pointera vers obj. En même temps, les arguments (aucune limite sur le nombre de paramètres transmis) sont utilisés comme paramètres et transmis à la fonction foo, donc lors de l'exécution de bar(3), obj.a est le premier ; La sortie, qui vaut 2 et 3, est transmise, puis foo renvoie la somme des deux, donc la valeur de b est 5


De même, cet exemple peut également utiliser bind:

function foo( something ) {
    console.log( this.a, something)
    return this.a + something
}
var obj = {
    a: 2
}
var bar = foo.bind(obj)
var b = bar(3); // 2 3
console.log(b); // 5

nouvelle liaison

Dans les langages traditionnels orientés classe, lors de l'utilisation de new pour initialiser une classe, le Le constructeur de la classe sera appelé , mais le nouveau mécanisme de JS est en fait complètement différent de celui orienté classe et celui orienté langage.

Utilisez new pour appeler une fonction, ou lorsqu'un appel de constructeur se produit, les opérations suivantes seront automatiquement effectuées :

Créer (ou construire) un tout nouvel objet

Ceci Le nouvel objet sera exécuté [[Prototype]] connexion

Ce nouvel objet sera lié à ceci

de l'appel de fonction Si la fonction ne renvoie pas d'autres objets, alors le nouveauexpressionLa fonction in renverra automatiquement ce nouvel objet tel que :

function foo(a){
    this.a = a
}
var bar = new foo(2);
console.log(bar.a); // 2

Lorsque nous utiliserons new pour appeler foo(…), nous construirons un nouvel objet et le lierons à l'appel foo( …) à ce sujet. new est la dernière méthode qui peut affecter le comportement de cette liaison lorsqu'une fonction est appelée. Nous l'appelons une nouvelle liaison.

C'est priorité

Il ne fait aucun doute que la priorité de la liaison par défaut est la plus basse parmi les quatre règles , nous pouvons donc l'ignorer en premier.


Lequel a une priorité plus élevée, une liaison implicite ou une liaison explicite ? Testons-le :

function foo(a){
    console.log(this.a)
}
var obj1 = {
    a: 2,
    foo: foo
}
var obj2 = {
    a: 3,
    foo: foo
}
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call(obj2); // 3
obj2.foo.call(obj1); // 2

Comme vous pouvez le voir, la liaison explicite a une priorité plus élevée, ce qui signifie que la question de savoir si une liaison explicite peut exister doit être prise en compte en premier lors du jugement.

Nous devons maintenant déterminer qui a une priorité plus élevée et laquelle a une priorité plus faible entre la nouvelle liaison et la liaison implicite :

function foo(something){
    this.a = something
}
var obj1 = {
    foo: foo
}
var obj2 = {}
obj1.foo(2); 
console.log(obj1.a); // 2
obj1.foo.call(obj2,3);
console.log(obj2.a); // 3
var bar = new obj1.foo(4)
console.log(obj1.a); // 2
console.log(bar.a); // 4

Vous pouvez voir que la nouvelle liaison a une priorité plus élevée que liaison implicite. Mais lequel a la priorité la plus élevée, une nouvelle liaison ou une liaison explicite ?

function foo(something){
    this.a = something
}
var obj1 = {}
var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2
var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3

Comme vous pouvez le voir, une nouvelle liaison modifie cela dans la liaison matérielle, donc une nouvelle liaison a une priorité plus élevée que la liaison explicite.


L'objectif principal de l'utilisation de fonctions liées matériellement dans new est de prédéfinir certains paramètres de la fonction, afin que seul le reste puisse être transmis lors de l'initialisation avec new paramètres. L'une des fonctions de bind(...) est qu'il peut transmettre tous les paramètres sauf le premier paramètre (le premier paramètre est utilisé pour le lier) à la fonction sous-jacente (cette technique est appelée « application partielle » et est un type de "curry"). Par exemple :

function foo(p1,p2){
    this.val = p1 + p2;
}
// 之所以使用null是因为在本例中我们并不关心硬绑定的this是什么
// 反正使用new时this会被修改
var bar = foo.bind(null,&#39;p1&#39;);
var baz = new bar(&#39;p2&#39;);
baz.val; // p1p2
}

Currying : Intuitivement, le currying indique que "si vous corrigez certains paramètres, vous obtiendrez une fonction qui accepte les paramètres restants". Donc pour la fonction yx à deux variables, si y = 2 est fixe, on obtient la fonction 2x à une variable

Cette application dans les fonctions fléchées

La fonction flèche n'utilise pas les quatre règles standard de ceci, mais détermine cela en fonction de la portée externe (fonction ou globale).

我们来看一下箭头函数的词法作用域:

function foo() {
    // 返回一个箭头函数
    return (a) => {
        // this继承自foo()
        console.log(this.a)
    };
}
var obj1 = {
    a: 2
};
var obj2 = {
    a: 3
};
var bar = foo.call(obj1);
bar.call(obj2); // 2, 不是3!

foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改。(new也不行!)

总结

如果要判断一个运行中的函数的this绑定,就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断this的绑定对象。

由new调用?绑定到新创建的对象。

由call或者apply(或者bind)调用?绑定到指定的对象。

由上下文对象调用?绑定到那个上下文对象。

默认:在严格模式下绑定到undefined,否则绑定到全局对象。

相关推荐:

JavaScript学习笔记之基础语法

JavaScript 是真正的 OOP 语言吗?

如何用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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn