2010-04-23 35 views
8

questo è uno dei più caratteristica mistero in JavaScript, dopo aver assegnato il metodo oggetto da altra variabile, il legame (questa parola chiave) è persofunzione JavaScript vincolante (questa parola chiave) è perso dopo l'assegnazione

var john = { 
    name: 'John', 
    greet: function(person) { 
    alert("Hi " + person + ", my name is " + this.name); 
    } 
}; 

john.greet("Mark"); // Hi Mark, my name is John 

var fx = john.greet; 
fx("Mark"); // Hi Mark, my name is 

mia domanda è:

1) cosa sta succedendo dietro l'incarico? var fx = john.greet; è questa copia per valore o copia per riferimento? fx e john.greet puntano a due diverse funzioni, giusto?

2) poiché fx è un metodo globale, la catena di ambito contiene solo l'oggetto globale. qual è il valore di questa proprietà in Oggetto variabile?

+0

Il binding non è "perso" - non è mai stato lì in primo luogo. In qualsiasi espressione JavaScript 'foo.bar()', 'this' nel contesto della funzione' bar() 'sarà' foo', indipendentemente da dove è stato dichiarato 'bar' o da come è stato associato a' foo '. –

risposta

5

1) fx e john.greet riferiamo allo stesso oggetto funzione, l'operazione di assegnazione di oggetti, opere per riferimento.

Per valori primitivi, come String, Number, Booleanundefined o null, verrà presa una copia del valore.

2) Il valore this si riferisce all'oggetto globale.

Il valore this non è una proprietà del Variable Object e non ha nulla a che fare con la catena ambito, è una parola riservata speciale, ed è determinato implicitamente quando un function is called (è anche possibile impostare in modo esplicito tramite call o apply).

JavaScript gestisce internamente un Reference type, che consiste di due componenti, l'oggetto di base e il nome struttura, quando viene richiamata una funzione, il valore this è determinato implicitamente ottenendo l'oggetto di base (dal funzionamento interno GetValue).

E, infine, l'ultimo caso in cui this è impostato in modo implicito è quando si richiama una funzione con l'operatore new, la parola chiave this farà riferimento a un oggetto appena creato.

Così in breve, ecco come funziona thisimplicitamente:

1- Quando una funzione viene richiamata come metodo (la funzione è invocata come membro di un oggetto):

obj.method(); // 'this' inside method will refer to obj 

2- normale chiamata di funzione:

myFunction(); // 'this' inside the function will refer to the Global object 
// or 
(function() {})(); 

3- Quando t egli new operatore viene utilizzato:

var obj = new MyObj(); // 'this' will refer to a newly created object. 
3

A quanto ho capito, si assegna questo metodo solo alla variabile "fx". Il contesto dell'oggetto john non lo accompagna.

In cima alla mia testa, "questo" nel contesto di fx farà riferimento all'oggetto globale, che nel contesto di un browser è (credo) equivalente all'oggetto della finestra.

(editing per chiarire oggetto globale. Una specie di)

+0

Esatto, poiché l'oggetto globale è 'window', quindi un' pippo 'non qualificato significa sempre 'window.foo' (a meno che non lo si abbia spaziato localmente usando' var'). –

+0

questo si riferirà a qualunque cosa stia chiamando il metodo, implicitamente o esplicitamente con 'call' o' apply'. –

13

john.greet("Mark") chiama in realtà una funzione. Quando si esegue var fx = john.greet;, si ottiene un riferimento alla funzione. Quindi quando lo chiami, this non è legato a john. Quello che stai facendo in realtà è window.fx("Mark") e quindi this è l'oggetto window. Eri sulla strada giusta quando hai detto che era nel contesto globale. In questa particolare istanza, l'oggetto globale è window e quindi fx è in realtà window.fx.

Se si dispone di un riferimento di funzione, è necessario utilizzare call o apply se si desidera impostare il valore di this. Prova a fare questo:

fx.call(john, "Mark"); 

Il primo argomento in call o apply è il valore utilizzato per this nel contesto della chiamata di funzione.

EDIT

Alcune persone detto che il vero problema qui potrebbe essere confusione che circonda un oggetto letterale contro un'istanza di un oggetto. Stai creando un oggetto letterale che si comporta anche come un singleton. Non è possibile creare una nuova istanza di quell'oggetto. In questo caso, john è un riferimento a tale oggetto letterale. In questo contesto, this nella funzione greet fa riferimento all'oggetto letterale stesso. Quindi quando si chiama john.greet("Mark"), this è legato a john.

quando si impugna un riferimento a john.greet basta da solo e di assegnarlo a una variabile globale, si sta essenzialmente facendo questo:

var fx = function(person) { 
    alert("Hi " + person + ", my name is " + this.name); 
} 

In questo scenario, è thiswindow, perché fx è fondamentalmente window.fx (Poiché l'oggetto globale è window. Supponendo che questo codice sia stato incluso all'interno di un'altra funzione, l'oggetto globale farebbe riferimento a tale funzione.

Se si desidera creare più istanze di un oggetto, si può fare qualcosa di simile:

var Person = function(name) { 
    var self = this; //maintains a reference to the instance 

    this.name = name; 
    this.greet = function(name) { 
     alert("Hi " + name + ", my name is " + self.name); 
    } 
} 

var john = new Person("John"); 
john.greet("Mark"); // alerts "Hi Mark, my name is John" 

var fx = john.greet; 
fx("Mark"); // also alerts "Hi Mark, my name is John" 

Qui, la variabile self (che è locale alla funzione) mantiene un riferimento all'istanza reale perché sei legandolo a this quando si crea l'oggetto.

Esistono molte best practice associate a OOP in Javascript. Puoi Google e scoprire (ci sono molti link). Consiglio soprattutto di leggere roba da Douglas Crockford.

+0

+1 per la spiegazione della funzione 'call'. –

+0

sì, buona menzione di.call, che in realtà risolverà il problema 8) – Funkatron

+0

@funkatron - il problema è molto più profondo del modo in cui viene chiamato il metodo. Rispondere a una domanda come scritta è una buona pratica. Essere in grado di determinare quando l'interrogante non comprende la propria domanda o il problema è anche un bene. –

1

Perché si sta impostando solo fx al metodo salutare e non l'intero oggetto John, non ha alcun concetto di suo genitore e diventa un ambito globale. Quindi, in sostanza, sta passando per valore in quanto in solo copia il metodo.

Poiché la funzione è ora globale, "this" diventa l'oggetto Window.

Se si imposta fx su john, si ottiene ciò che è previsto.

var john = { 
    name: 'John', 
    greet: function(person) { 
    alert("Hi " + person + ", my name is " + this.name); 
    } 
}; 

john.greet("Mark"); // Hi Mark, my name is John 

var fx = john; 
fx.greet("Mark"); // Hi Mark, my name is John 
0

ispirato da @Vivin risposta Paliath, in realtà io ne escono qualcosa di nuovo. Per quanto mi riguarda, cerco sempre di fare del mio meglio per programmare javascript allo stesso modo di java, specialmente in OOP.

Quindi il mio suggerimento è quello di evitare l'uso di questo possibile come possiamo, quando abbiamo prima facciamo

var self = this; 

dovremmo usare auto al posto di questa a tutte le funzioni (prototipo di funzione, di sorta), ma se scriviamo qualcosa di simile:

function MyObject = { 
    var self = this; 
}; 

MyObject.prototype = { 
    method1 = function(data){ 
     self.data = data; 
    } 
} 

questo non funzionera ', perché prototipo è un oggetto in MyObject, non può accedere privato membro self di proprietà di MyObject. La mia soluzione è semplice:

function MyObject = { 
    var self = this; 
    MyObject.prototype.method1 = function(data){ 
     self.data = data; 
    }; 
} 

Questa prende il vantaggio di efficienza del prototipo e anche noi non c'è bisogno di preoccuparsi di tutti i questo problemi. Anche se inseriremo un sacco di cose MyObject.prototype.xxxx.

Se questa utile ai vostri ragazzi, si prega di darmi qualche pollice in su, così ho potuto capire 15 reputazione a pollice in su altri, grazie.

Problemi correlati