2009-12-02 4 views
0
var utils = function() { 
    function getMyPrivateName() { 
     return "Caoimhin"; 
    } 
    return { 
     messages: { 
      getMyPublicName: function getMyPublicName() { 
       return "Kevin"; 
      }, 
      sayHello: function() { 
       document.writeln("hello " + getMyPublicName() + "<br/>"); 
       document.writeln("hello " + getMyPrivateName() + "<br/>"); 
      } 
     } 
    }; 
}(); 

utils.messages.sayHello(); 

Je joue avec les espaces de noms javascript et j'ai rencontré un comportement inattendu. Je développe principalement dans IE car c'est le navigateur cible pour notre application intranet.Javascript + namespacing + numéro FF

Dans IE ce qui précède, lorsqu'il est inclus sur une page blanche, sorties:

hello Kevin
hello Caoimhin

Dans FF le script rencontre une erreur:

getMyPublicName is not defined

Si je commente la ligne incriminée:

//document.writeln("hello " + getMyPublicName() + "<br/>"); 

Sorties FF:

hello Caoimhin

Je sais que cela peut accéder à la fonction privée ...

Quelqu'un peut-il expliquer pourquoi cela se produit? Et ce que je dois faire pour avoir une solution cross navigateur similaire à celui ci-dessus ..

Je sais que je pourrais écrire quelque chose comme:

document.writeln("hello " + utils.messages.getMyPublicName() + "<br/>"); 

mais je préfère ne pas ....

Merci à l'avance, Kevin

Répondre

5

Vous avez trébuché sur un bogue dans le langage JScript utilisé par IE.

getMyPublicName: function getMyPublicName() { 
    ... 
}, 

La valeur function getMyPublicName() est ici une expression de fonction en ligne qui a été donné un identifiant en option getMyPublicName qui est le même que son nom de propriété du propriétaire. (sayHello omet cet identifiant.)

Qu'est-ce que l'identifiant en option doit faire selon la norme ECMAScript est faire référence à la fonction visible dans le champ d'application du corps de la fonction elle-même, sous le nom d'identification getMyPublicName. Cela pourrait être utilisé pour faire une fonction inline anonyme qui se réfère à elle-même (pour la récursivité).

Qu'est-ce qu'il fait fait dans IE, à tort, est de rendre la fonction visible sous le nom getMyPublicName dans le champ parent (la fonction utils). Parce qu'il est visible dans cette portée, il devient également visible pour la portée enfant de la fonction sayHello, ce qui fait que votre code fonctionne quand il ne devrait pas, vraiment.

Vous pouvez utiliser this. pour obtenir la référence à getMyPublicName correctement, comme suggéré par Dustin. Sinon, si vous voulez éviter les problèmes de this -binding en JavaScript (par exemple parce que vous allez passer la fonction sayHello en tant que délégué à un délai ou à un événement), vous préférerez peut-être mettre les fonctions publiques dans la portée parent:

var utils = function() { 
    function getMyPrivateName() { 
     return "Caoimhin"; 
    } 
    function getMyPublicName() { 
     return "Kevin"; 
    } 
    function sayHello() { 
     document.writeln("hello " + getMyPublicName() + "<br/>"); 
     document.writeln("hello " + getMyPrivateName() + "<br/>"); 
    } 
    return { 
     messages: { 
      getMyPublicName: getMyPublicName, 
      sayHello: sayHello, 
     } 
    } 
}(); 
+0

Merci pour l'explication détaillée, quelques bonnes informations ici pour moi. – Kevin

2

Il est une question de portée:

var utils = function() { 
    function getMyPrivateName() { 
     return "Caoimhin"; 
    } 
    return { 
     messages: { 
      getMyPublicName: function() { 
       return "Kevin"; 
      }, 
      sayHello: function() { 
       document.writeln("hello " + this.getMyPublicName() + "<br/>"); 
       document.writeln("hello " + getMyPrivateName() + "<br/>"); 
      } 
     } 
    }; 
}(); 

utils.messages.sayHello(); 
4

Le comportement de Firefox est conforme, car une définition de fonction dans un initiateur d'objet est une expression de fonction et pas une déclaration de fonction .

ECMA-262, 3e édition, l'article 13:

The Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.

Je suggère de déplacer la définition de la initialiseur d'objet:

+0

Merci d'avoir répondu si bien – Kevin

0

Une façon de le faire est:

var utils = function() { 
    var getMyPrivateName = function() { 
     return "Caoimhin"; 
    }; 

    var self = { 
     getMyPublicName: function() { 
      return "Kevin"; 
     }, 
     sayHello: function() { 
      document.writeln("hello " + getMyPublicName() + "<br/>"); 
      document.writeln("hello " + self.getMyPrivateName() + "<br/>"); 
     }; 

    return self; 
}();