Zaczynam czytać wzorce JavaScript , niektóre kody mnie zmyliły.
var global = (function () {
return this || (1, eval)('this');
}());
Oto moje pytania:
P1:
(1, eval) === eval
?
Dlaczego i jak to działa?
P2: Dlaczego nie po prostu
var global = (function () {
return this || eval('this');
}());
lub
var global = (function () {
return this;
}());
javascript
eval
shawjia
źródło
źródło
Odpowiedzi:
Różnica między
(1,eval)
a zwykłym starymeval
polega na tym, że pierwsza jest wartością, a druga jest lwartością. Byłoby bardziej oczywiste, gdyby był to jakiś inny identyfikator:var x; x = 1; (1, x) = 1; // syntax error, of course!
To jest
(1,eval)
wyrażenie, które dajeeval
(tak jak powiedzmy(true && eval)
lub(0 ? 0 : eval)
zrobiłoby), ale nie jest odniesieniem doeval
.Dlaczego się przejmujesz?
Cóż, ECMA specyfikacja rozważa odwołanie się
eval
być „bezpośrednie połączenie eval”, ale to tylko wyraz daje w wynikueval
być pośrednim jeden - i pośrednie połączenia eval gwarantowane są do wykonania w zakresie globalnym.Rzeczy, których nadal nie wiem:
this
funkcja o zasięgu globalnym może nie dawać obiektu globalnego?Więcej informacji można znaleźć tutaj .
EDYTOWAĆ
Najwyraźniej odpowiedź na moje pierwsze pytanie brzmi „prawie zawsze”. Bezpośredni jest
eval
wykonywany z bieżącego zakresu. Rozważ następujący kod:var x = 'outer'; (function() { var x = 'inner'; eval('console.log("direct call: " + x)'); (1,eval)('console.log("indirect call: " + x)'); })();
Nic dziwnego (heh-heh), to wypisuje:
EDYTOWAĆ
Po dalszych eksperymentach zamierzam wstępnie powiedzieć, że
this
nie można ustawić nanull
lubundefined
. Można ustawić inne fałszywe wartości (0, „, NaN, fałsz”), ale tylko bardzo celowo.Powiem, że twoje źródło cierpi na łagodną i odwracalną inwersję czaszkowo-odbytniczą i może chcieć rozważyć spędzenie tygodnia na programowaniu w Haskell.
źródło
value
vslvalue
(no cóż, może w praktyce, ale nie słowami). Ani reguł ewaluacyjnych ES5 (których nie powinienemeval
kiedykolwiek używać ). Dzięki!eval
ma wiele paskudnych ostrych krawędzi i powinien być używany tylko w ostateczności, a potem bardzo, bardzo ostrożnie.innerHtml
eval
i być częścią MemberExpression elementu CallExpression i odnosić się doeval
funkcji standardowej .eval
jako cel wyrażenia wywołania jest szczególne. Twierdzisz, że ECMA traktuje odniesienia jakoeval
specjalne, a tego nie robi. Jest to miejsce docelowe w wyrażeniu wywołującym, które jest szczególne i że wyrażenie przyjmuje wartośćeval
funkcji standardowej . Na przykładvar eval = window.eval; eval('1');
jest nadal bezpośrednim eval iwindow.eval('1')
nie jest, nawet jeśli eval jest lwartością również w tym przypadku.Fragment,
var global = (function () { return this || (1, eval)('this'); }());
będzie poprawnie oceniać obiekt globalny nawet w trybie ścisłym. W trybie nieścisłym wartość
this
jest obiektem globalnym, ale w trybie ścisłym jestundefined
. Wyrażenie(1, eval)('this')
zawsze będzie obiektem globalnym. Powodem tego są zasady dotyczące wersetów pośrednich bezpośrednicheval
. Bezpośrednie wywołaniaeval
mają zasięg obiektu wywołującego, a ciągthis
zostałby oszacowany na wartośćthis
w zamknięciu. Pośrednieeval
wartości oceniają w zakresie globalnym tak, jakby były wykonywane wewnątrz funkcji w zakresie globalnym. Ponieważ ta funkcja sama w sobie nie jest funkcją trybu ścisłego, obiekt globalny jest przekazywany jako,this
a następnie wyrażenie'this'
obliczane jest na obiekt globalny. Wyrażenie(1, eval)
to po prostu fantazyjny sposób na wymuszenieeval
być pośrednim i zwrócić obiekt globalny.A1:
(1, eval)('this')
to nie to samo, coeval('this')
ze względu na specjalne zasady dotyczące bezpośredniego wywołania w wersecie pośrednimeval
.A2: Oryginał działa w trybie ścisłym, zmodyfikowane wersje nie.
źródło
Do Q1:
Myślę, że to dobry przykład operatora przecinka w JS. Podoba mi się wyjaśnienie dotyczące operatora przecinka w tym artykule: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
Operator przecinka ocenia oba swoje operandy (od lewej do prawej) i zwraca wartość drugiego operandu.
Do Q2:
(1, eval)('this')
jest uważane za pośrednie wywołanie eval, które w ES5 wykonuje kod globalnie. Wynik będzie więc globalnym kontekstem.Zobacz http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope
źródło
P1: Wiele kolejnych instrukcji javascript oddzielonych przecinkiem przyjmuje wartość ostatniej instrukcji. Więc:
(1, eval)
przyjmuje wartość ostatniej, która jest odwołaniem doeval()
funkcji. Najwyraźniej robi to w ten sposób, abyeval()
wywołać pośrednie wywołanie ewaluacyjne, które zostanie ocenione w zakresie globalnym w ES5. Szczegóły wyjaśniono tutaj .P2: Musi istnieć środowisko, które nie definiuje globalnego
this
, ale je definiujeeval('this')
. To jedyny powód, jaki przychodzi mi do głowy.źródło
/eval\(/g
?eval
kod jest wykonywany w swoim własnym kontekście, a nie w kontekście globalnym lub otaczającym. Jednym ze sposobów obejścia tego jest pośrednie odwołanie się do niego, tak jak robi to w przypadku danego kodu.