web-dev-qa-db-fra.com

javascript: fonction et objet ...?

Pouvez-vous appeler une fonction en tant qu'objet? Par exemple:

function Tip(txt){      
    this.content = txt;  
    this.shown = false;  
}

Et:

var tip = new Tip(elem.attr('title'));

Mes questions: 

  1. Pouvez-vous appeler new pour une fonction, comme pour un objet? 
  2. L'utilisation de "ceci" est rendue possible, car nous utilisons cette fonction en tant qu'objet?
41
Paul

Vous recherchez le concept constructor .

Toutes les fonctions en JavaScript sont des objets et peuvent être utilisées pour créer des objets:

function make_person(firstname, lastname, age) {
    person = {};
    person.firstname = firstname;
    person.lastname = lastname;
    person.age = age;
    return person;
}
make_person("Joe", "Smith", 23);
// {firstname: "Joe", lastname: "Smith", age: 23}

Cependant, afin de créer de nouveaux objets d’un type particulier (c’est-à-dire qui héritent d’un prototype, d’un constructeur, etc.), une fonction peut référencer this et si elle est appelée avec l’opérateur new il retournera ensuite un objet avec tous les attributs définis sur this dans la fonction - this, dans ce cas, il fait référence au nouvel objet que nous créons.

function make_person_object(firstname, lastname, age) {
    this.firstname = firstname;
    this.lastname = lastname;
    this.age = age;
    // Note, we did not include a return statement
}

La principale différence entre make_person et make_person_object est de noter que l'appel de new make_person() (par opposition à simplement make_person()) ne fera rien de différent ... les deux produiront le même objet. Toutefois, l'appel de make_person_object() sans l'opérateur new définira vos attributs this sur l'objet this actuel (généralement window si vous utilisez le navigateur.)

Ainsi:

var Joe = make_person_object("Joe", "Smith", 23);
console.log(Joe); // undefined
console.log(window.firstname) // "Joe" (oops)

var John = new make_person_object("John", "Smith", 45);
console.log(John); // {firstname: "John", lastname: "Smith", age: 45}

En outre, comme @RobG le fait remarquer, cette façon de faire crée une référence à la propriété prototype de make_person_object sur chaque "Personne" que nous créons. Cela nous permet d’ajouter des méthodes et des attributs aux personnes après coup:

 // Assuming all that came before
make_person_object.prototype.full_name = "N/A";
make_person_object.prototype.greet = function(){ 
    console.log("Hello! I'm", this.full_name, "Call me", this.firstname); 
};
John.full_name // "N/A"
John.full_name = "John Smith"; 
make_person_object.full_name // Still "N/A"
John.greet(); // "Hello! I'm John Smith Call me John"

Selon la convention, les fonctions de constructeur telles que make_person_object sont capitalisées, singularisées et "nommées" (faute d'un meilleur terme) - nous aurions donc un constructeur Person, plutôt qu'un make_person_object qui pourrait être confondu avec une fonction ordinaire.

Voir également: 

119
Sean Vieira

Chaque fonction a une référence à this. Si vous appelez Tip(), this fera référence à l'objet global. Si vous appelez new Tip(), un nouvel objet avec une référence à Tip.prototype est créé et this fera référence à ce nouvel objet.

Vous ne pouvez pas utiliser new sur des objets, par exemple new {} jette TypeError: object is not a function. Si vous vous référez à new Object() alors cela fonctionne puisque Object est une fonction.

17
Adam Bergmark

Oui. En JavaScript, techniquement, tout est un objet. Lorsque vous utilisez new, il crée une instance de l'objet Tip, puis appelle la fonction Tip comme s'il s'agissait d'un constructeur.

Si vous souhaitez ajouter des fonctions à l'objet Tip, vous devez les ajouter au prototype de Tip comme suit:

Tip.prototype.getContent = function() {
    return this.content;
};

Si vous en avez et que vous faites alors:

var tip = new Tip("this  is my content.");
alert(tip.getContent());

Il affichera un message disant "ceci est mon contenu".

Cependant, vous ne pouvez utiliser new que si l'objet a une implémentation fonctionnelle. Donc ça ne marchera pas:

var Tip = { content: txt, show: false };
var tipObj = new Tip();
6
Tom Chandler

J'ai eu du mal à comprendre ces concepts (fonctions en tant qu'objets, objets prototypes, propriété __proto__, propriété constructeur) pendant près de 8 ans (2008-2016). J'ai d'abord créé David Flanagan "JavaScript Definitive Guide 5/6th ed" pendant 4 à 5 ans après plusieurs lectures des chapitres 6,8,9; cela n’a aucun sens pour moi mais après avoir lutté sur Internet, je suis capable de gérer des fonctions (fonction typique C++ avec des propriétés) en tant qu’objets; car objet peut aussi avoir des méthodes. Et heureusement, en 7e année 2015, j'ai lancé Wrox Nicholas C. Zakas "JavaScript professionnel pour les développeurs Web, 3e édition", chapitre 6,7; et il était vraiment très utile de comprendre les quatre concepts ci-dessus. Traditionnellement, en C/C++/C #, les fonctions sont considérées comme permettant de modifier un objet; ou en d'autres termes, ils sont conçus pour le "faire quelque chose" alors que les objets sont conçus pour conserver l'état du contexte d'exécution global avec des méthodes permettant de modifier son propre état d'objet. Donc, si les fonctions peuvent être des objets de première classe, alors pourquoi les objets ne peuvent pas être comme des fonctions?

La principale question clé ici devrait être pourquoi? Pourquoi pas une seule entité conceptuelle comme "fonction associative" ou "arguments chaînés"? Et voici ma compréhension: Browser Exe est une application à un seul thread et cet exe contrôle l'appel de l'interpréteur JS avec une chaîne d'étendue prédéfinie (certaines ressemblant à une chaîne de commandes avec des arguments); maintenant, au moment de l'exécution, le moteur JS (non interprète) charge le code de manière ascendante (car il n'y a pas de méthode principale, il faut donc élever les codes à mots-clés bien définis et leur appel). Dans ce code, si les fonctions ne sont pas traitées en tant qu'objets, elles doivent être gérées sur un contexte d'appel distinct (en dehors de la chaîne d'étendue), ce qui est facilement possible dans c/c ++/c # (bcoz à mémoire vive et mémoire illimitée), mais pas dans JS. . Par conséquent, "à faire sur un objet chaîné" fait qu'un script Java fonctionne comme un objet de première classe. En fait, les objets JS font également la même chose; la seule différence est que "l'appel d'un objet" n'existe pas dans les objets où, comme "l'appel d'une fonction", un contexte chaîné ayant un sens. Les fonctions peuvent également être considérées comme "un groupe de variables avec des instructions en langage d'assemblage avec un lien d'adresse (chaîne)". La partie de liaison est un autre côté de l’histoire comme la liaison haut-> bas (objet prototype) vs la liaison bas-> haut (propriété __ proto__) vs objet bleu print-> instances d’objet (propriété constructeur). Il y a quelques mois, j'ai trouvé que l'image suivante était utile pour comprendre les liens.

http://judis.me/wordpress/wp-content/uploads/2015/08/JavaScriptDiagram.png "Modèle d'objet JS"

3
Saurabh

La fonction agit en tant que constructeur sur une classe. Alternativement, vous pouvez faire:

function Tip(txt) {
 return {
 content: txt,
 shown: false
}
}

et obtenez une nouvelle instance avec: var myTip = new Tip("my epic tip"); Ceci est similaire à, disons, c #:

public class Tip {
string text = "";
public Tip(string txt) {
text = txt;
}
}

Donc, en quelque sorte. 1) Vous appelez new puisque la fonction agit essentiellement en tant que classe et 2) this fait référence à l'instance actuelle de la classe. 

1
Thomas Shields

pour # 1: Il y a un objet appelé Function (majuscule F)

var f = nouvelle fonction ("x", "y", "renvoyer x * y;");

pour # 2: le "ceci" est différent selon le modèle d'invocation (comme l'a nommé Douglas Crockford). Crockford dit qu'il y a 4 modèles (modèle de méthode, modèle de fonction, modèle de constructeur et modèle "appliquer")

1
user670800
  1. En fait, tous les types de données comme les fonctions de tableau sont des objets.
  2. Lorsque nous prenons la fonction comme une déclaration de classe, cela fonctionne.
0
xblymmx