このエントリは、indirect eval call を使い global を取得する方法についてのメモです。
(0, eval)('this')とは何なのか を拝見したのがこのメモを記述するきっかけです。
このイディオム(indirect eval call)に関連する記事としては、以下の3つが見つかりました。2つめは Dr.Axel さんのものですね。
- http://pirosikick.hateblo.jp/entry/20110517/1305645797 ("global", eval)("this")
- http://www.2ality.com/2014/01/eval.html Evaluating JavaScript code via eval() and new Function()
- http://stackoverflow.com/questions/19357978/indirect-eval-call-in-strict-mode Indirect eval call in strict mode
書き方としては (0, eval)('this')
に限らず、亜種がいっぱいあるようです。
要は、一旦 eval を変数(または暗黙の変数)に入れると indirect eval call として扱われるようです。
(1, eval)('...')
(eval, eval)('...')
(1 ? eval : 0)('...')
(__ = eval)('...')
var e = eval; e('...')
(function(e) { e('...') })(eval)
(function(e) { return e })(eval)('...')
(function() { arguments[0]('...') })(eval)
this.eval('...')
this['eval']('...')
[eval][0]('...')
eval.call(this, '...')
eval('eval')('...')
in Babel
Babel だとどうなるのでしょうか?
indirect eval call で global が取得できるか、 Babel の repl で試してみた結果がこちらです。
// source
var a = (0, eval)("this");
console.log(Object.prototype.toString.call(a));
// result
"use strict";
var a = (0, eval)("this");
console.log(Object.prototype.toString.call(a)); // [object global]
遅延評価されることで global がとれてますね。
なお、
(0, eval)("this");
と文字列にせず、
(0, eval)(this);
としてしまうと、
Babel が(0, eval)(undefined);
に変換してしまいます。
in ESLint
ESLint で eval がどのように扱われているかも知る必要があるでしょう。
.eslintrc を用意し実行してみます。
{
"env": {
"browser": true,
"node": true
}
}
$ eslint ...
私の環境では特に怒られませんでした。良いですね。
vs WebModule
蛇足になりますが、uupaa さん家の WebModule では、
var GLOBAL = GLOBAL || (this || 0).self || global;
で global Object を求めていますね。
なんだか、WebModule のやり方よりも
var global = ("global", eval)("this");
のほうがシンプルでスッキリしている、そんな気がしてきました。
まとめ
まとめると、var global = ("global", eval)("this");
は、(困った事に)中々良いのではないでしょうか。
あ、そうそう初Qiita なのでお手柔らかにお願いします。