2009-09-29 2 views
32

Mi chiedevo se qualcuno ha un buon esempio funzionante di un riferimento circolare in javascript? So che questo è incredibilmente facile da fare con le chiusure, ma ho avuto difficoltà a sistemare il mio cervello attorno a questo. Un esempio che posso analizzare in Firebug sarebbe molto apprezzato.Esempio di riferimento circolare in Javascript?

Grazie

+0

Grazie per le risposte; Riesco a vedere l'esempio di Josh che accade in un'app di produzione in cui potrei avere molti eventi associati. Mi piacerebbe evitare che questa perdita si verifichi sui miei client che eseguono IE6. Correggetemi se ho torto ma questo è solo un problema con i browser IE6 e seguenti? La maggior parte dei browser moderni implementa un garbage collector in grado di trovare questo tipo di riferimenti? – MatthewJ

risposta

41

Un modo semplice per creare un riferimento circolare è quello di avere un oggetto che si riferisce a se stesso in una proprietà:

function Foo() { 
    this.abc = "Hello"; 
    this.circular = this; 
} 

var foo = new Foo(); 
alert(foo.circular.circular.circular.circular.circular.abc); 

Qui l'oggetto foo contiene un riferimento ad essa.

Con chiusure questo è solitamente più implicito, da solo avere il riferimento circolare portata, non come una proprietà esplicita di un oggetto:

var circular; 

circular = function(arg) { 
    if (arg) { 
    alert(arg); 
    } 
    else { 
    // refers to the |circular| variable, and by that to itself. 
    circular("No argument"); 
    } 
} 

circular("hello"); 
circular(); 

Qui la funzione memorizzata in circular riferisce alla variabile circular, e quindi a se stesso. Contiene implicitamente un riferimento a se stesso, creando un riferimento circolare. Anche se circular ora esce dall'ambito, viene comunque fatto riferimento dall'ambito delle funzioni. I semplici garbage collector non riconoscono questo ciclo e non raccoglieranno la funzione.

+0

Grazie per la spiegazione sth. È un esempio molto semplice che è facile da capire. – MatthewJ

+0

Qual è il vantaggio di "I garbage collector semplici non riconoscono questo ciclo e non raccoglieranno la funzione"? Nel tuo esempio qui, significa che 'circular' è sempre accessibile e può essere aggiornato? Chiedo perché la mia API ha un oggetto circolare che trasporta il contesto della transazione del database, quindi sembra che sarebbe stato aggiornato sempre con nuove informazioni di contesto, quindi evitare la garbage collection sembra un buon piano. Sono vicino? – agm1984

+0

E solo per alcune informazioni extra complete, ho notato che genera un errore di riferimento circolare se provo a eseguire un'istantanea con 'console.log (JSON.stringify (circolare))'. Sono curioso di sapere perché non riesco a vederlo in questo modo per vedere il contesto attuale. – agm1984

11
window.onload = function() { 
    hookup(document.getElementById('menu')); 

    function hookup(elem) { 
    elem.attachEvent("onmouseover", mouse); 

    function mouse() { 
    } 
    } 
}

Come si può vedere, il gestore è nidificato all'interno della attacher, il che significa che si chiude sopra il campo di applicazione del chiamante.

+0

Grazie Josh, sembra un esempio realistico di cosa potrebbe accadere in un'app reale – MatthewJ

+1

@Josh Stodola puoi spiegare perché questo è un problema?Ho cercato di analizzare questo codice e capire perché ciò causerebbe una perdita di memoria. Grazie. – Amir

+0

@Amir per collegare la funzione mouse() L'oggetto DOM deve fare riferimento alla funzione di collegamento completo e attachEvent si trova all'interno di questa funzione di collegamento e questo fa riferimento circolare più dettagli qui https://support.microsoft.com/en-gb/kb/830555 – Zgr3doo

1
var b = []; 
var a = []; 
a[0] = b; 
b[0] = a; 

stampa a o b sarebbe tornato Circular.

+7

Questo è un riferimento circolare, ma cosa intendi con "stampa"? La tua risposta implica che il motore JS restituirebbe effettivamente la stringa "Circular" ... – nnnnnn

+0

Significa che se tu "console.log (a)" viene stampato '[[Circular]]'. –

13

O anche più semplice, un array "contenente" stesso. Vedi l'esempio:

var arr = []; 
arr[0] = arr; 
1
function circular(arg){ 
    var count = 0; 

    function next(arg){ 
     count++; 
     if(count > 10) return; 
     if(arg){ 
      console.log('hava arg: ' + arg); 
      next(); 
     }else{ 
      console.log('no arg'); 
      next('add'); 
     } 
    } 
    next(); 
} 
circular(); 

circolare e con chiusure.

7

Probabilmente il modo più breve per definire un oggetto ciclico.

a = {}; a.a = a; 
2

o utilizzando ES6:

class Circular { 
    constructor() { 
    this.value = "Hello World"; 
    this.self = this; 
    } 
} 

circular = new Circular(); 
1

Si può fare:

  • window.window...window
  • var circle = {}; circle.circle = circle;
  • var circle = []; circle[0] = circle; or circle.push(circle)
  • function Circle(){this.self = this}; var circle = new Circle()