Domanda

Dato il seguente frammento di javascript in un ambito:

var x = 10;

function sayx() {
  alert(x);
}

sayx();

Ovviamente ci si aspetterebbe che una finestra di messaggio stampi '10', si potrebbe fare l'annidamento di più funzioni per interagire con il modo in cui viene determinato 'x', perché quando si risolve quale x è l'ambiente percorre la catena dell'ambito.

Puoi anche fare un livello di 'ricompilazione' con eval per iniettare nuovi ambiti in fase di esecuzione .. ad esempio:

var x = 10;

function sayx() {
  alert(x);
}

function wrap(f) {
  return eval('(function() { var x = 20;(' + f + ')(); })');
}

wrap(sayx)();

Funziona perché la funzione avrà la sua funzione toString chiamata che restituirà l'origine 'originale' .. quindi creiamo essenzialmente una versione di wrapping della funzione che ha un nuovo ambito che sovrascrive x .. il risultato sarà un avviso scatola che stampa '20' e non '10'.

Tuttavia, in superficie potrebbe sembrare che funzioni ma la catena dell'oscilloscopio è rotta, l'elemento successivo nella catena non è più lo stesso perché la funzione 'f' è ora definita in una posizione diversa .. ancora peggio è che la catena di portata che ha ereditato potrebbe contenere molti riferimenti a cui la funzione chiamante non dovrebbe avere accesso.

Quindi, esiste un modo più supportato e praticabile per iniettare un oggetto ambito? qualcosa come:

function withScope(f, scope) { ??? }

---

var x = 10, y = 10;

function dothemath() {
  alert(x + y);
}

var haxthemath = withScope(dothemath, { x: 9000 });
haxthemath(); // 9010 not 20

Suppongo che la risposta sia "no", alcuni potrebbero obiettare che ci sono problemi di "sicurezza" con tale iniezione di portata, ma considerando che puoi comunque fare il trucco (anche se gravemente rotto) Non penso che sia ..

I vantaggi di questo sarebbe che puoi essenzialmente falsificare le tue pseudo variabili.

Grazie in anticipo.


Modifica, solo un po 'di chiarimento, immagina che volessi "withScope" una funzione che avesse la seguente catena di portata:

Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }

Vorrei essere in grado di recuperare una funzione che effettivamente aveva la stessa catena + un ambito che fornisco .. cioè:

withScope(somefunc, { foo: 'bar' })

Mi darebbe

Window - window properties
Object - { var x = 10 }
Object - { var y = 5 + x }
Ext scope - { foo = 'bar' }

Tutte le variabili permanenti precedenti sarebbero state trovate perché il mio ambito esteso non dice nulla al riguardo.

È stato utile?

Soluzione

Se ti riferisci per ambito alle variabili locali nella funzione e / o nella chiusura, penso che la risposta sia no.

Puoi cambiare l'ambito della parola chiave this usando functionName.call (scope, arg1, ...) o functionName.apply (scope, [arg1, ...]); Questo potrebbe essere usato insieme ai prototipi per creare catene simili come descrivi tu - se qualcosa non viene trovato nelle proprietà dell'oggetto stesso, viene cercato nel suo prototipo. Se la proprietà non è presente, viene utilizzato il prototipo successivo nella catena e così via.

Altri suggerimenti

la risposta che penso tu stia cercando è quella incorporata in " con " comunicato.

Tuttavia, non consiglierei di usarlo, poiché è obsoleto e molto probabilmente non esisterà in ecmascript 6

L'unico altro modo in cui penso che potresti fare questo genere di cose è dall'interno dell'applicazione host stessa, manipolando l'ambiente javascript dall'esterno. Oppure, se stai usando rhino, puoi effettivamente farlo dall'interno di javascript, perché il collegamento tra API Java e Javascript è semplicemente perfetto in Rhino. Quando steve yegge lo ha sottolineato per la prima volta, mi è venuta in mente. Manipola javascript dall'esterno di javascript, ma dall'interno javascript! È geniale!

Se sei bloccato in un ambiente browser, forse puoi usare un interprete javascript scritto in javascript, come narciso.

Forse usi il metodo toString integrato di javascript per le funzioni?

function withScope(f, scope) {
    var toExec = "";
    for (var prop in scope) {
        toExec += "var " + prop + " = scope['" + prop + "'];"
    }
    toExec += "f = (" + f.toString() + ")";
    eval(toExec);
    return f;
}
var x = 10;
var f = function() {
    console.log(x);
};
withScope(f, {x: 20})();

Sembra una cattiva idea ...

Se vuoi giocare con scope potresti goderti l'istruzione let fornita in Javascript 1.7. Le versioni recenti di Firefox supportano let .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top