mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 23:14:06 +08:00
224 lines
20 KiB
HTML
224 lines
20 KiB
HTML
<article id="wikiArticle">
|
||
<div>
|
||
<div>
|
||
<div></div>
|
||
<div><code><strong>eval()</strong></code><strong> </strong>函数会将传入的字符串当做 JavaScript 代码进行执行。</div>
|
||
<div> </div>
|
||
</div>
|
||
</div>
|
||
<h2 id="Syntax" name="Syntax">语法</h2>
|
||
<pre><code class="language-javascript"><code>eval(<em>string</em>)</code></code></pre>
|
||
<h3 id="Parameters" name="Parameters">参数</h3>
|
||
<dl>
|
||
<dt><code>string</code></dt>
|
||
<dd>表示JavaScript表达式,语句或一系列语句的字符串。表达式可以包含变量以及已存在对象的属性。</dd>
|
||
</dl>
|
||
<h3 id="返回值">返回值</h3>
|
||
<p>执行指定代码之后的返回值。如果返回值为空,返回<a href="Reference/Global_Objects/undefined" title="undefined是全局对象的一个属性。也就是说,它是全局作用域的一个变量。undefined的最初值就是原始数据类型undefined。"><code>undefined</code></a></p>
|
||
<h2 id="Description" name="Description">描述</h2>
|
||
<p><code>eval()</code> 是全局对象的一个函数属性。</p>
|
||
<p><code>eval()</code> 的参数是一个字符串。如果字符串表示的是表达式,<span style="font-family: consolas,monaco,andale mono,monospace;"><code>eval()</code> </span>会对表达式进行求值。如果参数表示一个或多个 JavaScript 语句, 那么 <span style="font-family: consolas,monaco,andale mono,monospace;"><code>eval()</code> 就</span>会执行这些语句。注意不要用 <span style="font-family: consolas,monaco,andale mono,monospace;"><code>eval()</code> </span>来执行一个算术表达式;因为 JavaScript 可以自动为算术表达式求值。</p>
|
||
<p>如果你以字符串的形式构造算术表达式,则可以用 <span style="font-family: consolas,monaco,andale mono,monospace;"><code>eval()</code> </span>在随后对其求值。例如,假设你有一个变量 <code>x</code> ,您可以通过将表达式的字符串值(例如 <code>3 * x + 2</code> )赋值给一个变量,然后在你的代码后面的其他地方调用 <code>eval()</code> ,来推迟涉及 <code>x</code> 的表达式的求值。</p>
|
||
<p><font face="Open Sans, Arial, sans-serif">如果 <code>eval()</code> 的参数不是字符串, </font><span style="font-family: consolas,monaco,andale mono,monospace;"><code>eval()</code> </span>将会将参数原封不动的返回。在下面的例子中,<code>String</code> 构造器被指定, 而 <span style="font-family: consolas,monaco,andale mono,monospace;"><code>eval()</code> </span>返回了 <code>String</code> 对象而不是执行字符串。</p>
|
||
<pre><code class="language-javascript">eval(new String("2 + 2")); // 返回了包含"2 + 2"的字符串对象
|
||
eval("2 + 2"); // returns 4
|
||
</code></pre>
|
||
<p>你可以使用通用的的方法来绕过这个限制,如使用<code>toString()</code></p>
|
||
<pre><code class="language-javascript">var expression = new String("2 + 2");
|
||
eval(expression.toString());
|
||
</code></pre>
|
||
<p>如果你间接的使用 <span style="font-family: consolas,monaco,andale mono,monospace;">eval(),比如</span>通过一个引用来调用它,而不是直接的调用 <code>eval</code> 。 从 <a class="external" href="http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.2" rel="noopener">ECMAScript 5</a> 起,它工作在全局作用域下,而不是局部作用域中。这就意味着,例如,下面的代码的作用声明创建一个全局函数,并且geval中的这些代码在执行期间不能在被调用的作用域中访问局部变量。</p>
|
||
<pre><code class="language-javascript">function test() {
|
||
var x = 2, y = 4;
|
||
console.log(eval("x + y")); // 直接调用,使用本地作用域,结果是 6
|
||
var geval = eval; // 等价于在全局作用域调用
|
||
console.log(geval("x + y")); // 间接调用,使用全局作用域,throws ReferenceError 因为`x`未定义
|
||
<code> (0, eval)('x + y'); // 另一间接调用的例子
|
||
</code>}</code></pre>
|
||
<h2 id="Don.27t_use_eval.21" name="Don.27t_use_eval.21">避免在不必要的情况下使用 <code>eval</code></h2>
|
||
<p><code>eval()</code> 是一个危险的函数, 他执行的代码拥有着执行者的权利。如果你用 <code>eval()</code> 运行的字符串代码被恶意方(不怀好意的人)操控修改,您最终可能会在您的网页/扩展程序的权限下,在用户计算机上运行恶意代码。更重要的是,第三方代码可以看到某一个eval()被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的 <a href="Reference/Global_Objects/Function" title="Function 构造函数 创建一个新的Function对象。 在 JavaScript 中, 每个函数实际上都是一个Function对象。"><code>Function</code></a> 就不容易被攻击。</p>
|
||
<p><code>eval()</code> 通常比替代方法慢,因为它必须调用 JS 解释器,而许多其他结构则由现代 JS 引擎进行优化。</p>
|
||
<p>在常见的案例中我们都会找更安全或者更快的方案去替换 <code>eval()</code></p>
|
||
<h3 id="访问成员属性">访问成员属性</h3>
|
||
<p>你不应该去使用 <code>eval()</code> 来将属性名字转化为属性。考虑下面的这个例子,被访问对象的属性在它被执行之前都会未知的。这里可以用 eval 处理:</p>
|
||
<pre><code class="language-javascript">var obj = { a: 20, b: 30 };
|
||
var propName = getPropName(); <code>// 返回 "a" 或 "b"</code>
|
||
|
||
eval( 'var result = obj.' + propsName )</code></pre>
|
||
<p>但是,这里并不是必须得使用 <code>eval()</code> 。事实上,这里并不建议这样使用。可以使用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors" title="JavaScript/Reference/Operators/Member_Operators">属性访问器</a> 进行代替,它更快而且更安全:</p>
|
||
<pre><code class="language-javascript">var obj = { a: 20, b: 30 }
|
||
var propName = getPropName();<code> // 返回 "a" 或 "b"</code>
|
||
var result = obj[ propName ]; <code>// obj[ "a" ] 与 obj.a 等价</code></code></pre>
|
||
<p>你还可以使用这个方法去访问子代的属性。如下:</p>
|
||
<pre><code class="language-javascript">var obj = {a: {b: {c: 0}}};
|
||
var propPath = getPropPath(); // 例如返回 "a.b.c"
|
||
|
||
eval( 'var result = obj.' + propPath )
|
||
</code></pre>
|
||
<p>在这里避免 <code>eval()</code> 可以通过分割属性路径和循环遍历不同的属性来完成:</p>
|
||
<pre><code class="language-javascript">function getDescendantantProp(obj, desc) {
|
||
var arr = desc.split('.');
|
||
while(arr.length) {
|
||
obj = obj[arr.shift()];
|
||
}
|
||
return obj;
|
||
}
|
||
|
||
var obj = {a: {b: {c: 0}}};
|
||
var propPath = getPropPath(); // 例如返回 "a.b.c"
|
||
var result = getDescendantantProp(obj, propPath);</code></pre>
|
||
<p>同样的方法也可实现设置子代的属性值:</p>
|
||
<pre><code class="language-javascript">function setDescendantProp(obj, desc, value) {
|
||
var arr = desc.split('.');
|
||
while (arr.length > 1) {
|
||
obj = obj[arr.shift()];
|
||
}
|
||
obj[arr[0]] = value;
|
||
}
|
||
|
||
var obj = {a: {b: {c: 0}}};
|
||
var propPath = getPropPath(); // 例如返回 "a.b.c"
|
||
var result = setDescendantProp(obj, propPath, 1); // a.b.c 值为 1</code></pre>
|
||
<h3 id="使用函数而非代码段">使用函数而非代码段</h3>
|
||
<p>JavaScript拥有 <a href="/zh-CN/docs/Glossary/First-class_Function" title="http://en.wikipedia.org/wiki/First-class_function">first-class functions</a>,这意味着你可以将函数直接作为参数传递给其他接口,将他们保存在变量中或者对象的属性中,等等。很多DOM的API都用这种思路进行设计,你也可以(或者应该)这样子设计你的代码:</p>
|
||
<pre><code class="language-javascript">// 代替 setTimeout(" ... ", 1000) 写法:
|
||
setTimeout(function() { ... }, 1000);
|
||
|
||
// 代替 elt.setAttribute("onclick", "...") 写法:
|
||
elt.addEventListener('click', function() { ... } , false);</code></pre>
|
||
<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures" title="JavaScript/Guide/Closures">闭包</a> 也有助于创建参数化函数而不用连接字符串。</p>
|
||
<h3 id="Parsing_JSON" name="Parsing_JSON">解析 JSON(将字符串转化为JavaScript对象)</h3>
|
||
<p>如果你在调用 <code>eval()</code> 传入的字符串参数中包含数据(如:一个数组“[1,2,3]”)而不是代码,你应该考虑将其转换为 <a href="https://developer.mozilla.org/en-US/docs/Glossary/JSON">JSON</a> 对象,这允许你用JavaScript语法的子集来表示数据。<a href="/zh-CN/docs/Downloading_JSON_and_JavaScript_in_extensions">在扩展中下载JSON和JavaScript</a></p>
|
||
<p>提示:因为 JSON 语法子集相对于 JavaScript 语法子集比较有局限性,很多在 JavaScript 中可用的特性在 JSON 中就不起作用了。比如,后缀逗号在 JSON 中不支持,并且对象中的属性名在 JSON 中必须用引号括起来。请务必使用 JSON 序列化方法来生成稍后将被解析为 JSON 的字符串。</p>
|
||
<h3 id="尽量传递数据而非代码">尽量传递数据而非代码</h3>
|
||
<p>例如,设计为抓取网页内容的扩展,可能会在XPath中定义抓取规则,而不是在 JavaScript 代码中。</p>
|
||
<h3 id="以有限权限运行代码">以有限权限运行代码</h3>
|
||
<p>如果你必须执行这段代码, 应考虑以更低的权限运行。此建议主要适用于扩展和XUL应用程序,可以使用<a href="https://developer.mozilla.org/en-US/docs/Components.utils.evalInSandbox" title="Components.utils.evalInSandbox">Components.utils.evalInSandbox</a> 。</p>
|
||
<h2 id="Examples" name="Examples">例子</h2>
|
||
<h3 id="使用_eval">使用 <code>eval</code></h3>
|
||
<p>在下面的代码中,两种包含了 <code>eval()</code> 的声明都返回了42。第一种是对字符串 "<code>x + y + 1</code>" 求值;第二种是对字符串 "<code>42</code>"求值。</p>
|
||
<pre><code class="language-javascript">var x = 2;
|
||
var y = 39;
|
||
var z = "42";
|
||
eval("x + y + 1"); // returns 42
|
||
eval(z); // returns 42
|
||
</code></pre>
|
||
<h3 id="Example:_Using_eval_to_evaluate_a_string_of_JavaScript_statements" name="Example:_Using_eval_to_evaluate_a_string_of_JavaScript_statements">使用 <code>eval</code> 执行一串 JavaScript 语句</h3>
|
||
<p>下面的例子使用 <code>eval()</code> 来执行 <code>str</code> 字符串。这个字符串包含了如果 <code>x</code> 等于5,就打开一个Alert 对话框并对 <code>z</code> 赋值 42,否则就对 <code>z</code> 赋值 0 的 JavaScript 语句。 当第二个声明被执行,<code>eval()</code> 将会令字符串被执行,并最终返回赋值给 <code>z</code> 的 42。</p>
|
||
<pre><code class="language-javascript">var x = 5;
|
||
var str = "if (x == 5) {alert('z is 42'); z = 42;} else z = 0; ";
|
||
<code>console.log('z is ', eval(str));</code></code></pre>
|
||
<p>如果您定义了多个值,则会返回最后一个值。</p>
|
||
<pre><code class="language-javascript"><code>var x = 5;
|
||
var str = "if (x == 5) {console.log('z is 42'); z = 42; x = 420; } else z = 0;";
|
||
|
||
console.log('x is ', eval(str)); // z is 42 x is 420</code>
|
||
</code></pre>
|
||
<h3 id="Return_value" name="Return_value">返回值</h3>
|
||
<p><code>eval</code> 返回最后一个表达式的值。</p>
|
||
<pre><code class="language-javascript">var str = "if ( a ) { 1+1; } else { 1+2; }";
|
||
var a = true;
|
||
var b = eval(str); // returns 2
|
||
|
||
<code>console.log('b is : ' + b);</code>
|
||
|
||
a = false;
|
||
b = eval(str); // returns 3
|
||
|
||
<code>console.log('b is : ' + b);</code>
|
||
</code></pre>
|
||
<h3 id="eval_中函数作为字符串被定义需要“(”和“)”作为前缀和后缀"><code>eval</code> 中函数作为字符串被定义需要“(”和“)”作为前缀和后缀</h3>
|
||
<pre><code>var fctStr1 = 'function a() {}'
|
||
var fctStr2 = '(function a() {})'
|
||
var fct1 = eval(fctStr1) // return undefined
|
||
var fct2 = eval(fctStr2) // return a function</code>
|
||
</code></pre>
|
||
<h2 id="规范">规范</h2>
|
||
<table class="standard-table">
|
||
<tbody>
|
||
<tr>
|
||
<th scope="col">Specification</th>
|
||
<th scope="col">Status</th>
|
||
<th scope="col">Comment</th>
|
||
</tr>
|
||
<tr>
|
||
<td><a class="external" href="https://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%201st%20edition,%20June%201997.pdf" hreflang="en" lang="en" rel="noopener" title="ECMAScript 1st Edition (ECMA-262)">ECMAScript 1st Edition (ECMA-262)</a></td>
|
||
<td><span class="spec-Standard">Standard</span></td>
|
||
<td>Initial definition.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><a class="external" href="https://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.1" hreflang="en" lang="en" rel="noopener">ECMAScript 5.1 (ECMA-262)<br/><small lang="zh-CN">eval</small></a></td>
|
||
<td><span class="spec-Standard">Standard</span></td>
|
||
<td> </td>
|
||
</tr>
|
||
<tr>
|
||
<td><a class="external" href="https://www.ecma-international.org/ecma-262/6.0/#sec-eval-x" hreflang="en" lang="en" rel="noopener">ECMAScript 2015 (6th Edition, ECMA-262)<br/><small lang="zh-CN">eval</small></a></td>
|
||
<td><span class="spec-Standard">Standard</span></td>
|
||
<td> </td>
|
||
</tr>
|
||
<tr>
|
||
<td><a class="external" href="https://tc39.github.io/ecma262/#sec-eval-x" hreflang="en" lang="en" rel="noopener">ECMAScript Latest Draft (ECMA-262)<br/><small lang="zh-CN">eval</small></a></td>
|
||
<td><span class="spec-Draft">Draft</span></td>
|
||
<td> </td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2 id="浏览器兼容性">浏览器兼容性</h2>
|
||
<p></p><div class="bc-data"><a class="bc-github-link external" href="https://github.com/mdn/browser-compat-data" rel="noopener">Update compatibility data on GitHub</a><table class="bc-table bc-table-js"><thead><tr class="bc-platforms"><td></td><th class="bc-platform-desktop" colspan="6"><span>Desktop</span></th><th class="bc-platform-mobile" colspan="7"><span>Mobile</span></th><th class="bc-platform-server" colspan="1"><span>Server</span></th></tr><tr class="bc-browsers"><td></td><th class="bc-browser-chrome"><span class="bc-head-txt-label bc-head-icon-chrome">Chrome</span></th><th class="bc-browser-edge"><span class="bc-head-txt-label bc-head-icon-edge">Edge</span></th><th class="bc-browser-firefox"><span class="bc-head-txt-label bc-head-icon-firefox">Firefox</span></th><th class="bc-browser-ie"><span class="bc-head-txt-label bc-head-icon-ie">Internet Explorer</span></th><th class="bc-browser-opera"><span class="bc-head-txt-label bc-head-icon-opera">Opera</span></th><th class="bc-browser-safari"><span class="bc-head-txt-label bc-head-icon-safari">Safari</span></th><th class="bc-browser-webview_android"><span class="bc-head-txt-label bc-head-icon-webview_android">Android webview</span></th><th class="bc-browser-chrome_android"><span class="bc-head-txt-label bc-head-icon-chrome_android">Chrome for Android</span></th><th class="bc-browser-edge_mobile"><span class="bc-head-txt-label bc-head-icon-edge_mobile">Edge Mobile</span></th><th class="bc-browser-firefox_android"><span class="bc-head-txt-label bc-head-icon-firefox_android">Firefox for Android</span></th><th class="bc-browser-opera_android"><span class="bc-head-txt-label bc-head-icon-opera_android">Opera for Android</span></th><th class="bc-browser-safari_ios"><span class="bc-head-txt-label bc-head-icon-safari_ios">Safari on iOS</span></th><th class="bc-browser-samsunginternet_android"><span class="bc-head-txt-label bc-head-icon-samsunginternet_android">Samsung Internet</span></th><th class="bc-browser-nodejs"><span class="bc-head-txt-label bc-head-icon-nodejs">Node.js</span></th></tr></thead><tbody><tr><th scope="row"><code>eval</code></th><td class="bc-supports-yes bc-browser-chrome"><span class="bc-browser-name">Chrome</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-edge"><span class="bc-browser-name">Edge</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-firefox"><span class="bc-browser-name">Firefox</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
1</td><td class="bc-supports-yes bc-browser-ie"><span class="bc-browser-name">IE</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-opera"><span class="bc-browser-name">Opera</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-safari"><span class="bc-browser-name">Safari</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-webview_android"><span class="bc-browser-name">WebView Android</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-chrome_android"><span class="bc-browser-name">Chrome Android</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-edge_mobile"><span class="bc-browser-name">Edge Mobile</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-firefox_android"><span class="bc-browser-name">Firefox Android</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
4</td><td class="bc-supports-yes bc-browser-opera_android"><span class="bc-browser-name">Opera Android</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-safari_ios"><span class="bc-browser-name">Safari iOS</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-samsunginternet_android"><span class="bc-browser-name">Samsung Internet Android</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td><td class="bc-supports-yes bc-browser-nodejs"><span class="bc-browser-name">nodejs</span><abbr class="bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
</abbr>
|
||
Yes</td></tr></tbody></table><section class="bc-legend" id="sect1"><h3 class="offscreen" id="Legend">Legend</h3><dl><dt><span class="bc-supports-yes bc-supports">
|
||
<abbr class="bc-level bc-level-yes only-icon" title="Full support">
|
||
<span>Full support</span>
|
||
|
||
</abbr></span></dt><dd>Full support</dd></dl></section></div><p></p>
|
||
<h2 id="火狐相关">火狐相关</h2>
|
||
<ul>
|
||
<li>从历史上看,<code>eval()</code> 有一个可选的第二个参数,指定上下文执行对象。 这个参数是非标准的,并且明确地从 Firefox 4 中删除。请参阅 <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=531675" rel="noopener" title="FIXED: Ignore the second argument of eval()">bug 531675</a> 。</li>
|
||
</ul>
|
||
<h2 id="See_also" name="See_also">其他内容</h2>
|
||
<ul>
|
||
<li><a href="Reference/Global_Objects/uneval" title="uneval() 函数创建一个代表对象的源代码的字符串。"><code>uneval()</code></a></li>
|
||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors">Property accessors</a></li>
|
||
<li><a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#Using_eval()_in_content_scripts">WebExtensions: Using eval in content scripts</a></li>
|
||
</ul>
|
||
</article> |