We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近在看 SystemJS 源码时,发现 SystemJS 执行 script 时使用的是 (0, eval)(scriptText),特别好奇为啥这样写。经过了解,发现这种写法十分巧妙,故留下一篇记录
(0, eval)(scriptText)
SystemJS 源码:
var instantiate = systemJSPrototype.instantiate; var jsContentTypeRegEx = /^(text|application)\/(x-)?javascript(;|$)/; systemJSPrototype.instantiate = function (url, parent, meta) { var loader = this; if (!this.shouldFetch(url, parent, meta)) return instantiate.apply(this, arguments); return this.fetch(url, { credentials: 'same-origin', integrity: importMap.integrity[url], meta }) .then(function (res) { if (!res.ok) throw Error(errMsg(7, process.env.SYSTEM_PRODUCTION ? [res.status, res.statusText, url, parent].join(', ') : res.status + ' ' + res.statusText + ', loading ' + url + (parent ? ' from ' + parent : ''))); var contentType = res.headers.get('content-type'); if (!contentType || !jsContentTypeRegEx.test(contentType)) throw Error(errMsg(4, process.env.SYSTEM_PRODUCTION ? contentType : 'Unknown Content-Type "' + contentType + '", loading ' + url + (parent ? ' from ' + parent : ''))); return res.text().then(function (source) { if (source.indexOf('//# sourceURL=') < 0) source += '\n//# sourceURL=' + url; // 这里使用了 `(0, eval)(scriptText)` 来执行代码 (0, eval)(source); return loader.getRegister(url); }); }); };
上面代码中的 (0, eval) 是用了逗号运算符语法,不管括号中有多少个表达式,总是返回最后一个表达式的值。最常见的使用场景是在函数返回值前处理一些操作,如
(0, eval)
function myFunc() { let x = 0; return (x += 1, x); // 与 return ++x; 等价 }
根据逗号运算符的特点,表达式 (0, eval) 返回的是 eval 函数本身。
eval
const eval1 = (0, eval) console.log(eval1 === eval) // true
那么 (0, eval)('xxx') 和 eval('xxx') 是不是就没有任何区别了吗?
(0, eval)('xxx')
eval('xxx')
实则不然,根据 Ecma 规范,eval 有两种模式,直接调用和间接调用。直接调用是在当前作用域,间接调用是在全局作用域。通过逗号运算符表达式返回 eval 的引用能让 eval 变成间接调用。试着执行下面代码
直接调用
间接调用
function test() { var x = 2, y = 4; console.log(eval('x + y')); // 直接调用,使用本地作用域,结果是 6 var geval = eval; // 等价于在全局作用域调用 console.log(geval('x + y')); // 间接调用,使用全局作用域,throws ReferenceError 因为`x`未定义 (0, eval)('x + y'); // 另一个间接调用的例子 }
eval 有两种模式,直接调用和间接调用。直接调用是在当前作用域,间接调用是在全局作用域。直接调用会让 eval 中的代码能够获取到当前作用域链上的全部变量,就可能导致局部变量覆盖了全局变量,甚至可能作用域链上的任意变量值都会被执行的代码所影响。而通过逗号运算符表达式返回 eval 的引用能让 eval 变成间接调用,因此能保证 eval 中的代码不会和当前作用域链的变量产生相互影响。
eval - MDN 逗号运算符 - MDN Ecma eval 规范
The text was updated successfully, but these errors were encountered:
No branches or pull requests
最近在看 SystemJS 源码时,发现 SystemJS 执行 script 时使用的是
(0, eval)(scriptText)
,特别好奇为啥这样写。经过了解,发现这种写法十分巧妙,故留下一篇记录SystemJS 源码:
逗号运算符
上面代码中的
(0, eval)
是用了逗号运算符语法,不管括号中有多少个表达式,总是返回最后一个表达式的值。最常见的使用场景是在函数返回值前处理一些操作,如eval
根据逗号运算符的特点,表达式
(0, eval)
返回的是eval
函数本身。那么
(0, eval)('xxx')
和eval('xxx')
是不是就没有任何区别了吗?实则不然,根据 Ecma 规范,
eval
有两种模式,直接调用
和间接调用
。直接调用是在当前作用域,间接调用是在全局作用域。通过逗号运算符表达式返回 eval 的引用能让 eval 变成间接调用。试着执行下面代码结论
eval
有两种模式,直接调用
和间接调用
。直接调用是在当前作用域,间接调用是在全局作用域。直接调用会让 eval 中的代码能够获取到当前作用域链上的全部变量,就可能导致局部变量覆盖了全局变量,甚至可能作用域链上的任意变量值都会被执行的代码所影响。而通过逗号运算符表达式返回 eval 的引用能让 eval 变成间接调用,因此能保证 eval 中的代码不会和当前作用域链的变量产生相互影响。参考资料
eval - MDN
逗号运算符 - MDN
Ecma eval 规范
The text was updated successfully, but these errors were encountered: