Quando utilizzare la programmazione prototipica in JavaScript

15

Ho trascorso un bel po 'di tempo a sviluppare semplici widget per i progetti nel modo seguente:

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

Ma ho iniziato a cambiare il mio formato al seguente:

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

Certo, questi sono esempi stupidi, quindi non essere avvolto attorno all'asse. Ma qual è la differenza funzionale e quando dovrei scegliere l'una o l'altra?

    
posta JDillon522 13.02.2015 - 20:57
fonte

1 risposta

6

La prima differenza può essere riassunta come: this si riferisce all'istanza della classe. prototype si riferisce a Definizione .

Diciamo che abbiamo la seguente classe:

var Flight = function ( number ) { this.number = number; };

Quindi, qui stiamo associando this.number a ogni istanza della classe e ha senso perché ogni Flight deve avere il proprio numero di volo.

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

Al contrario, prototype definisce una singola proprietà a cui è possibile accedere da tutte le istanze.

Ora, se vogliamo ottenere il numero di volo, possiamo semplicemente scrivere il seguente frammento e tutte le nostre istanze avranno un riferimento a questo oggetto appena prototipato.

Flight.prototype.getNumber = function () { return this.number; };

La seconda differenza riguarda il modo in cui JavaScript cerca una proprietà di un oggetto. Quando stai cercando Object.whatever , JavaScript arriva fino all'oggetto Oggetto principale (l'oggetto da cui tutto il resto ha ereditato) e non appena trova una corrispondenza verrà restituito o chiamalo.

Ma ciò accade solo per le proprietà prototipate. Pertanto, se hai un livello superiore dithis.whatever in più, JavaScript non lo considererà una corrispondenza e continuerà la ricerca.

Vediamo come succede nella realtà.

Prima nota che [quasi] tutto è Oggetti in JavaScript. Prova questo:

typeof null

Ora vediamo cosa c'è dentro un Object (annota il% maiuscolo% co_de e il O alla fine). Negli Strumenti per sviluppatori di Google Chrome quando inserisci . otterrai un elenco di proprietà disponibili all'interno dell'oggetto specifico.

Object.

Ora fai la stessa cosa per . :

Function.

Potresti notare il metodo Function . Basta andare, accenderlo e vediamo cosa succede:

Object.name
Function.name

Ora creiamo una funzione:

var myFunc = function () {};

E vediamo anche qui il metodo name :

myFunc.name

Dovresti ottenere una stringa vuota, ma va bene. Non dovresti ricevere un errore o un'eccezione.

Ora aggiungiamo qualcosa a quel dio-come name e vediamo se lo otteniamo anche in altri posti?

Object.prototype.test = "Okay!";

Ed ecco qua:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

In tutti i casi dovresti vedere Object .

Per quanto riguarda i pro e i contro di ogni metodo, puoi considerare la prototipazione come un modo "più efficiente" di fare le cose, poiché mantiene un riferimento su ogni istanza piuttosto che copiare l'intera proprietà in ogni oggetto. D'altra parte è un esempio di Accoppiamento stretto che è un grande no-no fino a quando non si può davvero giustificare il motivo. "Okay!" è molto più complicato dal momento che è rilevante per il contesto. Puoi trovare molte buone risorse gratuitamente in Internet.

Ciò detto, entrambi i modi sono solo strumenti linguistici e dipendono davvero da te e dal problema che stai cercando di risolvere per scegliere ciò che si adatta meglio.

Se è necessario che una proprietà sia pertinente per ogni istanza di una classe, utilizzare this . Se è necessario disporre di una proprietà per funzionare allo stesso modo su ogni istanza, utilizzare this .

Aggiorna

Per quanto riguarda i frammenti di esempio, il primo è un esempio di Singleton , quindi ha senso utilizzare prototype nel corpo dell'oggetto. Puoi anche migliorare il tuo esempio rendendolo modulare come questo (e non devi usare sempre this ).

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

Il tuo secondo snippet non ha molto senso perché in primo luogo stai utilizzando this e in seguito stai tentando di modificarlo con this , che non funziona perché prototype ha la priorità su this . Non sono sicuro di quali fossero le tue aspettative da quel pezzo di codice e di come funzionava, ma ti raccomando caldamente di refactoring.

Aggiorna

Elaborare su prototype prendendo la precedenza su this Posso mostrarti un esempio e dirti come può essere spiegato, ma non ho alcuna risorsa esterna per eseguirne il backup.

L'esempio è molto semplice:

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

La spiegazione è, come sappiamo, prototype è rilevante per il contesto. Quindi non verrà all'esistenza finché il contesto non sarà pronto. Quando il contesto è pronto? Quando viene creata la nuova istanza! Dovresti indovinare il resto ora! Significa che anche se esiste una definizione this , ma prototype ha più senso per avere la precedenza perché è tutto incentrato sulla nuova istanza creata in quel momento.

    
risposta data 17.02.2015 - 10:55
fonte

Leggi altre domande sui tag