La valeur du mot-clé `this` d'une fonction retournée par un getter

15

J'ai trouvé une valeur inattendue de ce mot clé dans l'exemple suivant:

let x = {
    z : 10 ,
    get func1() {
        return function(v) {
            console.log(this === v);
        }
    }
}


x.func1(x)

La valeur de ce mot clé est l'objet x comme s'il était exécuté à partir de cet objet, je m'attends à ce que seule la fonction get qui a ce mot clé soit égale à l'objet appelant x

cet exemple nous montre la différence

let x = {
    func2() {
        return function(v) {
            console.log(this === v);
        }
    }
}

x.func2()(x);

Dans les deux exemples, func1, qui est la fonction getter, et func2, qui est une méthode de l'objet, sont exécutés à partir de l'objet x , et la fonction renvoyée est ensuite exécutée. Alors pourquoi cette valeur dans le premier exemple n'est pas égale à l'objet global au lieu de l'objet x .

Kirollos Nasr
la source
3
Question vraiment, vraiment intéressante. Je n'avais jamais pensé à cette ride auparavant.
TJ Crowder
1
« Comme si elle est exécutée à partir de cet objet » - mais il est exécuté sur cet objet, là: x.func1().
Bergi

Réponses:

13

Voilà une question très intéressante.

C'est parce que la fonction est appelée immédiatement sur le résultat d'un accès à la propriété. Ce sont donc fondamentalement équivalents:

let x = {
    get func1() {
        return function(v) {
            console.log(this === v);
        };
    },
    func2(v) {
        console.log(this === v);
    }
};

x.func1(x);
x.func2(x);

Dans les deux cas:

  1. La valeur de la propriété est lue, résultant en une référence de fonction.
  2. Cette fonction est exécutée dans le cadre de la même expression d'accès à la propriété.

Le fait qu'il func1s'agisse d'une propriété d'accesseur et d' func2une propriété de données n'a pas d'importance. C'est la façon dont la valeur résultant de la lecture de la propriété est utilisée qui compte.

TJ Crowder
la source
1
Je pensais que l'expression entière serait évaluée en fonction de l'objet puis exécutée. Merci bien
Kirollos Nasr
1
@KirollosNasr Oui, c'est le cas, mais dans l'expression, x.func1il conserve la référence xcomme contexte pour l'appel suivant, contrairement à x.func2()(d'après votre question) qui évalue également une fonction mais n'est pas une expression d'accès membre.
Bergi
1
@Bergi - Je pense que tu voulais dire x.func2()(x);?
TJ Crowder
1
@TJCrowder Oui, je me réfère aux expressions à l'intérieur x.func1(x)etx.func2()(x)
Bergi
1
@Bergi oui, il a une partie délicate. Mais maintenant, c'est plus clair Merci à TJ Crowder et à vous
Kirollos Nasr