2015-03-24 20 views
11

In passato, quando la creazione di "classi" in JavaScript, ho fatto in questo modo:confusione su come creare classi in JavaScript

function Dog(name){ 
    this.name=name; 
    this.sound = function(){ 
     return "Wuf"; 
    }; 
} 

Tuttavia, ho appena visto qualcuno fare in questo modo, invece:

var Dog = (function() { 
    function Dog(name) { 
     this.name = name; 
    } 
    Dog.prototype.sound = function() { 
     return "Wuf"; 
    }; 
    return Dog; 
})(); 

Puoi farlo in entrambi i modi, o è il modo in cui l'ho fatto male? In tal caso, perché? E qual'è esattamente la differenza tra i due in termini di ciò che finiamo con? In entrambi i casi siamo in grado di creare un oggetto dicendo:

var fido = new Dog("Fido"); 
fido.sound(); 

spero che qualcuno mi illumini.

+0

Ulteriori informazioni su come utilizzare le funzioni di costruzione e il prototipo possono essere trovate qui: http://stackoverflow.com/a/16063711/1641941 spero che aiuti – HMR

risposta

15

Ci sono due importanti differenze tra la tua strada e la loro.

  1. Wrapping in una funzione di auto invocando ((function() { ... })();)
  2. Usando la proprietà .prototype sopra this. per i metodi.

cose confezionamento in una funzione di auto chiamante, assegnando il risultato (come definito nel return dichiarazione di una variabile è chiamato module pattern. E 'un modello comune per assicurare portata è più controllata.

Uso Dog.prototype.sound = function() {} è preferibile a this.sound = function(). la differenza è che Dog.prototype.sound è definita una volta per tutti gli oggetti con il costruttore Dog, e il this.sound = function() {} è definito nuovamente per ciascun oggetto Dog creato.

La regola generale è: le cose che sono individuali per un oggetto (di solito le sue proprietà) devono essere definite su this, mentre le cose che sono condivise con tutti gli oggetti dello stesso tipo (di solito funzioni) devono essere definite su il prototipo.

4

Con il tuo codice, stai creando una nuova funzione sound per ogni nuova istanza Dog che viene creata. Javascript prototype evita questo creando solo una singola funzione condivisa da tutte le istanze dell'oggetto; eredità fondamentalmente classica.

Nel secondo codice che si sta visualizzando è appena stato aggiunto in un IIFE, cosa che in questo caso non fa molto.

3

Il primo è il tradizionale metodo di creazione di un costruttore. Il secondo un'espressione di funzione immediatamente richiamata che restituisce un costruttore. Questo metodo ti consente di mantenere le variabili all'interno del modulo senza uscire dall'ambito globale che potrebbe costituire un problema.

E qual è esattamente la differenza tra i due in termini di ciò che ci ritroviamo?

Entrambi, come hai visto, hanno lo stesso risultato. Gli altri hanno parlato di prototype quindi non ne parlerò qui.

+0

C'è una piccola differenza nel risultato. Il secondo esempio può essere considerato migliore a causa dell'uso di 'prototipo'. –

+1

Non vale davvero un downvote tho, vero? – Andy

+0

No, non ero io però. –

2

Il secondo è preferibile perché sfrutta il meccanismo di ereditarietà prototipale di Javascript.

Prototipi

Javascript eredità è una causa di confusione, ma in realtà è abbastanza semplice: ogni oggetto ha un prototipo, che è un oggetto che si provvederà a controllare quando cerchiamo di accedere a una proprietà non sull'originale oggetto. Il prototipo avrà, di per sé, un prototipo; in un caso semplice, come Dog, questo sarà probabilmente Object.prototype.

In entrambi gli esempi, a causa di come newoperator works, avremo una catena prototipo simile a questa: fido->Dog.prototype->Object.prototype. Quindi, se proviamo a cercare la proprietà name su Fido, lo troveremo proprio lì sull'oggetto. Se, invece, cerchiamo la proprietà hasOwnProperty, non riusciremo a trovarla su Fido, non la troveremo su Dog.prototype, quindi raggiungiamo lo Object.prototype, dove lo troveremo.

Nel caso di sound, gli esempi lo definiscono in due diversi punti: nel primo caso, fido e ogni altro cane che creiamo avrà una propria copia della funzione. Nel secondo caso, Dog.prototype avrà una singola copia della funzione, a cui i singoli cani accederanno quando viene chiamato il metodo. Ciò evita sprechi di risorse per la memorizzazione di duplicati della funzione sound.

Significa anche che possiamo estendere la catena del prototipo; forse vogliamo una classe Corgi che erediti la funzione sound da Dog. Nel secondo caso, possiamo semplicemente assicurare che Dog.prototype sia nella catena di prototipi di Corgi.prototype; nel primo, avremmo bisogno di creare un cane reale e inserirlo nella catena del prototipo.