2010-02-19 2 views
9

Il semble que lorsque vous utilisez un type primitif (chaîne, nombre) comme objet this d'un appel de fonction (en tant que premier argument de function.call() ou de function apply()), le type primitif est promu à son objet équivalent (par exemple, une chaîne se transforme en chaîne).Pourquoi javascript change-t-il les types primitifs lorsqu'il est passé dans function.apply() ou function.call()?

À titre d'illustration:

var f = function(x) { return [typeof(this), typeof(x)]; } 
var obj = '123' 
f.call(obj, obj) 
>>> ["object", "string"] 

C'est, « ce » devient un objet (il est un objet de chaîne, je l'ai vérifié) tandis que le second argument pour appeler devient le premier argument de la fonction « f » et reste une chaîne primitive.

Les objets sont à la fois "123", mais les choses subtiles ne fonctionnent pas (par exemple, ils sont égaux en termes de "==" mais pas en termes de "===").

J'ai remarqué ce comportement dans Chrome et Firefox, donc je suppose qu'il y a une raison spécifique pour cela. J'ai cherché, mais je n'ai trouvé aucune explication. J'apprécierais toute explication, j'espère avec une sorte de lien vers la documentation expliquant les règles autour de cela et pourquoi cela se produit.

Répondre

10

Cela semble être le comportement correct.

http://bclary.com/2004/11/07/#a-15.3.4.4

Function.prototype.call - La fonction appelée est transmise ToObject (thisArg) en tant que cette valeur.

ToObject « convertit son argument en une valeur de type objet selon les critères suivants »:

String - Créer un nouvel objet String dont la propriété [[valeur]] est réglée sur la valeur de la chaîne.

+0

Vraiment bien trouver J-P. Question très intéressante (et réponse ofc). Un moins WTF JavaScript pour moi atleast =) – anddoutoi

+0

Non seulement cela semble être juste, mais c'est tout à fait exact. Excellente source. –

+0

Ahh, merci beaucoup! Je suis curieux de savoir pourquoi toObject() est appelé, mais je ne suppose pas que le raisonnement soit dans la spécification n'importe où. Je me souviens avoir lu quelque part que les méthodes sur les chaînes primitives sont résolues en les convertissant temporairement en objet String et en retour, donc c'est vraisemblablement un cas similaire ... – gfxmonk

2

Premier paramètre de l'appel de fonction Javascript & Les méthodes Apply déterminent dans quel contexte la fonction demandée doit être exécutée. Donc, ce sera toujours un objet

Pour illustrer cela, checkout l'exemple ci-dessous

function totest() 
{ 
    this.ff = function(x) { 
     this.test(x); 
    }; 

    this.test = function(x) { 
     alert(x); 
    } 

} 

function totest1() 
{ 
this.test = function(x) { 
    alert(x); 
} 

} 

function fun() 
{ 
    var obj = new totest(); 
    var obj1 = new totest1(); 
    obj.ff('hi'); //Runs fine without any problem 
    obj.ff.call(obj, 'sam') ; //Runs fine without any problem 
    obj.ff.call(this, 'sam'); //throws an error 
    obj.ff.call(obj1, 'sam'); //will be executed in the context of totest1 

} 

obj.ff.call (this, 'sam') renvoie une erreur. Parce que nous spécifions la méthode obj.ff à exécuter dans le contexte de fun (ou une fenêtre ici) pas dans le contexte de totest. Obj.ff.call (obj1, 'sam') indique à l'appel d'exécuter ff avec dans le contexte de totest1(), et cela fonctionne depuis le test de la méthode.

donc cela doit être objet.

Et les paramètres restants dans la méthode d'appel sont réels pour la méthode à exécuter. Donc, ils déduiront le type de la valeur donnée.

espérons que vous pouvez comprendre maintenant

+0

la cause de l'erreur de type dans ce cas est parce que le 'ff' La fonction appelle 'this.test'. Dans 'fun', la valeur de' this' est définie sur l'objet global 'window' (qui est la valeur par défaut de' this' dans une fonction normale). Donc 'ff' est appelé avec' this' égal à 'window', et l'objet window n'a simplement pas de méthode appelée' test'. – gfxmonk

+0

@gfxmonk, oui en effet .. cela signifie que param1 dans la méthode d'appel doit être un objet, donc il peut appeler la méthode ff avec dans le contexte de l'objet param1. C'est la raison pour laquelle toutes les valeurs de type (qu'il s'agisse d'un type primitif ou non) affectées à param1 seront converties en objet. J'ai mis à jour une réponse avec une autre fonction. pls vérifier – RameshVel

0

court et simple: Le premier paramètre est transformé en un objet au cas où il est d'un type primitif parce que, comme vous l'avez dit, il pourrait être désigné par this dans l'appelé fonction. Comme this doit faire référence à un objet, l'environnement d'exécution s'assure qu'il y a réellement un objet auquel se référer. Réfléchissez à la façon dont vous le mettrez en œuvre et vous arriverez probablement à la même conclusion. Bonne question.

P.S .: J'apprécie la réponse de Ramesh, qui est techniquement illustrative, mais qui voulait ajouter une réponse pour le lecteur impatient.

Questions connexes