web-dev-qa-db-fra.com

Propriétés des objets de fonction Javascript

J'ai un objet de fonction JavaScript comme;

var addNum = function(num1, num2) {
        return num1 + num2;
}

Maintenant, si j'essaie d'accéder 

addNum.divide()

Je voulais comprendre la chaîne de prototypes pour le code ci-dessus. J'ai lu que dans l'exemple ci-dessus, addNum serait recherché pour divide (), suivi de Function.prototype et enfin Object.prototype. 

Mais ma question est dans l'exemple ci-dessus, comment addNum peut être recherché pour divide ()

Fait-il référence à quelque chose comme;

var addNum = function(num1, num2) {

this.divide = function(){}

            return num1 + num2;
    }

Je ne pouvais pas comprendre la ligne où il est dit que addNum serait recherché pour divide ()

S'il vous plaît aidez-moi à comprendre la même chose.

21
testndtv

Je ne suis pas sûr que cela réponde à votre question mais puisse vous donner un aperçu. Prenons l'exemple suivant:

var Person = (function () {
    var Person = function (name) {
        this.name = name;
    }

    Person.greet = function () {
        console.log("Hello!");
    }

    Person.prototype = {
        greet: function () {
            console.log('Hello, my name is ' + this.name);
        }
    };
    return Person;
})();

var bob = new Person("Bob");

Person.greet(); // logs "Hello!"
bob.greet(); // logs "Hello, my name is Bob

L'objet de fonction "Personne" a une propriété directe "saluer" qui est une fonction. En ce qui concerne la programmation orientée objet, vous pouvez presque y voir une méthode statique pouvant être appelée directement à partir de la fonction Person (Person.greet ()). Une fois que vous "instanciez" un objet personne à partir du constructeur Person, ce nouvel objet "bob" fait désormais référence à ses méthodes à partir de l'objet Person.prototype. Désormais, lorsque vous appelez bob.greet (), il utilise la fonction saluer de l'objet prototype.

J'espère que cela pourra aider.

50
Keith Morris

Comme vous le dites vous-même: vous avez une fonction objet. Les fonctions sont des objets dans JS, tout comme les littéraux d'objet, les tableaux ou autre chose: une fonction peut être affectée à des propriétés et à des méthodes à volonté:

var someAnonFunction = function(foo)
{
    console.log(this);
    console.log(this === someAnonFunction);//will be false most of the time
};
someAnonFunction.x = 123;//assign property
someAnonFunction.y = 312;
someAnonFunction.divide = function()
{
    console.log(this === someAnonFunction);//will be true most of the time
    return this.x/this.y;//divide properties x & y
};
someAnonFunction.divide();

Dans ce cas, l'objet de fonction, référencé par someAnonFunction, s'est vu attribuer une référence à la fonction anonyme, appelée divide (enfin, la référence à une fonction anonyme a été surnommée divide). Donc, il n'y a aucune implication de prototype ici. Remarquez, comme vous le dites si bien: tous les objets peuvent être remontés dans Object.prototype, essayez ceci:

console.log(someAnonFunction.toString === Function.prototype.toString);//functions are stringified differently than object literals
console.log(someAnonFunction.hasOwnProperty === Object.prototype.hasOwnProperty);//true

Ou peut-être est-ce plus clair: un schéma simple de la façon dont un appel de méthode/propriété est résolu en une valeur dans JS:

[      F.divide      ]<=========================================================\ \
F[divide] ===> JS checks instance for property divide                           | |
 /\ ||                                                                          | |
 || || --> property found @instance, return value-------------------------------| |
 || ||                                                                          | |
 || ===========> Function.prototype.divide could not be found, check prototype  | |
 ||      ||                                                                     | |
 ||      ||--> property found @Function.prototype, return-----------------------| |
 ||      ||                                                                     | |
 ||      ==========> Object.prototype.divide: not found check prototype?        | |
 ||          ||                                                                 | |
 ||          ||--> property found @Object.prototype, return---------------------|_|
 ||          ||                                                                 |=|
 ||          =======>prototype is null, return "undefined.divide"~~~~~~~~~~~~~~~|X|
 ||                                                                             \ /
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< TypeError can't read property 'x' of undefined

Il s'ensuit que si vous voulez que le code ci-dessus fonctionne avec des prototypes, vous devrez augmenter un prototype de toutes sortes (dans ce cas, le Function.prototype). Sachez que ce n'est pas à recommander, en fait, changer de prototypes "natif" est souvent mal vu. Encore:

Function.prototype.divide = function (a, b)
{
    a = +(a || 0);//coerce to number, use default value
    b = +(b || 1) || 1;//division by zeroe is not allowed, default to 1
    return a/b;
};
function someFunction ()
{
    return 'someString';
};
var another = function(a, b)
{
    return a + b;
};
someFunction.divide(12, 6);//will return 2
another.divide(12, 4);//3

Dans les deux cas, l'objet de fonction, référencé par le nom (someFunction ou another) sera analysé pour rechercher une propriété appelée divide, introuvable. Ensuite, il va scanner le Function.prototype, où une telle propriété est trouvée.
Si ce n’était pas le cas, JS vérifierait également le Object.prototype; si cela échouait, une erreur serait éventuellement générée.

J'ai posté des réponses assez longues sur SO sur ce sujet il y a quelque temps:

Qu'est-ce qui rend my.class.js si vite? (traite des prototypes de chaînes)
Objets et fonctions en javascript (récapitulation des fonctions <=> objets <=> constructeurs)
Quelles sont les différences entre ces trois modèles de définitions de "classe" en JavaScript? (quelques informations supplémentaires, encore)
Javascript - Change dynamiquement le contenu d'une fonction (touche vaguement les fonctions anonymes, assignées à des variables et à des propriétés et changeant leur contexte)

18

Vous pouvez créer divide en tant que [sorte de] static méthode:

var addNum = function(num1, num2) {
  addNum.divide = function(){return num1/num2;};
  return num1 + num2;
}
// now you first have to run addNum
var onethirds = addNum(1,3); //=> 4
addNum.divide(); //=> 0.333333...

Mais ce n'est pas conseillé. Mieux créer un constructeur fonction:

function Pair(n1,n2){
   n1 = n1 || 1;
   n2 = n2 || 1;
   // create instance methods
   this.add      = function(){return n1+n2;};
   this.divide   = function(){return n1/n2;};
   this.multiply = function(){return n1*n2;}
}
var pair1 = new Pair(2,6)
   ,pair2 = new Pair(1,2);
pair1.add();    //=> 8
pair2.divide(); //=> 0.5
//etc.

ou une approche plus prototype (des méthodes sont ajoutées au prototype du constructeur, mais pas à chaque instance):

function Pair(n1,n2){
   this.n1 = n1 || 1;
   this.n2 = n2 || 1;
   // create prototype methods (once)
   if (!Pair.prototype.add){
    var proto      = Pair.prototype;
    proto.add      = function(){return this.n1+this.n2;};
    proto.divide   = function(){return this.n1/this.n2;};
    proto.multiply = function(){return this.n1*this.n2;}
   }
}

Lire des articles

3
KooiInc

Non, votre dernier code n'a de sens que si vous avez utilisé addNum en tant que fonction constructeur:

var instance = new addNum();
instance.divide();

Toutefois, les fonctions étant des objets, les éléments suivants seraient valides:

var addNum = function(num1, num2) {
        return num1 + num2;
}
addNum.divide = function() {}

Dans ce cas, divide serait une propriété de addNum elle-même, pas d'un de ses prototypes.

2

Pour comprendre l’héritage prototype, c’est un peu obscur au début, mais considérez-le comme le nom l’indique. Il existe quelques prototypes en JavaScript et Function en fait partie.

Chaque fois que vous créez une nouvelle fonction, vous pouvez vérifier son type avec la commande typeof. Dans ton cas:

var a = function(a,b) { return a + b; }

Il renverra "function" donc il y a deux façons d'ajouter à votre variable a plusieurs méthodes. Comme le suggérait @ Keith Morris, on pourrait créer un nouveau constructeur, y insérer ses méthodes et les renvoyer. C’est également le moyen privilégié, car vous ne polluez donc pas les objets de base avec des méthodes prototypiques étendues à tous les objets qu’ils représentent.

Signification, si je fais plutôt ceci:

Function.prototype.divide = function(a, b) { return a / b; }

Je peux maintenant faire a.divide(2, 1); et il renverrait 2. Mais par exemple si j'utilise jQuery et fais jQuery.divide(2,1), j'obtiendrai également 2 car il essaiera de le trouver dans l'étendue immédiate de la fonction. Sinon, cela ira au prototype.

J'espère que cela vous l'explique un peu mieux.

0
gmaliar