2017-07-15 1 views
2

Betrachten Sie diesen CodeWie eine neue Variable in einem Verschluss zu schaffen

'use strict'; 

var factory =() => script => eval(script); 
var closure = factory(); 

closure('var v = 0'); 
var val = closure('typeof v'); 

console.log(val); 

Dies ist mein Versuch, es zu erreichen. Ich möchte eine Schließung erstellen und dann Benutzern ermöglichen, eine neue lokale Variable in dieser Schließung zu erstellen. Ist das überhaupt möglich?

Ich irgendwo gelesen, dass "native Funktion 'eval' kann sogar eine neue Variable im lokalen Kontext der Ausführung erstellen.". Also, warum funktioniert das nicht in meinem Beispiel? Meine Vermutung ist, dass dies daran liegt, dass die Ausführung der Funktion und die Anzahl der Variablen nach Ende der Funktion nicht geändert werden kann, aber ich bin mir nicht sicher.

Mein Beispielskript erstellt eine Schließung und versucht, die neue Variable v in dieser Schließung zu deklarieren und zu initialisieren und ihr die Nummer 0 zuzuweisen. Ich habe erwartet, dass das Ergebnis von typeof vnumber sein sollte, aber es ist tatsächlich undefined.

Also, ich habe zwei Fragen:

  1. Warum es nicht schafft die Variable v wie erwartet
  2. Wie tatsächlich zu erreichen, dass (was das Arbeitsbeispiel wäre)?
+0

Was genau sind Sie tryin hier zu bauen? Wie wäre es mit dem Erstellen eines Objekts zum Speichern Ihres Kontexts und Hinzufügen von Eigenschaften zu diesem Objekt, anstatt zu versuchen, sich in Schließungen zu hacken? – Thomas

+0

Warum brauchen Sie das? Ich habe eine Antwort zu 75% fertig, aber ich habe gemerkt, wie merkwürdig und nutzlos das scheint. Warum müssen Sie in einem solchen Bereich neue Variablen erstellen? Und jedes Mal, wenn Sie 'closure' aufrufen, erstellen Sie einen neuen Bereich. Alle Aufrufe von 'closure' sind nicht" verbunden ". – Carcigenicate

+0

@Thomas. Ich weiß, dass ich stattdessen Objekt verwenden kann, aber ich frage nur nach dieser Methode, um besser zu verstehen, wie Javascript funktioniert. –

Antwort

2

Nun, es lokal scoped ist, aber ein bisschen zu lokalen

var factory =() =>{ 
    return script =>{ 
    //this is the scope. you cant access any variables outside of this. 
    eval(script); 
    }; 
    //you want to eval here, which is impossible 
}; 

Sie könnten sehr hacky Umfang Dinge tun, alle Variablen, um diesen (Speicher arbeiten in context):

var factory = (context={}) => script =>{ with(context){ return eval(script); }}; 

Sie müssen alle lokalen Variablen bei der Erstellung initialisieren:

var exec=factory({v:0, b:undefined});// note that you need to set a value explicitly {v,b} wont worm 

und dann funktioniert es wie erwartet:

console.log(
exec("v"),//0 
exec("v=2"),//2 
exec("v"),//2 
typeof v //undefined 
); 

http://jsbin.com/xibozurizi/edit?console


Wenn Sie nicht wollen, dass tief gehen, das einzige, was Sie würden tun könnte die Saiten verketten:

var factory = code => concat => (eval(code),res=eval(concat),code+=concat,res); 
// or shorter/more buggy 
var factory = code => concat => eval(code+=";"+concat); 

var exec=factory("var a=1;"); 
console.log(
exec("a;"),//1 
exec("var b=a+1"), 
exec("b"),//2 
tyepof a, typeof b //undefined 
); 

http://jsbin.com/midawahobi/edit?console


Der obere Code wird die Saiten mehrmals ausgeführt, die wollte nicht ist. Ein anderer Ansatz:

var factory=code=>({ 
    code, 
    run(c){ 
    return eval(this.code+";"+c); 
    }, 
    add(c){ this.code+=";"+c} 
}); 

So können Sie tun

var exec=factory("var a='hello'"); 
exec.run("alert(a)")//alerts hello 
exec.add("var b=a+' world'"); 
console.log(exec.code,exec.run("b"));//hello world, the upper alert isnt run again 

http://jsbin.com/lihezuwaxo/edit?console

beachten Sie, dass evaling ist immer eine schlechte Idee ...

+0

Ok, ich glaube, ich habe es verstanden. Gut erklärt. Allerdings habe ich nicht genügend Rep für +1, sorry. –

+0

@FigliDelleTenebre bist du willkommen;) und ich denke du wirst bald ... –

0

Ihr Anruf zu eval()hat eine neue Variable erstellen, und es tut dies in dem lokalen Ausführungskontext des Anrufs. Dieser Kontext ist innerhalb diese Funktion, so dass es nicht den Kontext außerhalb, wo Sie closure() aufrufen.

Im Allgemeinen ist eval() streng zu vermeiden. Es macht die Optimierung schwierig (oder unmöglich), so dass Funktionen, die es verwenden, vom Optimierer ignoriert werden. Es gibt einige seltene Umstände, in denen es nützlich ist, aber eine neue lokale Variable zu deklarieren scheint nicht einer von ihnen zu sein.

+0

Ich weiß 'eval' ist nicht für kommerzielle oder ernsthafte Verwendung, aber ich versuche es nur Konzepte von JavaScript zu verstehen und wie es funktioniert, nicht mehr. Ich weiß, Evaling-Code sollte vermieden werden. –

0

Sie können wie zu tun, dass

var factory =() => script => eval(script); 
var closure = factory(); 
var v; 
closure('v=20') 
+0

Aber es erstellt globale Variable (oder zumindest Variable im übergeordneten Bereich). Wenn Sie versuchen, einen neuen Abschluss zu erstellen, wird dieselbe Variable "v" verwendet. –

Verwandte Themen