diff options
| author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
|---|---|---|
| committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
| commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
| tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/javascript/reference/statements | |
| parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
| download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip | |
initial commit
Diffstat (limited to 'files/zh-cn/web/javascript/reference/statements')
31 files changed, 5596 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/reference/statements/async_function/index.html b/files/zh-cn/web/javascript/reference/statements/async_function/index.html new file mode 100644 index 0000000000..cb6f595ff9 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/async_function/index.html @@ -0,0 +1,327 @@ +--- +title: async函数 +slug: Web/JavaScript/Reference/Statements/async_function +tags: + - JavaScript + - 函数 + - 声明 + - 异步函数 + - 语言特性 +translation_of: Web/JavaScript/Reference/Statements/async_function +--- +<div>{{jsSidebar("Statements")}}</div> + +<p>async函数是使用<code>async</code>关键字声明的函数。 async函数是{{jsxref("Global_Objects/AsyncFunction","AsyncFunction")}}构造函数的实例, 并且其中允许使用<code>await</code>关键字。<code>async</code>和<code>await</code>关键字让我们可以用一种更简洁的方式写出基于{{jsxref("Promise")}}的异步行为,而无需刻意地链式调用<code>promise</code>。</p> + +<div class="noinclude"> +<p>async函数还可以被{{jsxref("Operators/async_function", "作为表达式", "", 1)}}来定义。</p> +</div> + +<div>{{EmbedInteractiveExample("pages/js/statement-async.html", "taller")}}</div> + +<p class="hidden">该交互式demo源文件存储于Github仓库中。如果希望为此交互式项目做出贡献,请 clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> 项目并用pull形式向我们的原始仓库发出请求。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox notranslate">async function <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) { +<em> statements </em> +} +</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>name</code></dt> + <dd>函数名称。</dd> +</dl> + +<dl> + <dt><code>param</code></dt> + <dd>要传递给函数的参数的名称。</dd> +</dl> + +<dl> + <dt><code>statements</code></dt> + <dd>包含函数主体的表达式。可以使用<code>await</code>机制。</dd> + <dt> + <h3 id="返回值">返回值</h3> + </dt> + <dd>一个{{jsxref("Promise")}},这个promise要么会通过一个由async函数返回的值被解决,要么会通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>async函数可能包含0个或者多个{{jsxref("Operators/await", "await")}}表达式。await表达式会暂停整个async函数的执行进程并出让其控制权,只有当其等待的基于promise的异步操作被兑现或被拒绝之后才会恢复进程。promise的解决值会被当作该await表达式的返回值。使用<code>async</code> / <code>await</code>关键字就可以在异步代码中使用普通的<code>try</code> / <code>catch</code>代码块。</p> + +<div class="note"> +<p><code>await</code>关键字只在async函数内有效。如果你在async函数体之外使用它,就会抛出语法错误 {{jsxref("SyntaxError")}} 。</p> +</div> + +<div class="note"> +<p><code>async</code>/<code>await</code>的目的为了简化使用基于promise的API时所需的语法。<code>async</code>/<code>await</code>的行为就好像搭配使用了生成器和promise。</p> +</div> + +<p>async函数一定会返回一个promise对象。如果一个async函数的返回值看起来不是promise,那么它将会被隐式地包装在一个promise中。</p> + +<p>例如,如下代码:</p> + +<pre class="syntaxbox notranslate">async function <var>foo</var>() { + <var>return 1</var> +} +</pre> + +<p>等价于:</p> + +<pre class="syntaxbox notranslate">function <var>foo</var>() { + <var>return Promise.resolve(1)</var> +} +</pre> + +<p>async函数的函数体可以被看作是由0个或者多个await表达式分割开来的。从第一行代码直到(并包括)第一个await表达式(如果有的话)都是同步运行的。这样的话,一个不含await表达式的async函数是会同步运行的。然而,如果函数体内有一个await表达式,async函数就一定会异步执行。</p> + +<p>例如:</p> + +<pre class="syntaxbox notranslate">async function <var>foo</var>() { + <var>await 1</var> +} +</pre> + +<p>等价于</p> + +<pre class="syntaxbox notranslate">function <var>foo</var>() { + <var>return Promise.resolve(1).then(() => undefined)</var> +} +</pre> + +<p>在await表达式之后的代码可以被认为是存在在链式调用的then回调中,多个await表达式都将加入链式调用的then回调中,返回值将作为最后一个then回调的返回值。</p> + +<p>在接下来的例子中,我们将使用await执行两次promise,整个<code>foo</code>函数的执行将会被分为三个阶段。</p> + +<ol> + <li><code>foo</code>函数的第一行将会同步执行,await将会等待promise的结束。然后暂停通过<code>foo</code>的进程,并将控制权交还给调用<code>foo</code>的函数。</li> + <li>一段时间后,当第一个promise完结的时候,控制权将重新回到foo函数内。示例中将会将<code>1</code>(promise状态为fulfilled)作为结果返回给await表达式的左边即<code>result1</code>。接下来函数会继续进行,到达第二个await区域,此时<code>foo</code>函数的进程将再次被暂停。</li> + <li>一段时间后,同样当第二个promise完结的时候,<code>result2</code>将被赋值为<code>2</code>,之后函数将会正常同步执行,将默认返回<code>undefined</code> 。</li> +</ol> + +<pre class="notranslate">async function <var>foo</var>() { + const result1 = <var>await new Promise((resolve) => setTimeout(() => resolve('1'))) +</var> const result2 = <var>await new Promise((resolve) => setTimeout(() => resolve('2')))</var> +} +foo()</pre> + +<p>注意:promise链不是一次就构建好的,相反,promise链是分阶段构造的,因此在处理异步函数时必须注意对错误函数的处理。</p> + +<p>例如,在下面的代码中,在promise链上配置了<code>.catch</code>处理程序,将抛出未处理的promise错误。这是因为<code>p2</code>返回的结果不会被await处理。</p> + +<pre class="notranslate">async function <var>foo</var>() { + const p1 = <var>new Promise((resolve) => setTimeout(() => resolve('1'), 1000)) +</var> const p2 = <var>new Promise((_,reject) => setTimeout(() => reject('2'), 500)) + const results = [await p1, await p2] // 不推荐使用这种方式,请使用 Promise.all或者Promise.allSettled </var> +} +foo().catch(() => {}) // 捕捉所有的错误...</pre> + + + +<h2 id="示例">示例</h2> + +<h3 id="简单例子">简单例子</h3> + +<pre class="brush: js notranslate">var resolveAfter2Seconds = function() { + console.log("starting slow promise"); + return new Promise(resolve => { + setTimeout(function() { + resolve("slow"); + console.log("slow promise is done"); + }, 2000); + }); +}; + +var resolveAfter1Second = function() { + console.log("starting fast promise"); + return new Promise(resolve => { + setTimeout(function() { + resolve("fast"); + console.log("fast promise is done"); + }, 1000); + }); +}; + +var sequentialStart = async function() { + console.log('==SEQUENTIAL START=='); + + // 1. Execution gets here almost instantly + const slow = await resolveAfter2Seconds(); + console.log(slow); // 2. this runs 2 seconds after 1. + + const fast = await resolveAfter1Second(); + console.log(fast); // 3. this runs 3 seconds after 1. +} + +var concurrentStart = async function() { + console.log('==CONCURRENT START with await=='); + const slow = resolveAfter2Seconds(); // starts timer immediately + const fast = resolveAfter1Second(); // starts timer immediately + + // 1. Execution gets here almost instantly + console.log(await slow); // 2. this runs 2 seconds after 1. + console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved +} + +var concurrentPromise = function() { + console.log('==CONCURRENT START with Promise.all=='); + return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => { + console.log(messages[0]); // slow + console.log(messages[1]); // fast + }); +} + +var parallel = async function() { + console.log('==PARALLEL with await Promise.all=='); + + // Start 2 "jobs" in parallel and wait for both of them to complete + await Promise.all([ + (async()=>console.log(await resolveAfter2Seconds()))(), + (async()=>console.log(await resolveAfter1Second()))() + ]); +} + +// This function does not handle errors. See warning below! +var parallelPromise = function() { + console.log('==PARALLEL with Promise.then=='); + resolveAfter2Seconds().then((message)=>console.log(message)); + resolveAfter1Second().then((message)=>console.log(message)); +} + +sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast" + +// wait above to finish +setTimeout(concurrentStart, 4000); // after 2 seconds, logs "slow" and then "fast" + +// wait again +setTimeout(concurrentPromise, 7000); // same as concurrentStart + +// wait again +setTimeout(parallel, 10000); // truly parallel: after 1 second, logs "fast", then after 1 more second, "slow" + +// wait again +setTimeout(parallelPromise, 13000); // same as parallel +</pre> + +<div class="note"> +<h4 id="await_and_parallelism并行"><code>await</code> and parallelism(并行)</h4> + +<p>在<code>sequentialStart</code>中,程序在第一个<code>await</code>停留了2秒,然后又在第二个<code>await</code>停留了1秒。直到第一个计时器结束后,第二个计时器才被创建。程序需要3秒执行完毕。</p> + +<p><br> + 在 <code>concurrentStart</code>中,两个计时器被同时创建,然后执行<code>await</code>。这两个计时器同时运行,这意味着程序完成运行只需要2秒,而不是3秒,即最慢的计时器的时间。</p> + +<p>但是 <code>await </code>仍旧是顺序执行的,第二个 <code>await</code> 还是得等待第一个执行完。在这个例子中,这使得先运行结束的输出出现在最慢的输出之后。</p> + +<p>如果你希望并行执行两个或更多的任务,你必须像在<code>parallel</code>中一样使用<code>await Promise.all([job1(), job2()])</code>。</p> +</div> + +<div class="warning"> +<h4 id="asyncawait和Promisethen对比以及错误处理"><code>async</code>/<code>await和</code>Promise#then对比以及错误处理</h4> + +<p>大多数async函数也可以使用Promises编写。但是,在错误处理方面,async函数更容易捕获异常错误</p> + +<p>上面例子中的<code>concurrentStart</code>函数和<code>concurrentPromise</code>函数在功能上都是等效的。在<code>concurrentStart</code>函数中,如果任一<code>await</code>ed调用失败,它将自动捕获异常,async函数执行中断,并通过隐式返回Promise将错误传递给调用者。</p> + +<p>在Promise例子中这种情况同样会发生,该函数必须负责返回一个捕获函数完成的<code>Promise</code>。在<code>concurrentPromise</code>函数中,这意味着它从<code>Promise.all([]).then()</code>返回一个Promise。事实上,在此示例的先前版本忘记了这样做!</p> + +<p>但是,async函数仍有可能然可能错误地忽略错误。<br> + 以<code>parallel</code> async函数为例。 如果它没有等待<code>await</code>(或返回)<code>Promise.all([])</code>调用的结果,则不会传播任何错误。<br> + 虽然<code>parallelPromise</code>函数示例看起来很简单,但它根本不会处理错误! 这样做需要一个类似于<code>return </code><code>Promise.all([])</code>处理方式。</p> +</div> + +<h3 id="使用async函数重写_promise_链"><code><font face="x-locale-heading-primary, zillaslab, Palatino, Palatino Linotype, x-locale-heading-secondary, serif"><span style="background-color: #333333;">使用</span></font></code>async函数重写 promise 链</h3> + +<p>返回 {{jsxref("Promise")}}的 API 将会产生一个 promise 链,它将函数肢解成许多部分。例如下面的代码:</p> + +<pre class="brush: js notranslate">function getProcessedData(url) { + return downloadData(url) // 返回一个 promise 对象 + .catch(e => { + return downloadFallbackData(url) // 返回一个 promise 对象 + }) + .then(v => { + return processDataInWorker(v); // 返回一个 promise 对象 + }); +}</pre> + +<p>可以重写为单个async函数:</p> + +<pre class="brush: js notranslate">async function getProcessedData(url) { + let v; + try { + v = await downloadData(url); + } catch (e) { + v = await downloadFallbackData(url); + } + return processDataInWorker(v); +} +</pre> + +<p>注意,在上述示例中,<code>return</code> 语句中没有 <code>await</code> 操作符,因为 <code>async function</code> 的返回值将被隐式地传递给 <code>{{jsxref("Promise.resolve")}}</code>。</p> + +<div class="blockIndicator note"> +<p><strong><code>return await promiseValue;</code> 与 <code>return promiseValue;的比较</code></strong></p> + +<p>返回值<code>隐式的传递给</code>{{jsxref("Promise.resolve")}},并不意味着<code>return await promiseValue;和return promiseValue;</code>在功能上相同。</p> + +<p>看下下面重写的上面代码,在<code>processDataInWorker</code>抛出异常时返回了null:</p> + +<pre class="notranslate"><code>async function getProcessedData(url) { + let v; + try { + v = await downloadData(url); + } catch(e) { + v = await downloadFallbackData(url); + } + try { + return await processDataInWorker(v); // 注意 `return await` 和单独 `return` 的比较 + } catch (e) { + return null; + } +}</code></pre> + +<p>简单地写上<code>return processDataInworker(v);将导致在processDataInWorker(v)</code>出错时function返回值为{{jsxref("Promise")}}<code>而不是</code>返回null。<code>return foo;</code>和<code>return await foo;</code>,有一些细微的差异:<code>return foo;</code>不管<code>foo</code>是promise还是rejects都将会直接返回<code>foo。相反地,</code>如果<code>foo</code>是一个{{jsxref("Promise")}},<code>return await foo;</code>将等待<code>foo</code>执行(resolve)或拒绝(reject),如果是拒绝,将会在返回前抛出异常。</p> +</div> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('ESDraft', '#sec-async-function-definitions', 'async function')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td>初始定义于ES2017.</td> + </tr> + <tr> + <td>{{SpecName('ES8', '#sec-async-function-definitions', 'async function')}}</td> + <td>{{Spec2('ES8')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div class="hidden">该页面上的兼容性表是由结构化数据生成的。如果您想对数据做出贡献,请查看https://github.com/mdn/browser-compat-data,并向我们发送一个pull request。</div> + +<p>{{Compat("javascript.statements.async_function")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Operators/async_function", "async function expression")}}</li> + <li>{{jsxref("AsyncFunction")}} object</li> + <li>{{jsxref("Operators/await", "await")}}</li> + <li><a href="http://innolitics.com/10x/javascript-decorators-for-promise-returning-functions/">"Decorating Async Javascript Functions" on "innolitics.com"</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/block/index.html b/files/zh-cn/web/javascript/reference/statements/block/index.html new file mode 100644 index 0000000000..4188e5a2ec --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/block/index.html @@ -0,0 +1,163 @@ +--- +title: block +slug: Web/JavaScript/Reference/Statements/block +tags: + - JavaScript + - Reference + - Statement +translation_of: Web/JavaScript/Reference/Statements/block +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong>块语句</strong>(或其他语言的<strong>复合语句</strong>)用于组合零个或多个语句。该块由一对大括号界定,可以是{{jsxref("Statements/label", "labelled")}}:</p> + +<h2 id="语法">语法</h2> + +<h3 id="块声明">块声明</h3> + +<pre class="syntaxbox">{ <em>StatementList </em>} +</pre> + +<h3 id="标记块声明">标记块声明</h3> + +<pre class="syntaxbox"><em>LabelIdentifier</em>: { <em>StatementList </em>} +</pre> + +<dl> + <dt><code>StatementList</code></dt> + <dd>在块语句中分组的语句。</dd> + <dt><code>LabelIdentifier</code></dt> + <dd>用于视觉识别的可选{{jsxref("Statements/label", "label")}}或{{jsxref("Statements/break", "break")}}的目标。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>其他语言中通常将语句块称为<strong>复合语句</strong>。它允许你使用多个语句,其中 JavaScript 只需要一个语句。将语句组合成块是 JavaScript 中的常见做法。相反的做法是可以使用一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/Empty">空语句</a>,你不提供任何语句,虽然一个是必需的。</p> + +<h3 id="块级作用域">块级作用域</h3> + +<h4 id="在非严格模式non-strict_mode下的var_或者函数声明时">在非严格模式(non-strict mode)下的<code>var </code>或者函数声明时</h4> + +<p>通过<code>var</code>声明的变量或者非严格模式下(non-strict mode)创建的函数声明<strong>没有</strong>块级作用域。在语句块里声明的变量的作用域不仅是其所在的函数或者 script 标签内,所设置变量的影响会在超出语句块本身之外持续存在。 换句话说,这种语句块不会引入一个作用域。尽管单独的语句块是合法的语句,但在JavaScript中你不会想使用单独的语句块,因为它们不像你想象的C或Java中的语句块那样处理事物。例如:</p> + +<pre class="brush: js example-bad">var x = 1; +{ + var x = 2; +} +console.log(x); // 输出 2 +</pre> + +<p>输出结果是 2,因为块中的 <code>var x</code>语句与块前面的<code>var x</code>语句作用域相同。在 C 或 Java中,这段代码会输出 1。</p> + + + +<h4 id="使用let和_const">使用<code>let</code>和 <code>const</code></h4> + +<p>相比之下,使用 {{jsxref("Statements/let", "let")}}和{{jsxref("Statements/const", "const")}}声明的变量是<strong>有</strong>块级作用域的。</p> + +<pre class="brush: js">let x = 1; +{ + let x = 2; +} +console.log(x); // 输出 1</pre> + +<p><code>x = 2</code>仅限在定义它的块中。</p> + +<p><code>const</code>的结果也是一样的:</p> + +<pre class="brush: js">const c = 1; +{ + const c = 2; +} +console.log(c); // 输出1, 而且不会报错</pre> + +<p>注意,位于块范围之内的 <code>const c = 2</code> 并不会抛出<code>SyntaxError: Identifier 'c' has already been declared</code>这样的语法错误,因为在它自己的块中它可能是唯一一个被声明的常量。</p> + +<h5 id="使用let声明的变量在块级作用域内能强制执行更新变量,下面的两个例子对比:">使用let声明的变量在块级作用域内能强制执行更新变量,下面的两个例子对比:</h5> + +<pre class="brush: js">var a = []; +for (<strong>var</strong> i = 0; i < 10; i++) { + a[i] = function () {console.log(i);}; +} +a[0](); // 10 +a[1](); // 10 +a[6](); // 10 + +/********************/ + +var a = []; +for (<strong>let</strong> i = 0; i < 10; i++) { + a[i] = function () {console.log(i);}; +} +a[0](); // 0 +a[1](); // 1 +a[6](); // 6</pre> + +<h4 id="使用function">使用<code>function</code></h4> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function">函数声明</a>同样被限制在声明他的语句块内:</p> + + + +<pre><code>foo('outside'); // TypeError: foo is not a function +{ + function foo(location) { + console.log('foo is called ' + location); + } + foo('inside'); // 正常工作并且打印 'foo is called inside' +}</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>{{SpecName('ESDraft', '#sec-block', 'Block statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-block', 'Block statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.1', 'Block statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.1', 'Block statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.1', 'Block statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition. Implemented in JavaScript 1.0.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.block")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/while", "while")}}</li> + <li>{{jsxref("Statements/if...else", "if...else")}}</li> + <li>{{jsxref("Statements/let", "let")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/break/index.html b/files/zh-cn/web/javascript/reference/statements/break/index.html new file mode 100644 index 0000000000..9cecd6eef9 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/break/index.html @@ -0,0 +1,175 @@ +--- +title: break +slug: Web/JavaScript/Reference/Statements/break +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/break +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong>break 语句</strong>中止当前循环,{{jsxref("Statements/switch", "switch")}}语句或{{jsxref("Statements/label", "label")}} 语句,并把程序控制流转到紧接着被中止语句后面的语句。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox notranslate"><code>break [label];</code></pre> + +<dl> + <dt><code>label</code> {{可选}}</dt> + <dd>与语句标签相关联的标识符。如果 break 语句不在一个循环或 {{jsxref("Statements/switch", "switch")}} 语句中,则该项是必须的。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p><code>break</code>语句包含一个可选的标签,可允许程序摆脱一个被标记的语句。<code>break</code>语句需要内嵌在引用的标签中。被标记的语句可以是任何 {{jsxref("Statements/block", "块")}}语句;不一定是循环语句。</p> + +<p>break语句不能在function函数体中直接使用,break语句应嵌套在要中断的当前循环、switch或label语句中。</p> + +<h2 id="示例">示例</h2> + +<h3 id="break_in_while_loop">break in while loop</h3> + +<p>下面的函数里有个 <code>break</code> 语句,当 <code>i</code> 为 3 时,会中止 {{jsxref("Statements/while", "while")}} 循环,然后返回 3 * <code>x</code> 的值。</p> + +<pre class="brush: js notranslate"><code class="language-js"><span class="keyword token">function</span> <span class="function token">testBreak</span><span class="punctuation token">(</span>x<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">var</span> i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> + + <span class="keyword token">while</span> <span class="punctuation token">(</span>i <span class="operator token"><</span> <span class="number token">6</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>i <span class="operator token">==</span> <span class="number token">3</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">break</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + i <span class="operator token">+</span><span class="operator token">=</span> <span class="number token">1</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + + <span class="keyword token">return</span> i <span class="operator token">*</span> x<span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<h3 id="break_in_switch_statements">break in switch statements</h3> + +<p>在下面的代码中, <code>break</code> 使用在 {{jsxref("Statements/switch", "switch")}} 语句中,当遇到匹配到case后,就会执行相应的代码并中断循环体。</p> + +<pre class="notranslate">const food = "sushi"; + +switch (food) { + case "sushi": + console.log("Sushi is originally from Japan."); + break; + case "pizza": + console.log("Pizza is originally from Italy."); + break; + default: + console.log("I have never heard of that dish."); + break; +}</pre> + +<h3 id="break_in_labeled_blocks">break in labeled blocks</h3> + +<p>下面的代码中一起使用 <code>break</code> 语句和被标记的块语句。一个 <code>break</code> 语句必须内嵌在它引用的标记中。注意,<code>inner_block</code> 内嵌在 <code>outer_block</code> 中。</p> + +<pre class="brush:js;highlight:[1,3,5]; notranslate">outer_block:{ + + inner_block:{ + console.log ('1'); + break outer_block; // breaks out of both inner_block and outer_block + console.log (':-('); // skipped + } + + console.log ('2'); // skipped +} +</pre> + +<h3 id="break_in_labeled_blocks_that_throw">break in labeled blocks that throw</h3> + +<p>下面的代码同样使用了 <code>break</code> 语句和被标记的块语句,但是产生了一个语法错误,因为它的 <code>break</code> 语句在 <code>block_1</code> 中,但是引用了 <code>block_2</code>。<code>break</code> 语句必须内嵌在它引用的标签中。</p> + +<pre class="brush:js;highlight:[1,3,6]; notranslate">block_1:{ + console.log ('1'); + break block_2; // SyntaxError: label not found +} + +block_2:{ + console.log ('2'); +} +</pre> + +<h3 id="break_within_functions">break within functions</h3> + +<p>在下面的代码同样会产生SyntaxError,因为它并没被正确的使用在循环、switch或label语句中。</p> + +<pre class="notranslate">function testBreak(x) { + var i = 0; + + while (i < 6) { + if (i == 3) { + (function() { + break; + })(); + } + i += 1; + } + +return i * x; +} + +testBreak(1); // SyntaxError: Illegal break statement +</pre> + +<pre class="notranslate">block_1: { + console.log('1'); + ( function() { + break block_1; // SyntaxError: Undefined label 'block_1' + })(); +}</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>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition. Unlabeled version.</td> + </tr> + <tr> + <td>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Labeled version added.</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.8', 'Break statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-break-statement', 'Break statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-break-statement', 'Break statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.break")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/continue", "continue")}}</li> + <li>{{jsxref("Statements/label", "label")}}</li> + <li>{{jsxref("Statements/switch", "switch")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/class/index.html b/files/zh-cn/web/javascript/reference/statements/class/index.html new file mode 100644 index 0000000000..a5206d5b9c --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/class/index.html @@ -0,0 +1,119 @@ +--- +title: class +slug: Web/JavaScript/Reference/Statements/class +tags: + - Class + - Classes + - Declaration + - ECMAScript 2015 + - ES6 + - JavaScript + - Reference + - Statement +translation_of: Web/JavaScript/Reference/Statements/class +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong>class 声明</strong>创建一个基于原型继承的具有给定名称的新类。</p> + +<p>{{EmbedInteractiveExample("pages/js/statement-class.html")}}</p> + +<div class="noinclude"> +<p>你也可以使用{{jsxref("Operators/class", "类表达式", "", 1)}}定义类。但是不同于类表达式,类声明不允许再次声明已经存在的类,否则将会抛出一个类型错误。</p> +</div> + +<h2 id="语法">语法</h2> + +<pre class="brush: js">class <em>name</em> [extends] { + // class body +} +</pre> + +<h2 id="描述">描述</h2> + +<p>和类表达式一样,类声明体在<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode">严格模式</a>下运行。构造函数是可选的。</p> + +<p>类声明不可以提升(这与<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function">函数声明</a>不同)。</p> + +<h2 id="示例">示例</h2> + +<h3 id="声明一个类">声明一个类</h3> + +<p>在下面的例子中,我们首先定义一个名为Polygon的类,然后继承它来创建一个名为Square的类。注意,构造函数中使用的 super() 只能在构造函数中使用,并且必须在使用 this 关键字前调用。</p> + +<pre class="brush: js">class Polygon { + constructor(height, width) { + this.name = 'Polygon'; + this.height = height; + this.width = width; + } +} + +class Square extends Polygon { + constructor(length) { + super(length, length); + this.name = 'Square'; + } +}</pre> + +<div class="warning"> +<h3 id="重复定义类">重复定义类</h3> + +<p>重复声明一个类会引起类型错误。</p> + +<pre class="brush: js">class Foo {}; +class Foo {}; +// Uncaught TypeError: Identifier 'Foo' has already been declared</pre> + +<p>若之前使用类表达式定义了一个类,则再次声明这个类同样会引起类型错误。</p> + +<pre class="brush: js">let Foo = class {}; +class Foo {}; +// Uncaught TypeError: Identifier 'Foo' has already been declared</pre> +</div> + +<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>{{SpecName('ES2015', '#sec-class-definitions', 'Class definitions')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ES2016', '#sec-class-definitions', 'Class definitions')}}</td> + <td>{{Spec2('ES2016')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES2017', '#sec-class-definitions', 'Class definitions')}}</td> + <td>{{Spec2('ES2017')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.class")}}</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/function"><code>function</code> declaration</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/class"><code>class</code> expression</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Classes">Classes</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/const/index.html b/files/zh-cn/web/javascript/reference/statements/const/index.html new file mode 100644 index 0000000000..75a1676299 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/const/index.html @@ -0,0 +1,152 @@ +--- +title: const +slug: Web/JavaScript/Reference/Statements/const +tags: + - ECMAScript 2015 + - JavaScript + - Reference + - Statement + - constants +translation_of: Web/JavaScript/Reference/Statements/const +--- +<div>{{jsSidebar("Statements")}}</div> + +<p>常量是块级范围的,非常类似用 <a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/let">let</a> 语句定义的变量。但常量的值是无法(通过重新赋值)改变的,也不能被重新声明。</p> + +<div>{{EmbedInteractiveExample("pages/js/statement-const.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox notranslate">const <em>name1 = <em>value1 [</em>, <em>name2</em> = <em>value2</em><em> [</em>, ... [</em>, <em>nameN</em> = <em>valueN]]]</em>;</pre> + +<dl> + <dt><code>nameN</code></dt> + <dd>常量名称,可以是任意合法的{{Glossary("identifier","标识符")}}。</dd> + <dt><code>valueN</code></dt> + <dd>常量值,可以是任意合法的<a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions">表达式</a>。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>此声明创建一个常量,其作用域可以是全局或本地声明的块。 与<code><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/var">var</a></code>变量不同,全局常量不会变为 window 对象的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。</p> + +<p><strong><code>const</code></strong><strong>声明</strong>创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。</p> + +<p>关于“<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let">暂存死区</a>”的所有讨论都适用于<code><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/let">let</a></code>和<code>const</code>。</p> + +<p>一个常量不能和它所在作用域内的其他变量或函数拥有相同的名称。</p> + +<h2 id="示例">示例</h2> + +<h3 id="const_基本用法">const 基本用法</h3> + +<p>常量在声明的时候可以使用大小写,但通常情况下全部用大写字母。</p> + +<pre class="brush: js; notranslate">// 定义常量MY_FAV并赋值7 +const MY_FAV = 7; + +// 报错 - Uncaught TypeError: Assignment to constant variable. +MY_FAV = 20; + +// MY_FAV is 7 +console.log('my favorite number is: ' + MY_FAV); + +// 尝试重新声明会报错 +// Uncaught SyntaxError: Identifier 'MY_FAV' has already been declared +const MY_FAV = 20; + +// MY_FAV 保留给上面的常量,这个操作会失败 +var MY_FAV = 20; + +// 也会报错 +let MY_FAV = 20; + +</pre> + +<h3 id="块作用域">块作用域</h3> + +<p>注意块作用域的性质很重要</p> + +<pre class="brush: js notranslate">if (MY_FAV === 7) { + // 没问题,并且创建了一个块作用域变量 MY_FAV + // (works equally well with let to declare a block scoped non const variable) + let MY_FAV = 20; + + // MY_FAV 现在为 20 + console.log('my favorite number is ' + MY_FAV); + + // 这被提升到全局上下文并引发错误 + var MY_FAV = 20; +} + +// MY_FAV 依旧为7 +console.log('my favorite number is ' + MY_FAV); +</pre> + +<h3 id="常量要求一个初始值">常量要求一个初始值</h3> + +<pre class="brush: js notranslate">// 报错 +// Uncaught SyntaxError: Missing initializer in const declaration + +const FOO; +</pre> + +<h3 id="常量可以定义成对象和数组">常量可以定义成对象和数组</h3> + +<p>常量可以定义成对象和数组</p> + +<pre class="brush: js notranslate">const MY_OBJECT = {'key': 'value'}; + +// 重写对象和上面一样会失败 +// Uncaught TypeError: Assignment to constant variable. +MY_OBJECT = {'OTHER_KEY': 'value'}; + +// 对象属性并不在保护的范围内 +// 下面这个声明会成功执行 +MY_OBJECT.key = 'otherValue'; // Use Object.freeze() to make object immutable + +// 也可以用来定义数组 +const MY_ARRAY = []; +// 可以向数组填充数据 +MY_ARRAY.push('A'); // ["A"] +// 但是,将一个新数组赋给变量会引发错误 +// Uncaught TypeError: Assignment to constant variable. +MY_ARRAY = ['B'];</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>{{SpecName('ES2015', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td>No changes.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.const")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/var", "var")}}</li> + <li>{{jsxref("Statements/let", "let")}}</li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Constants">Constants in the JavaScript Guide</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/continue/index.html b/files/zh-cn/web/javascript/reference/statements/continue/index.html new file mode 100644 index 0000000000..dfea4a3be3 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/continue/index.html @@ -0,0 +1,156 @@ +--- +title: continue +slug: Web/JavaScript/Reference/Statements/continue +translation_of: Web/JavaScript/Reference/Statements/continue +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong>continue 声明</strong>终止当前循环或标记循环的当前迭代中的语句执行,并在下一次迭代时继续执行循环。</p> + +<p>{{EmbedInteractiveExample("pages/js/statement-continue.html")}}</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">continue [ label ];</pre> + +<dl> +</dl> + +<dl> + <dt><code>label</code></dt> + <dd>标识标号关联的语句</dd> +</dl> + +<h2 id="Description" name="Description">描述</h2> + +<p>与 {{jsxref("Statements/break", "break")}} 语句的区别在于, continue 并不会终止循环的迭代,而是:</p> + +<ul> + <li>在 {{jsxref("Statements/while", "while")}} 循环中,控制流跳转回条件判断;</li> +</ul> + +<ul> + <li>在 {{jsxref("Statements/for", "for")}} 循环中,控制流跳转到更新语句。</li> +</ul> + +<p><code>continue</code> 语句可以包含一个可选的标号以控制程序跳转到指定循环的下一次迭代,而非当前循环。此时要求 <code>continue</code> 语句在对应的循环内部。</p> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example_Using_continue_with_while" name="Example:_Using_continue_with_while">在 <code>while</code> 语句中使用 <code>continue</code></h3> + +<p>下述例子展示了一个在<code>i</code> 为 3时执行<code>continue</code> 语句的 {{jsxref("Statements/while", "while")}} 循环。因此,<code>n</code> 的值在几次迭代后分别为 1, 3, 7 和 12 .</p> + +<pre class="brush: js language-js"><code class="language-js">i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> +n <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> +<span class="keyword token">while</span> <span class="punctuation token">(</span>i <span class="operator token"><</span> <span class="number token">5</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + i<span class="operator token">++</span><span class="punctuation token">;</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span>i <span class="operator token">===</span> <span class="number token">3</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">continue</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + n <span class="operator token">+</span><span class="operator token">=</span> i<span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<h3 id="使用带_label_的_continue">使用带 label 的 continue</h3> + +<p>在下面的例子中,被标记为 <code>checkiandj</code> 的语句包含一个被标记为 <code>checkj</code> 的语句。当遇到<code>continue</code> 语句时,程序回到 <code>checkj</code> 语句的开始继续执行。每次遇到 <code>continue</code> 时,再次执行 <code>checkj</code> ,直到条件判断返回 false 。之后完成 <code>checkiandj</code> 语句剩下的部分。</p> + +<p>但如果 <code>continue</code> 的标号被改为 <code>checkiandj</code> ,那程序将会从 <code>checkiandj</code> 语句的开始继续运行。</p> + +<p>参考 {{jsxref("Statements/label", "label")}} 。</p> + +<pre class="brush: js language-js"><code class="language-js"><span class="keyword token">var</span> i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">,</span> + j <span class="operator token">=</span> <span class="number token">8</span><span class="punctuation token">;</span> + +checkiandj<span class="punctuation token">:</span> <span class="keyword token">while</span> <span class="punctuation token">(</span>i <span class="operator token"><</span> <span class="number token">4</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"i: "</span> <span class="operator token">+</span> i<span class="punctuation token">)</span><span class="punctuation token">;</span> + i <span class="operator token">+</span><span class="operator token">=</span> <span class="number token">1</span><span class="punctuation token">;</span> + + checkj<span class="punctuation token">:</span> <span class="keyword token">while</span> <span class="punctuation token">(</span>j <span class="operator token">></span> <span class="number token">4</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"j: "</span><span class="operator token">+</span> j<span class="punctuation token">)</span><span class="punctuation token">;</span> + j <span class="operator token">-</span><span class="operator token">=</span> <span class="number token">1</span><span class="punctuation token">;</span> + <span class="keyword token">if</span> <span class="punctuation token">(</span><span class="punctuation token">(</span>j <span class="operator token">%</span> <span class="number token">2</span><span class="punctuation token">)</span> <span class="operator token">==</span> <span class="number token">0</span><span class="punctuation token">)</span> + <span class="keyword token">continue</span> checkj<span class="punctuation token">;</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span>j <span class="operator token">+</span> <span class="string token">" is odd."</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"i = "</span> <span class="operator token">+</span> i<span class="punctuation token">)</span><span class="punctuation token">;</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"j = "</span> <span class="operator token">+</span> j<span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<p>输出:</p> + +<pre class="brush: js language-js"><code class="language-js"><span class="string token">"i: 0"</span> +<span class="comment token"> +// start checkj +</span><span class="string token">"j: 8"</span> +<span class="string token">"7 is odd."</span> +<span class="string token">"j: 7"</span> +<span class="string token">"j: 6"</span> +<span class="string token">"5 is odd."</span> +<span class="string token">"j: 5"</span><span class="comment token"> +// end checkj +</span> +<span class="string token">"i = 1"</span> +<span class="string token">"j = 4"</span> + +<span class="string token">"i: 1"</span> +<span class="string token">"i = 2"</span> +<span class="string token">"j = 4"</span> + +<span class="string token">"i: 2"</span> +<span class="string token">"i = 3"</span> +<span class="string token">"j = 4"</span> + +<span class="string token">"i: 3"</span> +<span class="string token">"i = 4"</span> +<span class="string token">"j = 4"</span></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>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition. Unlabeled version.</td> + </tr> + <tr> + <td>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Labeled version added.</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.7', 'Continue statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-continue-statement', 'Continue statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-continue-statement', 'Continue statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p>{{Compat("javascript.statements.continue")}}</p> + +<h2 id="See_also" name="See_also">See also</h2> + +<ul> + <li>{{jsxref("Statements/break", "break")}}</li> + <li>{{jsxref("Statements/label", "label")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/debugger/index.html b/files/zh-cn/web/javascript/reference/statements/debugger/index.html new file mode 100644 index 0000000000..664e35af1e --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/debugger/index.html @@ -0,0 +1,79 @@ +--- +title: debugger +slug: Web/JavaScript/Reference/Statements/debugger +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/debugger +--- +<p>{{jsSidebar("Statements")}}</p> + +<p><strong>debugger 语句</strong>调用任何可用的调试功能,例如设置断点。 如果没有调试功能可用,则此语句不起作用。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox" style="font-size: 14px; white-space: normal;"><code>debugger;</code> +</pre> + +<h2 id="示例">示例</h2> + +<p>下面的例子演示了一个包含 debugger 语句的函数,当函数被调用时,会尝试调用一个可用的调试器进行调试。</p> + +<pre class="brush:js language-js" style="padding: 1em 0px 1em 30px; font-size: 14px; white-space: normal; color: rgb(77, 78, 83);"><code class="language-js" style="direction: ltr; white-space: pre;"><span class="keyword token" style="color: #0077aa;">function</span> <span class="function token" style="color: #dd4a68;">potentiallyBuggyCode<span class="punctuation token" style="color: #999999;">(</span></span><span class="punctuation token" style="color: #999999;">)</span> <span class="punctuation token" style="color: #999999;">{</span> + <span class="keyword token" style="color: #0077aa;">debugger</span><span class="punctuation token" style="color: #999999;">;</span> + <span class="comment token" style="color: #708090;"> // do potentially buggy stuff to examine, step through, etc. +</span><span class="punctuation token" style="color: #999999;">}</span></code></pre> + +<p>当 debugger 被调用时, 执行暂停在 debugger 语句的位置。就像在脚本源代码中的断点一样。</p> + +<p><a href="https://mdn.mozillademos.org/files/6963/Screen%20Shot%202014-02-07%20at%209.14.35%20AM.png"><img alt="Paused at a debugger statement." src="https://mdn.mozillademos.org/files/6963/Screen%20Shot%202014-02-07%20at%209.14.35%20AM.png" style="height: 371px; width: 700px;"></a></p> + +<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>{{SpecName('ESDraft', '#sec-debugger-statement', 'Debugger statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-debugger-statement', 'Debugger statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.15', 'Debugger statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td>Initial definition</td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-7.5.3', 'Debugger statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-7.4.3', 'Debugger statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Only mentioned as reserved word.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.debugger")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Debugging_JavaScript">JavaScript调试</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Tools/Debugger">在火狐开发者工具中调试</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/default/index.html b/files/zh-cn/web/javascript/reference/statements/default/index.html new file mode 100644 index 0000000000..914eed34fd --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/default/index.html @@ -0,0 +1,119 @@ +--- +title: default +slug: Web/JavaScript/Reference/Statements/default +tags: + - JavaScript + - Keyword +translation_of: Web/JavaScript/Reference/Statements/switch +--- +<div>{{jsSidebar("Statements")}}</div> + +<div></div> + +<p><strong>default 关键字</strong>可以在 JavaScript 的两种情况下使用:在 {{jsxref("Statements/switch", "switch")}} ,或 {{jsxref("Statements/export", "export")}} 中。</p> + +<h2 id="语法">语法</h2> + +<p>在{{jsxref("Statements/switch", "switch")}} 语句中使用:</p> + +<pre class="syntaxbox">switch (expression) { + case value1: + //当表达式的值和value1匹配执行这里的语句 + [break;] + default: + //当表达式的值没有匹配,执行这里的语句 + [break;] +}</pre> + +<p>在{{jsxref("Statements/export", "export")}} 中使用:</p> + +<pre class="syntaxbox">export default <em>nameN</em> </pre> + +<h2 id="描述">描述</h2> + +<p>更多细节,参见</p> + +<ul> + <li>{{jsxref("Statements/switch", "switch")}} 语句和</li> + <li>{{jsxref("Statements/export", "export")}} 语句页面。</li> +</ul> + +<h2 id="示例">示例</h2> + +<h3 id="在switch语句中使用default">在<code>switch</code>语句中使用<code>default</code></h3> + +<p>在以下示例中,如果<code>expr</code>为“Oranges”或“Apples”,程序将匹配“Oranges”或“Apples”的值并执行相应的声明。在任何其它情况下,<code>default</code>关键字将执行关联的语句。</p> + +<pre class="brush: js">switch (expr) { + case "Oranges": + console.log("Oranges are $0.59 a pound."); + break; + case "Apples": + console.log("Apples are $0.32 a pound."); + break; + default: + console.log("Sorry, we are out of " + expr + "."); +}</pre> + +<h3 id="在export语句中使用default">在<code>export</code>语句中使用<code>default</code></h3> + +<p>如果要导出单个值或需要模块的回调值,则可以使用默认导出: </p> + +<pre class="brush: js">// module "my-module.js" +let cube = function cube(x) { + return x * x * x; +} +export default cube; +</pre> + +<p>然后,在另一个脚本中,默认导出将直接被导入:</p> + +<pre class="brush: js">// module "my-module.js" +import myFunction from 'my-module'; +console.log(myFunction(3)); // 27 +</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>{{SpecName('ES6', '#sec-switch-statement', 'switch statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-exports', 'Exports')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-switch-statement', 'switch statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-exports', 'Exports')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.default")}}</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>{{jsxref("Statements/export", "export")}}</li> + <li>{{jsxref("Statements/switch", "switch")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/do...while/index.html b/files/zh-cn/web/javascript/reference/statements/do...while/index.html new file mode 100644 index 0000000000..bd3fb46473 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/do...while/index.html @@ -0,0 +1,99 @@ +--- +title: do...while +slug: Web/JavaScript/Reference/Statements/do...while +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/do...while +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong><code>do...while</code> 语句</strong><span lang="zh-CN"><span>创建一个执行指定语句的循环,直到</span></span><code>condition</code><span lang="zh-CN"><span>值为 false。</span><span>在执行</span></span><code>statement</code> <span lang="zh-CN"><span>后检测</span></span><code>condition</code><span lang="zh-CN"><span>,所以指定的</span></span><code>statement</code><span lang="zh-CN"><span>至少执行一次。</span></span></p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox">do + <em>statement</em> +while (<em>condition</em>); +</pre> + +<dl> + <dt><code>statement</code></dt> + <dd><span class="short_text" id="result_box" lang="zh-CN"><span>执行至少一次的语句,并在每次 </span></span><code>condition</code> <span class="short_text" lang="zh-CN"><span>值为真时重新执行。</span></span>想执行多行语句,可使用<span style="line-height: 19.0909080505371px;">{{jsxref("Statements/block", "block")}}</span>语句<span style="line-height: 19.0909080505371px;">(</span><code style="font-style: normal; line-height: 19.0909080505371px;">{ ... }</code><span style="line-height: 19.0909080505371px;">)</span>包裹这些语句。</dd> +</dl> + +<dl> + <dt><code>condition</code></dt> + <dd>循环中每次都会计算的表达式。如果 <code>condition</code> 值为真, <code>statement</code> 会再次执行。当 <code>condition</code> <span style="line-height: 19.0909080505371px;">值为假</span>,则跳到<code>do...while</code>之后的语句。</dd> +</dl> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example:_Using_do...while" name="Example:_Using_do...while">使用 <code>do...while</code></h3> + +<p>下面的例子中,<code>do...while</code> 循环至少迭代一次,并且继续迭代直到 <code>i</code>不再小于 5 时结束。</p> + +<h3 id="HTML_内容">HTML 内容</h3> + +<pre class="brush: html line-numbers language-html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>div</span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>example<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>div</span><span class="punctuation token">></span></span></code></pre> + +<h3 id="JavaScript_内容">JavaScript 内容</h3> + +<pre class="brush: js"><code class="language-js"><span class="keyword token">var</span> result <span class="operator token">=</span> <span class="string token">''</span><span class="punctuation token">;</span> +<span class="keyword token">var</span> i <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span> +<span class="keyword token">do</span> <span class="punctuation token">{</span> + i <span class="operator token">+</span><span class="operator token">=</span> <span class="number token">1</span><span class="punctuation token">;</span> + result <span class="operator token">+</span><span class="operator token">=</span> i <span class="operator token">+</span> <span class="string token">' '</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span> <span class="keyword token">while</span> <span class="punctuation token">(</span>i <span class="operator token"><</span> <span class="number token">5</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +document<span class="punctuation token">.</span><span class="function token">getElementById</span><span class="punctuation token">(</span><span class="string token">'example'</span><span class="punctuation token">)</span><span class="punctuation token">.</span>innerHTML <span class="operator token">=</span> result<span class="punctuation token">;</span></code></pre> + +<h3 id="结果">结果</h3> + +<p>{{ EmbedLiveSample('Examples') }}</p> + +<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>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Initial definition. Implemented in JavaScript 1.2</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.6.1', 'do-while statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-do-while-statement', 'do-while statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>Trailing ; is now optional.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-do-while-statement', 'do-while statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + + + +<p>{{Compat("javascript.statements.do_while")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/while", "while")}}</li> + <li>{{jsxref("Statements/for", "for")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/empty/index.html b/files/zh-cn/web/javascript/reference/statements/empty/index.html new file mode 100644 index 0000000000..3a03a63165 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/empty/index.html @@ -0,0 +1,103 @@ +--- +title: empty +slug: Web/JavaScript/Reference/Statements/Empty +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/Empty +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong>空语句</strong>用来表明没有语句,尽管 JavaScript 语法希望有语句。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">; +</pre> + +<h2 id="描述">描述</h2> + +<p><span class="short_text" id="result_box" lang="zh-CN"><span>空语句是一个分号(;),表示不会执行任何语句,即使 JavaScript 语法需要一个语句。</span></span> 相反,当你需要多行语句,但 JavaScript 只允许一个时,可以使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block">语句块</a>;语句块可以将多条语句合并为一个。</p> + +<h2 id="示例">示例</h2> + +<p>空<span class="short_text" lang="zh-CN"><span>语句有时与循环语句一起使用。以下示例使用空循环体:</span></span></p> + +<pre class="brush: js">var arr = [1, 2, 3]; + +// Assign all array values to 0 +for (let i = 0; i < arr.length; arr[i++] = 0) /* empty statement */ ; + +console.log(arr) +// [0, 0, 0] +</pre> + +<p><strong>提示:</strong>在使用空语句的情况下专门写上注释是个不错的主意,因为不是很容易区分空语句和普通的分号。下面的示例可能不是故意加上分号的:</p> + +<pre class="brush: js">if (condition); // Caution, this "if" does nothing! + killTheUniverse() // So this gets always executed!!! +</pre> + +<p>另一个例子:<a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else"><code>if...else</code></a> 语句不带花括号(<code>{}</code>)。如果<code>three</code>为<code>true</code>, 不会发生任何事,<code>four</code>不会执行,同时<code>else</code>从句中的<code>launchRocket()</code>函数也不会执行。</p> + +<pre class="brush: js">if (one) + doOne(); +else if (two) + doTwo(); +else if (three) + ; // nothing here +else if (four) + doFour(); +else + launchRocket();</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>{{SpecName('ESDraft', '#sec-empty-statement', 'Empty statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-empty-statement', 'Empty statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.3', 'Empty statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.3', 'Empty statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.3', 'Empty statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + + + +<p>{{Compat("javascript.statements.empty")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/block", "块语句")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/export/index.html b/files/zh-cn/web/javascript/reference/statements/export/index.html new file mode 100644 index 0000000000..9e584a2903 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/export/index.html @@ -0,0 +1,268 @@ +--- +title: export +slug: Web/JavaScript/Reference/Statements/export +tags: + - ECMAScript 2015 + - JavaScript + - export + - 声明 + - 模块 +translation_of: Web/JavaScript/Reference/Statements/export +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><span class="seoSummary">在创建JavaScript模块时,<code><strong>export</strong></code> 语句用于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过 {{jsxref("Statements/import", "import")}} 语句使用它们。被导出的绑定值依然可以在本地进行修改。在使用import进行导入时,这些绑定值只能被导入模块所读取,但在export导出模块中对这些绑定值进行修改,所修改的值也会实时地更新。</span></p> + +<p dir="ltr" id="tw-target-text">无论您是否声明,导出的模块都处于{{jsxref("Strict_mode","严格模式")}}。 export语句不能用在嵌入式脚本中。</p> + +<h2 id="语法">语法</h2> + +<p>存在两种 exports 导出方式:</p> + +<ol> + <li>命名导出(每个模块包含任意数量)</li> + <li>默认导出(每个模块包含一个)</li> +</ol> + +<pre class="brush: js notranslate">// 导出单个特性 +export let <em>name1</em>, <em>name2</em>, …, <em>nameN</em>; // also var, const +export let <em>name1</em> = …, <em>name2</em> = …, …, <em>nameN</em>; // also var, const +export function FunctionName(){...} +export class ClassName {...} + +// 导出列表 +export { <em>name1</em>, <em>name2</em>, …, <em>nameN</em> }; + +// 重命名导出 +export { <em>variable1</em> as <em>name1</em>, <em>variable2</em> as <em>name2</em>, …, <em>nameN</em> }; + +// 解构导出并重命名 +export const { <em>name1</em>, <em>name2</em>: <em>bar</em> } = o; + +// 默认导出 +export default expression; +export default function (…) { … } // also class, function* +export default function name1(…) { … } // also class, function* +export { <em>name1</em> as default, … }; + +// 导出模块合集 +export * from …; // does not set the default export +export * as name1 from …; // Draft ECMAScript® 2O21 +export { <em>name1</em>, <em>name2</em>, …, <em>nameN</em> } from …; +export { <em>import1</em> as <em>name1</em>, <em>import2</em> as <em>name2</em>, …, <em>nameN</em> } from …; +export { default } from …;</pre> + +<dl> + <dt><code>nameN</code></dt> + <dd>要导出的标识符(以便其他脚本通过 {{jsxref("Statements/import", "import")}} 语句进行导入).</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>有两种不同的导出方式,命名导出和默认导出。你能够在每一个模块中定义多个命名导出,但是只允许有一个默认导出。每种方式对应于上述的一种语法:</p> + +<p>命名导出:</p> + +<pre class="brush: js notranslate">// 导出事先定义的特性 +export { myFunction,myVariable }; + +// 导出单个特性(可以导出var,let, +//const,function,class) +export let myVariable = Math.sqrt(2); +export function myFunction() { ... };</pre> + +<p>默认导出:</p> + +<pre class="brush: js notranslate">// 导出事先定义的特性作为默认值 +export { myFunction as default }; + +// 导出单个特性作为默认值 +export default function () { ... } +export default class { .. } + +// 每个导出都覆盖前一个导出</pre> + +<p>在导出多个值时,命名导出非常有用。在导入期间,必须使用相应对象的相同名称。</p> + +<p>但是,可以使用任何名称导入默认导出,例如:</p> + +<pre class="brush: js notranslate">// 文件 test.js +let k; export default k = 12; </pre> + +<pre class="brush: js notranslate">// 另一个文件 +import m from './test'; // 由于 k 是默认导出,所以可以自由使用 import m 替代 import k +console.log(m); // 输出为 12 </pre> + +<p> 你也可以重命名命名导出以避免命名冲突:</p> + +<pre class="brush: js notranslate">export { <var>myFunction</var> as <var>function1</var>,<var> + myVariable</var> as variable };</pre> + +<h3 id="重导出_聚合">重导出 / 聚合</h3> + +<p>为了使模块导入变得可用,在一个父模块中“导入/导出”这些不同模块也是可行的。也就是说,你可以创建单个模块,集中多个模块的多个导出。</p> + +<p>这个可以使用“export from”语法实现:</p> + +<pre class="brush: js notranslate">export { default as function1, + function2 } from 'bar.js'; +</pre> + +<p>与之形成对比的是联合使用导入和导出:</p> + +<pre class="brush: js notranslate">import { default as function1, + function2 } from 'bar.js'; +export { function1, function2 }; +</pre> + +<p>但这里的 <code>function1</code> 和 <code>function2</code> 在当前模块中变得不可用。</p> + +<div class="blockIndicator note"> +<p>注意:尽管与import等效,但以下语法在语法上无效:</p> +</div> + +<pre class="brush: js notranslate">import DefaultExport from 'bar.js'; // 有效的 +</pre> + +<pre class="brush: js notranslate">export DefaultExport from 'bar.js'; // 无效的</pre> + +<p>这里正确的做法是重命名这个导出:</p> + +<pre class="brush: js notranslate">export { default as DefaultExport } from 'bar.js';</pre> + +<h2 id="示例">示例</h2> + +<h3 id="使用命名导出">使用命名导出</h3> + +<p>在模块 <code>my-module.js</code> 中,可能包含以下代码:</p> + +<pre class="brush: js notranslate">// module "my-module.js" +function cube(x) { + return x * x * x; +} + +const foo = Math.PI + Math.SQRT2; + +var graph = { + options: { + color:'white', + thickness:'2px' + }, + draw: function() { + console.log('From graph draw function'); + } +} + +export { cube, foo, graph }; +</pre> + +<p>然后,在你的 HTML 页面的顶级模块中:</p> + +<pre class="brush: js notranslate">import { cube, foo, graph } from 'my-module.js'; + +graph.options = { + color:'blue', + thickness:'3px' +}; + +graph.draw(); +console.log(cube(3)); // 27 +console.log(foo); // 4.555806215962888</pre> + +<p>着重注意以下几点:</p> + +<ul> + <li>在你的 HTML 中需要包含 type="module" 的 {{htmlelement("script")}} 元素这样的脚本,以便它被识别为模块并正确处理</li> + <li>不能通过 <code>file://</code> URL 运行 JS 模块 — 这将导致 <a href="/en-US/docs/Web/HTTP/CORS">CORS</a> 错误。你需要通过 HTTP 服务器运行。</li> +</ul> + +<h3 id="使用默认导出">使用默认导出</h3> + +<p>如果我们要导出一个值或得到模块中的返回值,就可以使用默认导出:</p> + +<pre class="brush: js notranslate">// module "my-module.js" + +export default function cube(x) { + return x * x * x; +} +</pre> + +<p>然后,在另一个脚本中,可以直接导入默认导出:</p> + +<pre class="brush: js notranslate" dir="rtl">import cube from './my-module.js'; +console.log(cube(3)); // 27 +</pre> + +<h3 id="模块重定向">模块重定向</h3> + +<p>举个例子,假如我们有如下层次结构:</p> + +<ul> + <li><code>childModule1.js</code>: 导出 <code>myFunction</code> 和 <code>myVariable</code></li> + <li><code>childModule2.js</code>: 导出 <code>myClass</code></li> + <li><code>parentModule.js</code>: 作为聚合器(不做其他事情)</li> + <li>顶层模块:调用 <code>parentModule.j</code> 的导出项</li> +</ul> + +<p>你的代码看起来应该像这样:</p> + +<pre class="brush: js notranslate">// childModule1.js 中 +let myFunction = ...; // assign something useful to myFunction +let myVariable = ...; // assign something useful to myVariable +export {myFunction, myVariable};</pre> + +<pre class="brush: js notranslate">// childModule2.js 中 +let myClass = ...; // assign something useful to myClass +export myClass; +</pre> + +<pre class="brush: js notranslate">// parentModule.js 中 +// 仅仅聚合 childModule1 和 childModule2 中的导出 +// 以重新导出他们 +export { myFunction, myVariable } from 'childModule1.js'; +export { myClass } from 'childModule2.js'; +</pre> + +<pre class="brush: js notranslate">// 顶层模块中 +// 我们可以从单个模块调用所有导出,因为 parentModule 事先 +// 已经将他们“收集”/“打包”到一起 +import { myFunction, myVariable, myClass } from 'parentModule.js' +</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-exports', 'Exports')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>初版</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-exports', 'Exports')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements.export")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Statements/import", "import")}}</li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Modules">JavaScript modules</a> guide</li> + <li><a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 in Depth: Modules</a>, Hacks blog post by Jason Orendorff</li> + <li><a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ES modules: A cartoon deep-dive</a>, Hacks blog post by Lin Clark</li> + <li><a href="http://exploringjs.com/es6/ch_modules.html">Axel Rauschmayer's book: "Exploring JS: Modules"</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/for-await...of/index.html b/files/zh-cn/web/javascript/reference/statements/for-await...of/index.html new file mode 100644 index 0000000000..87033e17ba --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/for-await...of/index.html @@ -0,0 +1,161 @@ +--- +title: for await...of +slug: Web/JavaScript/Reference/Statements/for-await...of +tags: + - JavaScript + - Reference + - Statement + - await + - for + - for await...of + - for...in + - for...of + - 异步 + - 迭代 +translation_of: Web/JavaScript/Reference/Statements/for-await...of +--- +<p>{{jsSidebar("Statements")}}</p> + +<p><strong><code>for await...of</code> 语句</strong>创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括: <span style="">内置的 </span>{{jsxref("String")}}, {{jsxref("Array")}},<span style="">类似数组对象 (例如 </span>{{jsxref("Functions/arguments", "arguments")}} <span style="">或</span> {{DOMxRef("NodeList")}})<span style="">,</span>{{jsxref("TypedArray")}}, {{jsxref("Map")}}, {{jsxref("Set")}} <span style="">和用户定义的异步/同步迭代器。</span>它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。</p> + +<p>类似于 {{jsxref("Operators/await", "await")}} 运算符一样,该语句只能在一个{{jsxref("Statements/async_function", "async function", "异步函数", 1)}} 内部使用。</p> + +<div class="blockIndicator note"> +<p><code>for await...of</code> 不适用于不是异步可迭代的异步迭代器。</p> +</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox notranslate">for await (<em>variable</em> of <em>iterable</em>) { + <em>statement +</em>} +</pre> + +<dl> + <dt><code>variable</code></dt> + <dd>在每次迭代中,将不同属性的值分配给变量。变量有可能以<code>const</code>, <code>let</code>, 或者 <code>var</code>来声明。</dd> + <dt><code>iterable</code></dt> + <dd>被迭代枚举其属性的对象。与 for...of 相比,这里的对象可以返回 <code>Promise</code>,如果是这样,那么 <code>variable</code> 将是 <code>Promise</code> 所包含的值,否则是值本身。</dd> +</dl> + +<h2 id="例子">例子</h2> + +<h3 id="迭代异步可迭代对象">迭代异步可迭代对象</h3> + +<p>你还可以迭代一个明确实现异步迭代协议的对象:</p> + +<pre class="brush:js notranslate">var asyncIterable = { + [Symbol.asyncIterator]() { + return { + i: 0, + next() { + if (this.i < 3) { + return Promise.resolve({ value: this.i++, done: false }); + } + + return Promise.resolve({ done: true }); + } + }; + } +}; + +(async function() { + for await (num of asyncIterable) { + console.log(num); + } +})(); + +// 0 +// 1 +// 2 +</pre> + +<h3 id="迭代异步生成器">迭代异步生成器 </h3> + +<p>异步生成器已经实现了异步迭代器协议, 所以可以用 <code>for await...of</code>循环。</p> + +<pre class="brush: js notranslate">async function* asyncGenerator() { + var i = 0; + while (i < 3) { + yield i++; + } +} + +(async function() { + for await (num of asyncGenerator()) { + console.log(num); + } +})(); +// 0 +// 1 +// 2</pre> + +<p>有关使用<code>for await... of</code>考虑迭代API中获取数据的异步 generator 更具体的例子。这个例子首先为一个数据流创建了一个异步 generator,然后使用它来获得这个API的响应值的大小。</p> + +<pre class="brush: js notranslate">async function* streamAsyncIterator(stream) { + const reader = stream.getReader(); + try { + while (true) { + const { done, value } = await reader.read(); + if (done) { + return; + } + yield value; + } + } finally { + reader.releaseLock(); + } +} +// 从url获取数据并使用异步 generator 来计算响应值的大小 +async function getResponseSize(url) { + const response = await fetch(url); + // Will hold the size of the response, in bytes. + let responseSize = 0; + // 使用for-await-of循环. 异步 generator 会遍历响应值的每一部分 + for await (const chunk of streamAsyncIterator(response.body)) { + // Incrementing the total response length. + responseSize += chunk.length; + } + + console.log(`Response Size: ${responseSize} bytes`); + // expected output: "Response Size: 1071472" + return responseSize; +} +getResponseSize('https://jsonplaceholder.typicode.com/photos');</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>{{SpecName('ESDraft', '#sec-for-in-and-for-of-statements', 'ECMAScript Language: The for-in, for-of, and for-await-of Statements')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES2018', '#sec-for-in-and-for-of-statements', 'ECMAScript Language: The for-in, for-of, and for-await-of Statements')}}</td> + <td>{{Spec2('ES2018')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">此页面上的兼容性表是根据结构化数据生成的。如果您想为数据做出贡献,请查看https://github.com/mdn/browser-compat-data并向我们发送拉取请求。</div> + +<p>{{Compat("javascript.statements.for_await_of")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Global_Objects/Symbol/asyncIterator", "Symbol.asyncIterator")}}</li> + <li>{{jsxref("Statements/for...of")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/for...in/index.html b/files/zh-cn/web/javascript/reference/statements/for...in/index.html new file mode 100644 index 0000000000..91575e3233 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/for...in/index.html @@ -0,0 +1,157 @@ +--- +title: for...in +slug: Web/JavaScript/Reference/Statements/for...in +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/for...in +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>for...in</code>语句</strong>以任意顺序遍历一个对象的除<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol">Symbol</a>以外的<a href="/zh-CN/docs/Web/JavaScript/Enumerability_and_ownership_of_properties">可枚举</a>属性。</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="notranslate">for (<var>variable</var> in <var>object</var>) + statement</pre> + +<dl> + <dt><code>variable</code></dt> + <dd>在每次迭代时,variable会被赋值为不同的属性名。</dd> +</dl> + +<dl> + <dt><code>object</code></dt> + <dd>非Symbol类型的可枚举属性被迭代的对象。</dd> +</dl> + +<h2 id="sect1"></h2> + +<h3 id="数组迭代和_for...in" style="line-height: 24px; font-size: 1.71428571428571rem;">数组迭代和 <code>for...in</code></h3> + +<div class="note"> +<p><strong>提示:</strong><code>for...in</code>不应该用于迭代一个关注索引顺序的 {{jsxref("Array")}}。</p> +</div> + +<h3 id="仅迭代自身的属性" style="line-height: 24px; font-size: 1.71428571428571rem;">仅迭代自身的属性</h3> + +<p>如果你只要考虑对象本身的属性,而不是它的原型,那么使用 {{jsxref("Object.getOwnPropertyNames", "getOwnPropertyNames()")}} 或执行 {{jsxref("Object.prototype.hasOwnProperty", "hasOwnProperty()")}} 来确定某属性是否是对象本身的属性(也能使用{{jsxref("Object.prototype.propertyIsEnumerable", "propertyIsEnumerable")}})。或者,如果你知道不会有任何外部代码干扰,您可以使用检查方法扩展内置原型。</p> + +<h2 id="Example" name="Example">为什么用for ... in?</h2> + +<p><code>for ... in</code>是为遍历对象属性而构建的,不建议与数组一起使用,数组可以用<code>Array.prototype.forEach()</code>和<code>for ... of</code>,那么<code>for ... in</code>的到底有什么用呢?</p> + +<p>它最常用的地方应该是用于调试,可以更方便的去检查对象属性(通过输出到控制台或其他方式)。尽管对于处理存储数据,数组更实用些,但是你在处理有<code>key-value</code>数据(比如属性用作“键”),需要检查其中的任何键是否为某值的情况时,还是推荐用<code>for ... in</code>。</p> + +<h2 id="Example" name="Example">示例</h2> + +<p>下面的函数接受一个对象作为参数。被调用时迭代传入对象的所有可枚举属性然后返回一个所有属性名和其对应值的字符串。</p> + +<pre class="brush: js notranslate">var obj = {a:1, b:2, c:3}; + +for (var prop in obj) { + console.log("obj." + prop + " = " + obj[prop]); +} + +// Output: +// "obj.a = 1" +// "obj.b = 2" +// "obj.c = 3"</pre> + +<p>下面的函数说明了{{jsxref("Object.prototype.hasOwnProperty", "hasOwnProperty()")}}的用法:继承的属性不显示。</p> + +<pre class="brush: js notranslate">var triangle = {a: 1, b: 2, c: 3}; + +function ColoredTriangle() { + this.color = 'red'; +} + +ColoredTriangle.prototype = triangle; + +var obj = new ColoredTriangle(); + +for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + console.log(`obj.${prop} = ${obj[prop]}`); + } +} + +// Output: +// "obj.color = red"</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>{{SpecName('ESDraft', '#sec-for-in-and-for-of-statements', 'for...in statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-for-in-and-for-of-statements', 'for...in statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.6.4', 'for...in statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.6.4', 'for...in statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.6.3', 'for...in statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.for_in")}}</p> + +<h2 id="兼容性:初始化函数表达式">兼容性:初始化函数表达式</h2> + +<p>在 SpiderMonkey 40 {{geckoRelease(40)}} 版本之前,可以在使用一个初始化表达式(<code>i=0</code>)在一个<code>for...in</code>循环中:</p> + +<pre class="brush: js example-bad notranslate">var obj = {a: 1, b: 2, c: 3}; +for (var i = 0 in obj) { + console.log(obj[i]); +} +// 1 +// 2 +// 3 +</pre> + +<p><span style="line-height: 1.5;">这个非标准行为现在在版本40及更高版本中被忽略,并将在严格模式({{bug(748550)}} 和 </span>{{bug(1164741)}})<span style="line-height: 1.5;">中呈现{{jsxref("SyntaxError")}}("<a href="/zh-CN/docs/Web/JavaScript/Reference/Errors/Invalid_for-in_initializer">for-in loop head declarations may not have initializers</a>")错误。</span></p> + +<p><span style="line-height: 1.5;">像其他引擎 V8(Chrome),</span>Chakra (IE/Edge), JSC (WebKit/Safari) 正在研究去除这种不标准的行为。</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/for...of", "for...of")}} 一个类似的迭代属性值的语句</li> + <li>{{jsxref("Statements/for_each...in", "for each in")}} 一个类似的但是迭代的是对象的属性的值而不是其属性名字的语句(过时的)</li> + <li>{{jsxref("Statements/for", "for")}}</li> + <li>迭代器和构造器(uses the <code>for...in</code> syntax)</li> + <li><a href="/zh-CN/docs/Web/JavaScript/Enumerability_and_ownership_of_properties">属性的可枚举性和所有权</a></li> + <li>{{jsxref("Object.getOwnPropertyNames()")}}</li> + <li>{{jsxref("Object.prototype.hasOwnProperty()")}}</li> + <li>{{jsxref("Array.prototype.forEach()")}}</li> +</ul> + +<div id="gtx-trans" style="position: absolute; left: 606px; top: 659px;"> +<div class="gtx-trans-icon"></div> +</div> diff --git a/files/zh-cn/web/javascript/reference/statements/for...of/index.html b/files/zh-cn/web/javascript/reference/statements/for...of/index.html new file mode 100644 index 0000000000..49152b716f --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/for...of/index.html @@ -0,0 +1,313 @@ +--- +title: for...of +slug: Web/JavaScript/Reference/Statements/for...of +tags: + - ECMAScript 2015 + - JavaScript + - Reference + - Statement +translation_of: Web/JavaScript/Reference/Statements/for...of +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong><code>for...of</code>语句</strong>在<a href="/zh-CN/docs/Web/JavaScript/Guide/iterable">可迭代对象</a>(包括 {{jsxref("Array")}},{{jsxref("Map")}},{{jsxref("Set")}},{{jsxref("String")}},{{jsxref("TypedArray")}},<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments">arguments</a> 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句</p> + +<div>{{EmbedInteractiveExample("pages/js/statement-forof.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">for (variable of iterable) { + //<em>statements</em> +} +</pre> + +<dl> + <dt><code>variable</code></dt> + <dd>在每次迭代中,将不同属性的值分配给变量。</dd> + <dt><code>iterable</code></dt> + <dd>被迭代枚举其属性的对象。</dd> +</dl> + +<h2 id="示例">示例</h2> + +<h3 id="迭代jsxrefArray">迭代{{jsxref("Array")}}</h3> + +<pre class="brush: js">let iterable = [10, 20, 30]; + +for (let value of iterable) { + value += 1; + console.log(value); +} +// 11 +// 21 +// 31 +</pre> + +<p>如果你不想修改语句块中的变量 , 也可以使用<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const"><code>const</code></a>代替<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a></code>。</p> + +<pre class="brush: js">let iterable = [10, 20, 30]; + +for (const value of iterable) { + console.log(value); +} +// 10 +// 20 +// 30</pre> + +<h3 id="迭代jsxrefString">迭代{{jsxref("String")}}</h3> + +<pre class="brush: js">let iterable = "boo"; + +for (let value of iterable) { + console.log(value); +} +// "b" +// "o" +// "o"</pre> + +<h3 id="迭代_jsxrefTypedArray">迭代 {{jsxref("TypedArray")}}</h3> + +<pre class="brush: js">let iterable = new Uint8Array([0x00, 0xff]); + +for (let value of iterable) { + console.log(value); +} +// 0 +// 255 +</pre> + +<h3 id="迭代jsxrefMap">迭代{{jsxref("Map")}}</h3> + +<pre class="brush: js">let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]); + +for (let entry of iterable) { + console.log(entry); +} +// ["a", 1] +// ["b", 2] +// ["c", 3] + +for (let [key, value] of iterable) { + console.log(value); +} +// 1 +// 2 +// 3 +</pre> + +<h3 id="迭代_jsxrefSet">迭代 {{jsxref("Set")}}</h3> + +<pre class="brush: js">let iterable = new Set([1, 1, 2, 2, 3, 3]); + +for (let value of iterable) { + console.log(value); +} +// 1 +// 2 +// 3</pre> + +<h3 id="迭代_jsxrefarguments_对象">迭代 {{jsxref("arguments")}} 对象</h3> + +<pre class="brush: js">(function() { + for (let argument of arguments) { + console.log(argument); + } +})(1, 2, 3); + +// 1 +// 2 +// 3</pre> + +<h3 id="迭代_DOM_集合">迭代 DOM 集合</h3> + +<p>迭代 DOM 元素集合,比如一个{{domxref("NodeList")}}对象:下面的例子演示给每一个 article 标签内的 p 标签添加一个 "<code>read</code>" 类。</p> + +<pre class="brush:js">//注意:这只能在实现了NodeList.prototype[Symbol.iterator]的平台上运行 +let articleParagraphs = document.querySelectorAll("article > p"); + +for (let paragraph of articleParagraphs) { + paragraph.classList.add("read"); +} +</pre> + +<h3 id="关闭迭代器">关闭迭代器</h3> + +<p>对于<code>for...of</code>的循环,可以由<code>break</code>, <code>throw continue </code> 或<code>return</code>终止。在这些情况下,迭代器关闭。</p> + +<pre class="brush: js">function* foo(){ + yield 1; + yield 2; + yield 3; +}; + +for (let o of foo()) { + console.log(o); + break; // closes iterator, triggers return +} +</pre> + +<h3 id="迭代生成器">迭代生成器</h3> + +<p><span><span>你还可以</span></span>迭代<span><span>一个</span></span><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/function*">生成器</a>:</p> + +<pre class="brush:js">function* fibonacci() { // 一个生成器函数 + let [prev, curr] = [0, 1]; + for (;;) { // while (true) { + [prev, curr] = [curr, prev + curr]; + yield curr; + } +} + +for (let n of fibonacci()) { + console.log(n); + // 当n大于1000时跳出循环 + if (n >= 1000) + break; +}</pre> + +<h4 id="不要重用生成器">不要重用生成器</h4> + +<p>生成器不应该重用,即使<code>for...of</code>循环的提前终止,例如通过{{jsxref("Statements/break", "break")}}关键字。在退出循环后,生成器关闭,并尝试再次迭代,不会产生任何进一步的结果。</p> + +<pre class="brush: js">var gen = (function *(){ + yield 1; + yield 2; + yield 3; +})(); +for (let o of gen) { + console.log(o); + break;//关闭生成器 +} + +//生成器不应该重用,以下没有意义! +for (let o of gen) { + console.log(o); +} + +</pre> + +<h3 id="迭代其他可迭代对象">迭代其他可迭代对象</h3> + +<p>你还可以迭代显式实现<a href="/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols#iterable">可迭代</a>协议的对象:</p> + +<pre class="brush: js">var iterable = { + [Symbol.iterator]() { + return { + i: 0, + next() { + if (this.i < 3) { + return { value: this.i++, done: false }; + } + return { value: undefined, done: true }; + } + }; + } +}; + +for (var value of iterable) { + console.log(value); +} +// 0 +// 1 +// 2</pre> + +<h3 id="for...of与for...in的区别"><code>for...of</code>与<code>for...in</code>的区别</h3> + +<p>无论是<code>for...in</code>还是<code>for...of</code>语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。</p> + +<p>{{jsxref("Statements/for...in", "for...in")}} 语句以任意顺序迭代对象的<a href="/zh-CN/docs/Web/JavaScript/Enumerability_and_ownership_of_properties">可枚举属性</a>。</p> + +<p><code>for...of</code> 语句遍历<a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables">可迭代对象</a>定义要迭代的数据。</p> + +<p>以下示例显示了与{{jsxref("Array")}}一起使用时,<code>for...of</code>循环和<code>for...in</code>循环之间的区别。</p> + +<pre class="brush: js">Object.prototype.objCustom = function() {}; +Array.prototype.arrCustom = function() {}; + +let iterable = [3, 5, 7]; +iterable.foo = 'hello'; + +for (let i in iterable) { + console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom" +} + +for (let i in iterable) { + if (iterable.hasOwnProperty(i)) { + console.log(i); // logs 0, 1, 2, "foo" + } +} + +for (let i of iterable) { + console.log(i); // logs 3, 5, 7 +}</pre> + +<pre class="brush: js">Object.prototype.objCustom = function() {}; +Array.prototype.arrCustom = function() {}; + +let iterable = [3, 5, 7]; +iterable.foo = 'hello'; +</pre> + +<p>每个对象将继承<code>objCustom</code>属性,并且作为{{jsxref("Array")}}的每个对象将继承<code>arrCustom</code>属性,因为将这些属性添加到{{jsxref("Object.prototype")}}和{{jsxref("Array.prototype")}}。由于<a href="/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">继承和原型链</a>,对象<code>iterable</code>继承属性<code>objCustom</code>和<code>arrCustom</code>。</p> + +<pre class="brush: js">for (let i in iterable) { + console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom" +} +</pre> + +<p>此循环仅以原始插入顺序记录<code>iterable</code> 对象的<a href="/zh-CN/docs/Web/JavaScript/Enumerability_and_ownership_of_properties">可枚举属性</a>。它不记录数组<strong>元素</strong><code>3</code>, <code>5</code>, <code>7</code> 或<code>hello</code>,因为这些<strong>不是</strong>枚举属性。但是它记录了数组<strong>索引</strong>以及<code>arrCustom</code>和<code>objCustom</code>。如果你不知道为什么这些属性被迭代,{{jsxref("Statements/for...in", "array iteration and for...in", "#Array_iteration_and_for...in")}}中有更多解释。</p> + +<pre class="brush: js">for (let i in iterable) { + if (iterable.hasOwnProperty(i)) { + console.log(i); // logs 0, 1, 2, "foo" + } +} +</pre> + +<p>这个循环类似于第一个,但是它使用{{jsxref("Object.prototype.hasOwnProperty()", "hasOwnProperty()")}} 来检查,如果找到的枚举属性是对象自己的(不是继承的)。如果是,该属性被记录。记录的属性是<code>0</code>, <code>1</code>, <code>2</code>和<code>foo</code>,因为它们是自身的属性(<strong>不是继承的</strong>)。属性<code>arrCustom</code>和<code>objCustom</code>不会被记录,因为它们<strong>是继承的</strong>。</p> + +<pre class="brush: js">for (let i of iterable) { + console.log(i); // logs 3, 5, 7 +} +</pre> + +<p>该循环迭代并记录<code>iterable</code>作为<a href="/zh-CN/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables">可迭代对象</a>定义的迭代值,这些是数组元素 <code>3</code>, <code>5</code>, <code>7</code>,而不是任何对象的<strong>属性</strong>。</p> + +<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>{{SpecName('ES2015', '#sec-for-in-and-for-of-statements', 'for...of statement')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-for-in-and-for-of-statements', 'for...of statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.for_of")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Array.prototype.forEach()")}}</li> + <li>{{jsxref("Map.prototype.forEach()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/for/index.html b/files/zh-cn/web/javascript/reference/statements/for/index.html new file mode 100644 index 0000000000..0a904c3473 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/for/index.html @@ -0,0 +1,169 @@ +--- +title: for +slug: Web/JavaScript/Reference/Statements/for +tags: + - JavaScript + - Loop + - Reference + - Statement + - for +translation_of: Web/JavaScript/Reference/Statements/for +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>for</code> 语句</strong>用于创建一个循环,它包含了三个可选的表达式,这三个表达式被包围在圆括号之中,使用分号分隔,后跟一个用于在循环中执行的语句(通常是一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block">块语句</a>)。</p> + +<div>{{EmbedInteractiveExample("pages/js/statement-for.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">for ([<em>initialization</em>]; [<em>condition</em>]; [<em>final-expression</em>]) + <em>statement</em> +</pre> + +<dl> + <dt><code>initialization</code></dt> + <dd>一个表达式 (包含赋值语句) 或者变量声明。典型地被用于初始化一个计数器。该表达式可以使用 <code>var</code> 或 <code>let</code> 关键字声明新的变量,使用 <code>var</code> 声明的变量不是该循环的局部变量,而是与 <code>for</code> 循环处在同样的作用域中。用 <code>let</code> 声明的变量是语句的局部变量。该表达式的结果无意义。</dd> + <dt><code>condition</code></dt> + <dd>一个条件表达式被用于确定每一次循环是否能被执行。如果该表达式的结果为 true,<code>statement</code> 将被执行。这个表达式是可选的。如果被忽略,那么就被认为永远为真。如果计算结果为假,那么执行流程将被跳到 <code>for</code> 语句结构后面的第一条语句。</dd> + <dt><code>final-expression</code></dt> + <dd>每次循环的最后都要执行的表达式。执行时机是在下一次 <code>condition</code> 的计算之前。通常被用于更新或者递增计数器变量。</dd> + <dt><code>statement</code></dt> + <dd>只要<code>condition</code>的结果为true就会被执行的语句。要在循环体内执行多条语句,使用一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block">块语句</a>(<code>{ ... }</code>)来包含要执行的语句。没有任何语句要执行,使用一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/Empty">空语句</a>(<code>;</code>)。</dd> +</dl> + +<h2 id="示例">示例</h2> + +<h3 id="使用_for">使用 <code>for</code></h3> + +<p>以下例子声明了变量 <code>i</code> 并被初始赋值为 <code>0</code>,<code>for</code> 语句检查 <code>i</code> 的值是否小于 9,如果小于 9,则执行语句块内的语句,并且最后将 <code>i</code> 的值增加 1。</p> + +<pre class="brush: js">for (var i = 0; i < 9; i++) { + console.log(i); + // more statements +} +</pre> + +<h3 id="可选的_for_表达式">可选的 <code>for</code> 表达式</h3> + +<p><code>for</code> 语句头部圆括号中的所有三个表达式都是可选的。</p> + +<p>例如,初始化块中的表达式没有被指定:</p> + +<pre class="brush: js">var i = 0; +for (; i < 9; i++) { + console.log(i); + // more statements +} +</pre> + +<p>像初始化块一样,条件块也是可选的。如果省略此表达式,则必须确保在循环体内跳出,以防创建死循环。</p> + +<pre class="brush: js">for (var i = 0;; i++) { + console.log(i); + if (i > 3) break; + // more statements +}</pre> + +<p>你当然可以忽略所有的表达式。同样的,确保使用了 {{jsxref("Statements/break", "break")}} >语句来跳出循环并且还要修改(增加)一个变量,使得 break 语句的条件在某个时候是真的。</p> + +<pre class="brush: js">var i = 0; + +for (;;) { + if (i > 3) break; + console.log(i); + i++; +} +</pre> + +<h3 id="使用无语句的_for">使用无语句的 <code>for</code></h3> + +<p>以下 <code>for</code> 循环计算 <em>final-expression</em> 部分中节点的偏移位置,它不需要执行一个 <code>statement</code> 或者一组 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block">block</a> statement</code> ,因此使用了空语句。</p> + +<pre class="brush: js">function showOffsetPos(sId) { + + var nLeft = 0, nTop = 0; + + for ( + + var oItNode = document.getElementById(sId); /* initialization */ + + oItNode; /* condition */ + + nLeft += oItNode.offsetLeft, nTop += oItNode.offsetTop, oItNode = oItNode.offsetParent /* final-expression */ + + ); /* 分号 semicolon */ + + console.log('Offset position of \'' + sId + '\' element:\n left: ' + nLeft + 'px;\n top: ' + nTop + 'px;'); + +} + +/* Example call: */ + +showOffsetPos('content'); + +// Output: +// "Offset position of "content" element: +// left: 0px; +// top: 153px;"</pre> + +<div class="note"> +<p><strong>提示:</strong><strong>这里的分号是强制性的</strong>,是 JavaScript 中的少数几种强制分号的情况。如果没有分号,循环声明之后的行将被视为循环语句。</p> +</div> + +<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>{{SpecName('ESDraft', '#sec-for-statement', 'for statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-for-statement', 'for statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.6.3', 'for statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.6.3', 'for statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.6.2', 'for statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements.for")}}</p> + +<h2 id="另请参阅">另请参阅</h2> + +<ul> + <li>{{jsxref("Statements/empty", "empty statement", "", 0)}}</li> + <li>{{jsxref("Statements/break", "break")}}</li> + <li>{{jsxref("Statements/continue", "continue")}}</li> + <li>{{jsxref("Statements/while", "while")}}</li> + <li>{{jsxref("Statements/do...while", "do...while")}}</li> + <li>{{jsxref("Statements/for...in", "for...in")}}</li> + <li>{{jsxref("Statements/for...of", "for...of")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/for_each...in/index.html b/files/zh-cn/web/javascript/reference/statements/for_each...in/index.html new file mode 100644 index 0000000000..05c1043588 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/for_each...in/index.html @@ -0,0 +1,69 @@ +--- +title: for each...in +slug: Web/JavaScript/Reference/Statements/for_each...in +translation_of: Archive/Web/JavaScript/for_each...in +--- +<div>{{jsSidebar("Statements")}}</div> + +<p>使用一个变量迭代一个对象的所有属性值,对于每一个属性值,有一个指定的语句块被执行。</p> + +<div class="noinclude"> +<div class="warning"> +<p>作为ECMA-357(<a href="/zh-CN/docs/E4X" title="/zh-CN/docs/E4X">E4X</a>)标准的一部分,for each...in语句已被废弃,E4X中的大部分特性已被删除,但考虑到向后兼容,for each...in只会被禁用而不会被删除,可以使用ES6中新的<a href="/zh-CN/docs/JavaScript/Reference/Statements/for...of" title="/zh-CN/docs/JavaScript/Reference/Statements/for...of">for...of</a>语句来代替。({{ bug("791343")}}.)</p> +</div> + +<div class="note"><code>for each...in</code> 是 <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-357.htm" title="http://www.ecma-international.org/publications/standards/Ecma-357.htm">ECMA-357 (E4X)</a> 标准的一部分,大部分非Mozilla浏览器都没有实现该标准,E4X并不是 ECMAScript 标准的一部分。</div> +</div> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><code>for each (<em>variable</em> in <em>object</em>) { + <em>statement</em> +}</code></pre> + +<h2 id="Parameters" name="Parameters">参数</h2> + +<dl> + <dt><code>variable</code></dt> + <dd>用来遍历属性值的变量,前面的<code>var</code>关键字是可选的。该变量是函数的局部变量而不是语句块的局部变量。</dd> +</dl> + +<dl> + <dt><code>object</code></dt> + <dd>属性值会被遍历的对象。</dd> +</dl> + +<dl> + <dt><code>statement</code></dt> + <dd>遍历属性时执行的语句。如果想要执行多条语句,请用<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block">块语句</a>(<code>{ ... }</code>) 将多条语句括住。</dd> +</dl> + +<h2 id="Description" name="Description">描述</h2> + +<p>一些对象的内置属性是无法被遍历到的,包括所有的内置方法,例如String对象的<code>indexOf</code>方法。不过,大部分的用户自定义属性都是可遍历的.</p> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example:_Using_for_each...in" name="Example:_Using_for_each...in">例子: 使用<code>for each...in</code></h3> + +<p><strong>警告:</strong>永远不要使用for each...in语句遍历数组,仅用来遍历常规对象。<a href="/zh-CN/docs/JavaScript/Reference/Statements/for...in#Description" title="JavaScript/Reference/Statements/for...in#Description">这里讲解了为什么这么说</a>。</p> + +<p>下面的代码片段演示如何遍历一个对象的属性值,并计算它们的和:</p> + +<pre class="brush:js">var sum = 0; +var obj = {prop1: 5, prop2: 13, prop3: 8}; + +for each (var item in obj) { + sum += item; +} + +print(sum); // 输出"26",也就是5+13+8的值</pre> + +<h2 id="See_also" name="See_also">参见</h2> + +<ul> + <li><a href="/zh-CN/docs/JavaScript/Reference/Statements/for...in" title="JavaScript/Reference/Statements/for...in">for...in</a> - 一个相似的语法,用来遍历对象的属性名称而非属性值.</li> + <li><a href="/zh-CN/docs/JavaScript/Reference/Statements/for...of" title="/zh-CN/docs/JavaScript/Reference/Statements/for...of">for...of</a> - 一个相似的语法,用来遍历可迭代对象,有时候效果等同于<code>for each</code>...<code>in</code>语句.</li> + <li><a href="/zh-CN/docs/JavaScript/Reference/Statements/for" title="JavaScript/Reference/Statements/for">for</a></li> + <li><a href="/zh-CN/docs/JavaScript/Guide/Predefined_Core_Objects#Array_Object">数组推导式</a> (该语句中可以使用for...in<code>,</code><code>for each</code>...<code>in,</code><code>for</code>...<code>of多种语法</code>)</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/function/index.html b/files/zh-cn/web/javascript/reference/statements/function/index.html new file mode 100644 index 0000000000..b53c1891b8 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/function/index.html @@ -0,0 +1,179 @@ +--- +title: function +slug: Web/JavaScript/Reference/Statements/function +tags: + - 函数 + - 函数声明提升 + - 函数表达式 + - 提升 + - 语句 +translation_of: Web/JavaScript/Reference/Statements/function +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong>函数声明</strong>定义一个具有指定参数的函数。</p> + +<div class="noinclude"> +<p>你还可以使用 {{jsxref("Function")}} 构造函数和 一个{{jsxref("Operators/function", "function expression")}} 定义函数。</p> +</div> + +<div class="hidden">The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</div> + +<h2 id="语法"><span style="font-size: 2.14285714285714rem;">语法</span></h2> + +<pre class="eval notranslate">function <em>name</em>([<em>param</em>,[, <em>param</em>,[..., <em>param</em>]]]) { + [<em>statements</em>] +} +</pre> + +<dl> + <dt><code>name</code></dt> + <dd>函数名</dd> +</dl> + +<dl> + <dt><code>param</code></dt> + <dd>要传递给函数的参数的名称。不同引擎中的最大参数数量不同。</dd> +</dl> + +<dl> + <dt><code>statements</code></dt> + <dd>包含函数体的语句。</dd> +</dl> + +<h2 id="Description" name="Description">描述</h2> + +<p>一个被函数声明创建的函数是一个 Function 对象,具有 Function 对象的所有属性、方法和行为。查看 <a href="/en/JavaScript/Reference/Global_Objects/Function">Function</a> 以获取 function 的详细信息。</p> + +<p>函数也可以被表达式创建( <a href="/en/JavaScript/Reference/Operators/function">function expression</a> )</p> + +<p>函数可以被有条件来声明,这意味着,在一个 if 语句里,函数声明是可以嵌套的。有的浏览器会将这种有条件的声明看成是无条件的声明,无论这里的条件是true还是false,浏览器都会创建函数。因此,它们不应该被使用。</p> + +<p>默认情况下,函数是返回 undefined 的。想要返回一个其他的值,函数必须通过一个 <a href="/en/JavaScript/Reference/Statements/return">return</a> 语句指定返回值。</p> + +<h3 id="有条件的创建函数" style="line-height: 24px; font-size: 1.71428571428571rem;">有条件的创建函数</h3> + +<p>函数可以被有条件来声明,这意味着,函数声明可能出现在一个 if 语句里,但是,这种声明方式在不同的浏览器里可能有不同的效果。因此,不应该在生成环境代码中使用这种声明方式,应该使用函数表达式来代替。</p> + +<pre class="brush: js notranslate"><code>var hoisted = "foo" in this; +console.log(`'foo' name ${hoisted ? "is" : "is not"} hoisted. typeof foo is ${typeof foo}`); +if (false) { + function foo(){ return 1; } +} + +// 在Chrome里: +// 'foo' 变量名被提升,但是 typeof foo 为 undefined +// +// 在Firefox里: +// 'foo' 变量名被提升. 但是 typeof foo 为 undefined +// +// 在Edge里: +// 'foo' 变量名未被提升. 而且 typeof foo 为 undefined +// +// 在Safari里: +// 'foo' 变量名被提升. 而且 typeof foo 为 function</code></pre> + +<p>注意,即使把上面代码中的 if(false) 改为 if(true),结果也是一样的</p> + +<pre class="brush: js notranslate"><code>var hoisted = "foo" in this; +console.log(`'foo' name ${hoisted ? "is" : "is not"} hoisted. typeof foo is ${typeof foo}`); +if (true) { + function foo(){ return 1; } +} + +// 在Chrome里: +// 'foo' 变量名被提升,但是 typeof foo 为 undefined +// +// 在Firefox里: +// 'foo' 变量名被提升. 但是 typeof foo 为 undefined +// +// 在Edge里: +// 'foo' 变量名未被提升. 而且 typeof foo 为 undefined +// +// 在Safari里: +// 'foo' 变量名被提升. 而且 typeof foo 为 function</code> +</pre> + +<h3 id="函数声明提升">函数声明提升</h3> + +<p>JavaScript 中的<strong>函数声明</strong>被提升到了<strong>函数定义</strong>。你可以在函数声明之前使用该函数:</p> + +<pre class="brush: js language-js notranslate"><code class="language-js" style="direction: ltr; white-space: pre;"><span class="function token">hoisted<span class="punctuation token">(</span></span><span class="punctuation token">)</span><span class="punctuation token">;</span><span class="comment token"> // "foo" + +</span><span class="keyword token">function</span> <span class="function token">hoisted<span class="punctuation token">(</span></span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"foo"</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="punctuation token">} +</span> +<span class="comment token">/* equal to*/ +var </span><span class="function token">hoisted</span><span class="punctuation token">;</span><span class="comment token"> </span> + +<span class="function token">hoisted = </span><span class="keyword token">function</span><span class="function token"><span class="punctuation token">(</span></span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"foo"</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="punctuation token">} +</span><span class="function token">hoisted<span class="punctuation token">(</span></span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="comment token">// "foo" </span></code> +</pre> + +<div class="note"> +<p>注意 :<strong>函数表达式</strong>{{jsxref("Operators/function", "function expressions")}} 不会被提升:</p> +</div> + +<pre class="brush: js language-js notranslate"><code class="language-js" style="direction: ltr; white-space: pre;"><span class="function token">notHoisted<span class="punctuation token">(</span></span><span class="punctuation token">)</span><span class="punctuation token">;</span><span class="comment token"> // TypeError: notHoisted is not a function +</span> +<span class="keyword token">var</span> notHoisted <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> + console<span class="punctuation token">.</span><span class="function token">log<span class="punctuation token">(</span></span><span class="string token">"bar"</span><span class="punctuation token">)</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example_Using_function" name="Example:_Using_function">使用函数</h3> + +<p>下面的代码声明了一个函数,该函数返回了销售的总金额, 参数是产品a,b,c分别的销售的数量.</p> + +<pre class="brush: js language-js notranslate"><code class="language-js" style="direction: ltr; white-space: pre;"><span class="keyword token">function</span> <span class="function token">calc_sales<span class="punctuation token">(</span></span>units_a<span class="punctuation token">,</span> units_b<span class="punctuation token">,</span> units_c<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">return</span> units_a<span class="operator token">*</span><span class="number token">79</span> <span class="operator token">+</span> units_b <span class="operator token">*</span> <span class="number token">129</span> <span class="operator token">+</span> units_c <span class="operator token">*</span> <span class="number token">699</span><span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<h2 id="规范" style="margin-bottom: 20px; line-height: 30px; font-size: 2.14285714285714rem;">规范</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>ECMAScript 1st Edition.</td> + <td>Standard</td> + <td>Initial definition. Implemented in JavaScript 1.0</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-13', 'Function definition')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-function-definitions', 'Function definitions')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性" style="margin-bottom: 20px; line-height: 30px; font-size: 2.14285714285714rem;">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements.function")}}</p> + +<h2 id="See_also" name="See_also" style="margin-bottom: 20px; line-height: 30px; font-size: 2.14285714285714rem;">相关链接</h2> + +<ul> + <li>{{jsxref("Functions_and_function_scope", "Functions and function scope")}}</li> + <li>{{jsxref("Function")}}</li> + <li>{{jsxref("Operators/function", "function expression")}}</li> + <li>{{jsxref("Statements/function*", "function* statement")}}</li> + <li>{{jsxref("Operators/function*", "function* expression")}}</li> + <li>{{jsxref("GeneratorFunction")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/function_star_/index.html b/files/zh-cn/web/javascript/reference/statements/function_star_/index.html new file mode 100644 index 0000000000..4e1f69883a --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/function_star_/index.html @@ -0,0 +1,242 @@ +--- +title: function* +slug: Web/JavaScript/Reference/Statements/function* +tags: + - ECMAScript 2015 + - Generator + - JavaScript + - function* + - 函数 + - 声明 + - 迭代器 +translation_of: Web/JavaScript/Reference/Statements/function* +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><code><strong>function*</strong></code> 这种声明方式(<code style="font-style: normal;">function</code>关键字后跟一个星号)会定义一个<strong><em>生成器函数</em> (</strong><em>generator function</em><strong>)</strong>,它返回一个 {{jsxref("Global_Objects/Generator","Generator")}} 对象。</p> + +<div>{{EmbedInteractiveExample("pages/js/statement-functionasterisk.html")}}</div> + + + +<div class="noinclude"> +<p>你也可以使用构造函数 {{jsxref("GeneratorFunction")}} 或 {{jsxref("Operators/function*", "function* expression")}} 定义<strong><em>生成器函数</em> </strong>。</p> +</div> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">function* <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) { <em>statements</em> } +</pre> + +<dl> + <dt><code>name</code></dt> + <dd>函数名</dd> +</dl> + +<dl> + <dt><code>param</code></dt> + <dd>要传递给函数的一个参数的名称,一个函数最多可以有255个参数。</dd> +</dl> + +<dl> + <dt><code>statements</code></dt> + <dd>普通JS语句。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p><strong>生成器函数</strong>在执行时能暂停,后面又能从暂停处继续执行。</p> + +<p>调用一个<strong>生成器函数</strong>并不会马上执行它里面的语句,而是返回一个这个生成器的 <strong>迭代器</strong> <strong>( <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterator">iterator</a> )对象</strong>。当这个迭代器的 <code>next() </code>方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现{{jsxref("Operators/yield", "yield")}}的位置为止,{{jsxref("Operators/yield", "yield")}} 后紧跟迭代器要返回的值。或者如果用的是 {{jsxref("Operators/yield*", "yield*")}}(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。</p> + +<p><code>next()</code>方法返回一个对象,这个对象包含两个属性:value 和 done,value 属性表示本次 <code>yield </code>表达式的返回值,done 属性为布尔类型,表示生成器后续是否还有<code> yield </code>语句,即生成器函数是否已经执行完毕并返回。</p> + +<p>调用 <code>next()</code>方法时,如果传入了参数,那么这个参数会传给<strong>上一条执行的 yield语句左边的变量</strong>,例如下面例子中的<code> x </code>:</p> + +<pre class="brush: js">function *gen(){ + yield 10; + x=yield 'foo'; + yield x; +} + +var gen_obj=gen(); +console.log(gen_obj.next());// 执行 yield 10,返回 10 +console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo' +console.log(gen_obj.next(100));// 将 100 赋给上一条 yield 'foo' 的左值,即执行 x=100,返回 100 +console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true</pre> + +<p>当在生成器函数中显式 <code>return </code>时,会导致生成器立即变为完成状态,即调用 <code>next()</code> 方法返回的对象的 <code>done </code>为 <code>true</code>。如果 <code>return </code>后面跟了一个值,那么这个值会作为<strong>当前</strong>调用 <code>next()</code> 方法返回的 value 值。</p> + +<h2 id="示例">示例</h2> + +<h3 id="简单示例">简单示例</h3> + +<pre class="brush: js">function* idMaker(){ + var index = 0; + while(index<3) + yield index++; +} + +var gen = idMaker(); +console.log(gen.next().value); // 0 +console.log(gen.next().value); // 1 +console.log(gen.next().value); // 2 +console.log(gen.next().value); // undefined +</pre> + +<h3 id="生成器也可以接收参数:">生成器也可以接收参数:</h3> + +<pre class="brush: js">function* idMaker(){ + var index = arguments[0] || 0; + while(true) + yield index++; +} + +var gen = idMaker(5); +console.log(gen.next().value); // 5 +console.log(gen.next().value); // 6</pre> + +<h3 id="yield*的示例">yield*的示例</h3> + +<pre class="brush: js">function* anotherGenerator(<strong>i</strong>) { + yield i + 1; + yield i + 2; + yield i + 3; +} + +function* generator(<strong>i</strong>){ + yield i; + yield* anotherGenerator(<strong>i</strong>);// 移交执行权 + yield i + 10; +} + +var gen = generator(10); + +console.log(gen.next().value); // 10 +console.log(gen.next().value); // 11 +console.log(gen.next().value); // 12 +console.log(gen.next().value); // 13 +console.log(gen.next().value); // 20 +</pre> + +<h3 id="传递参数">传递参数</h3> + +<pre class="brush: js">function *createIterator() { + let first = yield 1; + let second = yield first + 2; // <strong>4</strong> + 2 + // first =4 是next<strong>(4)将参数赋给上一条的</strong> + yield second + 3; // <strong>5</strong> + 3 +} + +let iterator = createIterator(); + +console.log(iterator.next()); // "{ value: 1, done: false }" +console.log(iterator.next<strong>(4)</strong>); // "{ value: 6, done: false }" +console.log(iterator.next(<strong>5</strong>)); // "{ value: 8, done: false }" +console.log(iterator.next()); // "{ value: undefined, done: true }"</pre> + +<h3 id="显式返回">显式返回</h3> + +<pre class="brush: js">function* yieldAndReturn() { + yield "Y"; + return "R";//显式返回处,可以观察到 done 也立即变为了 true + yield "unreachable";// 不会被执行了 +} + +var gen = yieldAndReturn() +console.log(gen.next()); // { value: "Y", done: false } +console.log(gen.next()); // { value: "R", done: true } +console.log(gen.next()); // { value: undefined, done: true }</pre> + +<h3 id="生成器函数不能当构造器使用">生成器函数不能当构造器使用</h3> + +<pre class="brush: js">function* f() {} +var obj = new f; // throws "TypeError: f is not a constructor"</pre> + +<h3 id="使用迭代器遍历二维数组并转换成一维数组:">使用迭代器遍历二维数组并转换成一维数组:</h3> + +<blockquote> +<pre class="brush: js">function* iterArr(arr) { //迭代器返回一个迭代器对象 + if (Array.isArray(arr)) { // 内节点 + for(let i=0; i < arr.length; i++) { + yield* iterArr(arr[i]); // (*)递归 + } + } else { // 离开 + yield arr; + } +} +// 使用 for-of 遍历: +var arr = ['a', ['b', 'c'], ['d', 'e']]; +for(var x of iterArr(arr)) { + console.log(x); // a b c d e + } + +// 或者直接将迭代器展开: +var arr = [ 'a', ['b',[ 'c', ['d', 'e']]]]; +var gen = iterArr(arr); +arr = [...gen]; // ["a", "b", "c", "d", "e"]</pre> +</blockquote> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('ES2015', '#', 'function*')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#', 'function*')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div> + + +<p>{{Compat("javascript.statements.generator_function")}} </p> +</div> + +<h2 id="Firefox浏览器具体事项">Firefox浏览器具体事项</h2> + +<h4 id="Firefox_26之前的生成器和迭代器">Firefox 26之前的生成器和迭代器</h4> + +<p>旧版本的Firefox实施了旧版本的生成器提案。旧版中用普通的<code>function关键字定义</code>(没有星号).</p> + +<h4 id="IteratorResult不再抛出错误"><code>IteratorResult</code>不再抛出错误</h4> + +<p>从Gecko 29 {{geckoRelease(29)}}开始,完成的生成器函数不再抛出{{jsxref("TypeError")}} "generator has already finished". 而是返回一个<code>IteratorResult</code>对象:<span style="font-family: consolas,monaco,andale mono,monospace;">{ value: undefined, done: true }</span> ({{bug(958951)}})。</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Operators/function*", "function* expression")}}</li> + <li>{{jsxref("GeneratorFunction")}} object</li> + <li><a href="/zh-CN/docs/Web/JavaScript/Guide/The_Iterator_protocol">迭代器协议</a></li> + <li>{{jsxref("Operators/yield", "yield")}}</li> + <li>{{jsxref("Operators/yield*", "yield*")}}</li> + <li>{{jsxref("Function")}} object</li> + <li>{{jsxref("Statements/function", "function declaration")}}</li> + <li>{{jsxref("Operators/function", "function expression")}}</li> + <li>{{jsxref("Functions_and_function_scope", "Functions and function scope")}}</li> + <li>其他网络资源: + <ul> + <li><a href="http://facebook.github.io/regenerator/">Regenerator</a> an ES2015 generator compiler to ES5</li> + <li><a href="http://www.youtube.com/watch?v=qbKWsbJ76-s">Forbes Lindesay: Promises and Generators: control flow utopia -- JSConf EU 2013</a></li> + <li><a href="https://www.youtube.com/watch?v=ZrgEZykBHVo&list=PLuoyIZT5fPlG44bPq50Wgh0INxykdrYX7&index=1">Hemanth.HM: The New gen of *gen(){}</a></li> + <li><a href="http://taskjs.org/">Task.js</a></li> + </ul> + </li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/if...else/index.html b/files/zh-cn/web/javascript/reference/statements/if...else/index.html new file mode 100644 index 0000000000..90d29e86ae --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/if...else/index.html @@ -0,0 +1,176 @@ +--- +title: if...else +slug: Web/JavaScript/Reference/Statements/if...else +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/if...else +--- +<div> +<div> {{jsSidebar("Statements")}}</div> +</div> + +<p><span style="line-height: 19.0909080505371px;">当指定条件为真,</span><strong>if 语句</strong>会执行一段语句。如果条件为假,则执行另一段语句。</p> + +<p>{{EmbedInteractiveExample("pages/js/statement-ifelse.html")}}</p> + +<div class="hidden"> +<p>The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p> +</div> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox">if (<em>condition</em>) + <em>statement1</em> +[else + <em>statement2</em>] +</pre> + +<dl> + <dt><code>condition</code></dt> + <dd>值为真或假的<a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions">表达式</a></dd> +</dl> + +<dl> + <dt><code>statement1</code></dt> + <dd>当<code>condition</code>为真时执行的语句。可为任意语句,包括更深层的内部<code>if</code>语句。要执行多条语句,使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block" title="en/JavaScript/Reference/Statements/block">块</a>语句({ ... })将这些语句分组;若不想执行语句,则使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/Empty">空</a>语句。 </dd> +</dl> + +<dl> + <dt><code>statement2</code></dt> + <dd>如果<code>condition</code>为假且 <code>else</code>从句存在时执行的语句。<span style="line-height: 19.0909080505371px;">可为任意语句,包括块语句和</span>嵌套的<code>if</code>语句<span style="line-height: 19.0909080505371px;">。</span></dd> +</dl> + +<h2 id="Description" name="Description">说明</h2> + +<p>多层 <code>if...else</code> 语句可使用 <code>else if</code> 从句。注意:在 Javascript 中没有 <code>elseif</code> (一个单词)关键字。</p> + +<pre class="eval">if (<em>condition1</em>) + <em>statement1</em> +else if (<em>condition2</em>) + <em>statement2</em> +else if (<em>condition3</em>) + <em>statement3</em> +... +else + <em>statementN</em> + +</pre> + +<p>要看看它如何工作,可以调整下嵌套的缩进:</p> + +<pre class="eval">if (<em>condition1</em>) + <em>statement1</em> +else + if (<em>condition2</em>) + <em>statement2</em> + else + if (<em>condition3</em>) +... +</pre> + +<p>要在一个从句中执行多条语句,可使用语句块(<code>{ ... }</code>)。通常情况下,一直使用语句块是个好习惯,特别是在涉及嵌套<code>if</code>语句的代码中:</p> + +<pre class="eval">if (<em>condition</em>) { + <em>statements1</em> +} else { + <em>statements2</em> +} +</pre> + +<p>不要将原始布尔值的<code>true</code>和<code>false</code>与<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Boolean" title="en/JavaScript/Reference/Global_Objects/Boolean">Boolean</a>对象的真或假混淆。任何一个值,只要它不是 <code>undefined</code><font face="Open Sans, Arial, sans-serif">、</font><code>null</code>、 <code>0</code><font face="Open Sans, Arial, sans-serif">、</font><code>NaN</code>或空字符串(<code>""</code>),那么无论是任何对象,即使是值为假的Boolean对象,在条件语句中都为真。例如:</p> + +<pre class="brush: js">var b = new Boolean(false); +if (b) //表达式的值为true +</pre> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example:_Using_if...else" name="Example:_Using_if...else">使用 <code>if...else</code></h3> + +<pre class="brush: js">if (cipher_char === from_char) { + result = result + to_char; + x++; +} else { + result = result + clear_char; +} +</pre> + +<h3 id="使用_else_if">使用 <code>else if</code></h3> + +<p>注意,Javascript中没有<code>elseif</code>语句。但可以使用<code>else</code>和<code>if</code>中间有空格的语句:</p> + +<pre class="brush: js">if (x > 5) { + /* do the right thing */ +} else if (x > 50) { + /* do the right thing */ +} else { + /* do the right thing */ +}</pre> + +<h3 id="Example:_Assignment_within_the_conditional_expression" name="Example:_Assignment_within_the_conditional_expression">条件表达式中的赋值运算</h3> + +<p>建议不要在条件表达式中单纯的使用赋值运算,因为粗看下赋值运算的代码很容易让人误认为是等性比较。比如,不要使用下面示例的代码:</p> + +<pre class="brush: js example-bad">if (x = y) { + /* do the right thing */ +} +</pre> + +<p>如果你需要在条件表达式中使用赋值运算,用圆括号包裹赋值运算。例如:</p> + +<pre class="brush: js example-good">if ((x = y)) { + /* do the right thing */ +} +</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>{{SpecName('ESDraft', '#sec-if-statement', 'if statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-if-statement', 'if statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.5', 'if statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.5', 'if statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.5', 'if statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.if_else")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/block", "block")}}</li> + <li>{{jsxref("Statements/switch", "switch")}}</li> + <li>{{jsxref("Operators/conditional_operator", "条件运算符")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/import.meta/index.html b/files/zh-cn/web/javascript/reference/statements/import.meta/index.html new file mode 100644 index 0000000000..95f5f68e36 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/import.meta/index.html @@ -0,0 +1,104 @@ +--- +title: import.meta +slug: Web/JavaScript/Reference/Statements/import.meta +tags: + - JavaScript + - Language feature + - Modules + - Reference + - Statement + - import +translation_of: Web/JavaScript/Reference/Statements/import.meta +--- +<div>{{JSSidebar("Statements")}}</div> + +<p><code>import.meta</code>是一个给JavaScript模块暴露特定上下文的元数据属性的对象。它包含了这个模块的信息,比如说这个模块的URL。</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">import.meta</pre> + +<h2 id="描述">描述</h2> + +<p><code>import.meta</code>对象由一个关键字<code>"import"</code>,一个点符号和一个<code>meta</code>属性名组成。通常情况下<code>"import."</code>是作为一个属性访问的上下文,但是在这里<code>"import"</code>不是一个真正的对象。</p> + +<p><code>import.meta</code>对象是由ECMAScript实现的,它带有一个{{jsxref("null")}}的原型对象。这个对象可以扩展,并且它的属性都是可写,可配置和可枚举的。</p> + +<h2 id="示例">示例</h2> + +<p>这里有一个 <code>my-module.mjs模块</code></p> + +<pre class="brush: html"><script type="module" src="my-module.mjs"></script> +</pre> + +<p>你可以通过 <code>import.meta</code> 对象获取这个模块的元数据信息.</p> + +<pre class="brush: js">console.log(import.meta); // { url: "file:///home/user/my-module.mjs" }</pre> + +<p>它返回一个带有<code>url</code>属性的对象,指明模块的基本URL。也可以是外部脚本的URL,还可以是内联脚本所属文档的URL。</p> + +<p>注意,url也可能包含参数或者哈希(比如后缀<code>?</code>或<code>#</code>)</p> + +<p>以下面的HTML为例:</p> + +<pre><script type="module"> +import './index.mjs?someURLInfo=5'; +</script></pre> + +<p>...下面的JavaScript会打印<code>someURLInfo</code>这个参数:</p> + +<pre>// index.mjs +new URL(import.meta.url).searchParams.get('someURLInfo'); // 5</pre> + +<p>在脚本中引入别的脚本同样生效:</p> + +<pre>// index.mjs +import './index2.mjs?someURLInfo=5'; + +// index2.mjs +new URL(import.meta.url).searchParams.get('someURLInfo'); // 5</pre> + +<p>虽然在上述例子中,Node.js允许携带参数(或哈希),但以Node 14.1.0为例,使用<code>node --experimental-modules index.mjs?someURLInfo=5</code> 执行脚本,查询URL参数将会报错(该环境下<code>index.mjs?someURLInfo=5</code> 被视作一个文件而不是URL)</p> + +<p>像这种特定于文件的参数传递可能是对应用范围内<code>location.href</code>(ps: 通过在HTML路径添加参数或哈希)(而在Node.js中是<code>process.env</code>)的补充</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td><a href="https://github.com/tc39/proposal-import-meta">tc39/proposal-import-meta</a></td> + <td>Stage 3</td> + <td>Initial definition.</td> + </tr> + <tr> + <td><a href="https://html.spec.whatwg.org/multipage/webappapis.html#hostgetimportmetaproperties">HTML Standard</a></td> + <td>Living Standard</td> + <td>Defines import.meta properties in HTML.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器支持">浏览器支持</h2> + + + +<p>{{Compat("javascript.statements.import_meta")}}</p> + +<h3 id="Implementation_Progress">Implementation Progress</h3> + +<p>The following table provides a daily implementation status for this feature, because this feature has not yet reached cross-browser stability. The data is generated by running the relevant feature tests in <a href="https://github.com/tc39/test262">Test262</a>, the standard test suite of JavaScript, in the nightly build, or latest release of each browser's JavaScript engine.</p> + +<p>{{EmbedTest262ReportResultsTable("import.meta")}}</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/import">import</a></li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/export">export</a></code></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/import/index.html b/files/zh-cn/web/javascript/reference/statements/import/index.html new file mode 100644 index 0000000000..fabebc11d1 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/import/index.html @@ -0,0 +1,232 @@ +--- +title: import +slug: Web/JavaScript/Reference/Statements/import +tags: + - ECMAScript 2015 + - JavaScript + - Modules + - Statement + - import +translation_of: Web/JavaScript/Reference/Statements/import +--- +<p>{{jsSidebar("Statements")}}</p> + +<p>静态的<code><strong>import</strong></code> 语句用于导入由另一个模块导出的绑定。无论是否声明了 {{jsxref("Strict_mode","strict mode")}} ,导入的模块都运行在严格模式下。在浏览器中,<code>import</code> 语句只能在声明了 <code>type="module"</code> 的 <code>script</code> 的标签中使用。</p> + +<p>此外,还有一个类似函数的动态 <code>import()</code>,它不需要依赖 <code>type="module"</code> 的script标签。</p> + +<p>在 <a href="/zh-CN/docs/Web/HTML/Element/script">script</a> 标签中使用 <code>nomodule</code> 属性,可以确保向后兼容。</p> + +<p>在您希望按照一定的条件或者按需加载模块的时候,动态<code>import()</code> 是非常有用的。而静态型的 <code>import</code> 是初始化加载依赖项的最优选择,使用静态 <code>import</code> 更容易从代码静态分析工具和 <a href="/zh-CN/docs/Glossary/Tree_shaking">tree shaking</a> 中受益。</p> + +<p>语法</p> + +<pre class="syntaxbox notranslate">import <em>defaultExport</em> from "<em>module-name</em>"; +import * as <em>name</em> from "<em>module-name</em>"; +import { <em>export </em>} from "<em>module-name</em>"; +import { <em>export</em> as <em>alias </em>} from "<em>module-name</em>"; +import { <em>export1 , export2</em> } from "<em>module-name</em>"; +import { foo , bar } from "module-name/path/to/specific/un-exported/file"; +import { <em>export1 , export2</em> as <em>alias2</em> , <em>[...]</em> } from "<em>module-name</em>"; +import <em>defaultExport</em>, { <em>export</em> [ , <em>[...]</em> ] } from "<em>module-name</em>"; +import <em>defaultExport</em>, * as <em>name</em> from "<em>module-name</em>"; +import "<em>module-name</em>"; +var promise = import("module-name");//这是一个处于第三阶段的提案。 +</pre> + +<dl> + <dt><code>defaultExport</code></dt> + <dd>导入模块的默认导出接口的引用名。</dd> + <dt><code>module-name</code></dt> + <dd>要导入的模块。通常是包含目标模块的<code>.js</code>文件的相对或绝对路径名,可以不包括<code>.js</code>扩展名。某些特定的打包工具可能允许或需要使用扩展或依赖文件,它会检查比对你的运行环境。只允许单引号和双引号的字符串。</dd> + <dt><code>name</code></dt> + <dd>导入模块对象整体的别名,在引用导入模块时,它将作为一个命名空间来使用。</dd> + <dt><code>export, exportN</code></dt> + <dd>被导入模块的导出接口的名称。</dd> + <dt><code>alias, aliasN</code></dt> + <dd>将引用指定的导入的名称。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p><code>name</code>参数是“导入模块对象”的名称,它将用一种名称空间来引用导入模块的接口。export参数指定单个的命名导出,而<code>import * as name</code>语法导入所有导出接口,即导入模块整体。以下示例阐明该语法。</p> + +<h3 id="导入整个模块的内容">导入整个模块的内容</h3> + +<p>这将<code>myModule</code>插入当前作用域,其中包含来自位于<code>/modules/my-module.js</code>文件中导出的所有接口。</p> + +<pre class="brush: js notranslate">import * as myModule from '/modules/my-module.js'; +</pre> + +<p>在这里,访问导出接口意味着使用模块名称(在本例为“myModule”)作为命名空间。例如,如果上面导入的模块包含一个接口<code>doAllTheAmazingThings()</code>,你可以这样调用:</p> + +<pre class="brush: js notranslate">myModule.doAllTheAmazingThings();</pre> + +<h3 id="导入单个接口">导入单个接口</h3> + +<p>给定一个名为<code>myExport</code>的对象或值,它已经从模块<code>my-module</code>导出(因为整个模块被导出)或显式地导出(使用{{jsxref("Statements/export", "export")}}语句),将<code>myExport</code>插入当前作用域。</p> + +<pre class="brush: js notranslate">import {myExport} from '/modules/my-module.js';</pre> + +<h3 id="导入多个接口">导入多个接口</h3> + +<p>这将<code>foo</code>和<code>bar</code>插入当前作用域。</p> + +<pre class="brush: js notranslate">import {foo, bar} from '/modules/my-module.js';</pre> + +<h3 id="导入带有别名的接口">导入带有别名的接口</h3> + +<p>你可以在导入时重命名接口。例如,将<code>shortName</code>插入当前作用域。</p> + +<pre class="brush: js notranslate">import {reallyReallyLongModuleExportName as shortName} + from '/modules/my-module.js';</pre> + +<h3 id="导入时重命名多个接口">导入时重命名多个接口</h3> + +<p>使用别名导入模块的多个接口。</p> + +<pre class="brush: js notranslate">import { + reallyReallyLongModuleMemberName as shortName, + anotherLongModuleName as short +} from '/modules/my-module.js'; +</pre> + +<h3 id="仅为副作用而导入一个模块">仅为副作用而导入一个模块</h3> + +<p>整个模块仅为副作用(中性词,无贬义含义)而导入,而不导入模块中的任何内容(接口)。 这将运行模块中的全局代码, 但实际上不导入任何值。</p> + +<pre class="notranslate"><code>import '/modules/my-module.js';</code></pre> + +<h3 id="导入默认值">导入默认值</h3> + +<p><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">引入模块可能有一个</span></font>default</code>{{jsxref("Statements/export", "export")}}(无论它是对象,函数,类等)可用。然后可以使用<code>import</code>语句来导入这样的默认接口。</p> + +<p>最简单的用法是直接导入默认值:</p> + +<pre class="brush: js notranslate">import myDefault from '/modules/my-module.js';</pre> + +<p>也可以同时将<code>default</code>语法与上述用法(命名空间导入或命名导入)一起使用。在这种情况下,<code>default</code>导入必须首先声明。 例如:</p> + +<pre class="brush: js notranslate">import myDefault, * as myModule from '/modules/my-module.js'; +// myModule used as a namespace</pre> + +<p>或者</p> + +<pre class="brush: js notranslate">import myDefault, {foo, bar} from '/modules/my-module.js'; +// specific, named imports +</pre> + +<p>When importing a default export with {{anch("Dynamic Imports", "dynamic imports")}}, it works a bit differently. You need to destructure and rename the "default" key from the returned object.</p> + +<pre class="notranslate">(async () => { + if (somethingIsTrue) { + const { default: myDefault, foo, bar } = await import('/modules/my-module.js'); + } +})();</pre> + +<h3 id="动态import">动态import</h3> + +<p>标准用法的import导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。下面的是你可能会需要动态导入的场景:</p> + +<ul> + <li>当静态导入的模块很明显的降低了代码的加载速度且被使用的可能性很低,或者并不需要马上使用它。</li> + <li>当静态导入的模块很明显的占用了大量系统内存且被使用的可能性很低。</li> + <li>当被导入的模块,在加载时并不存在,需要异步获取</li> + <li>当导入模块的说明符,需要动态构建。(静态导入只能使用静态说明符)</li> + <li>当被导入的模块有副作用(这里说的副作用,可以理解为模块中会直接运行的代码),这些副作用只有在触发了某些条件才被需要时。(原则上来说,模块不能有副作用,但是很多时候,你无法控制你所依赖的模块的内容)</li> +</ul> + +<p>请不要滥用动态导入(只有在必要情况下采用)。静态框架能更好的初始化依赖,而且更有利于静态分析工具和<a href="https://wiki.developer.mozilla.org/en-US/docs/Glossary/Tree_shaking">tree shaking</a>发挥作用</p> + +<p>关键字import可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 <code>promise</code>。</p> + +<pre class="brush: js notranslate"><code>import('/modules/my-module.js') + .then((module) => { + // Do something with the module. + });</code> +</pre> + +<p>这种使用方式也支持 <code>await</code> 关键字。</p> + +<pre class="brush: js notranslate"><code>let module = await import('/modules/my-module.js');</code></pre> + +<h2 id="示例">示例</h2> + +<h3 id="标准导入">标准导入</h3> + +<p>下面的代码将会演示如何从辅助模块导入以协助处理AJAX JSON请求。</p> + +<h4 id="模块:file.js">模块:file.js</h4> + +<pre class="brush: js notranslate">function getJSON(url, callback) { + let xhr = new XMLHttpRequest(); + xhr.onload = function () { + callback(this.responseText) + }; + xhr.open('GET', url, true); + xhr.send(); +} + +export function getUsefulContents(url, callback) { + getJSON(url, data => callback(JSON.parse(data))); +}</pre> + +<h4 id="主程序:main.js">主程序:main.js</h4> + +<pre class="brush: js notranslate">import { getUsefulContents } from '/modules/file.js'; + +getUsefulContents('http://www.example.com', + data => { doSomethingUseful(data); });</pre> + +<h3 id="动态导入">动态导入</h3> + +<p>此示例展示了如何基于用户操作去加载功能模块到页面上,在例子中通过点击按钮,然后会调用模块内的函数。当然这不是能实现这个功能的唯一方式,<code>import()</code>函数也可以支持<code>await</code>。</p> + +<pre class="brush: js notranslate">const main = document.querySelector("main"); +for (const link of document.querySelectorAll("nav > a")) { + link.addEventListener("click", e => { + e.preventDefault(); + + import('/modules/my-module.js') + .then(module => { + module.loadPageInto(main); + }) + .catch(err => { + main.textContent = err.message; + }); + }); +}</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="https://tc39.es/proposal-dynamic-import/#sec-import-calls">"function-like" dynamic <code>import()</code> proposal</a></td> + </tr> + <tr> + <td>{{SpecName("ESDraft", "#sec-imports", "Imports")}}</td> + </tr> + </tbody> +</table> + +<h2 id="sect1"></h2> + +<p>{{Compat("javascript.statements.import")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{JSxRef("Statements/export", "export")}}</li> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/import.meta"><code>import.meta</code></a></li> + <li>Limin Zhu, Brian Terlson and Microsoft Edge Team: <a href="https://blogs.windows.com/msedgedev/2016/05/17/es6-modules-and-beyond/">Previewing ES6 Modules and more from ES2015, ES2016 and beyond</a></li> + <li>Hacks blog post by Jason Orendorff: <a href="https://hacks.mozilla.org/2015/08/es6-in-depth-modules/">ES6 in Depth: Modules</a></li> + <li>Hacks blog post by Lin Clark: <a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/">ES modules: A cartoon deep-dive</a></li> + <li>Axel Rauschmayer's book: <a class="external" href="http://exploringjs.com/es6/ch_modules.html">"Exploring JS: Modules"</a></li> + <li>The Modern JavaScript Tutorial(javascript.info): <a class="external" href="https://javascript.info/import-export">Export and Import</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/index.html b/files/zh-cn/web/javascript/reference/statements/index.html new file mode 100644 index 0000000000..c6d70fce55 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/index.html @@ -0,0 +1,150 @@ +--- +title: 语句和声明 +slug: Web/JavaScript/Reference/Statements +tags: + - JavaScript + - 参考 + - 声明 + - 语句和声明 +translation_of: Web/JavaScript/Reference/Statements +--- +<div>{{jsSidebar("Statements")}}</div> + +<p>JavaScript 应用程序是由许多语法正确的语句组成的。单个语句可以跨多行。如果每个语句用分号隔开,那么多个语句可以在一行中出现。本页的内容并不是一个关键字,而是一组关键字。</p> + +<h2 id="语句和声明(按类别分类)">语句和声明(按类别分类)</h2> + +<p>若需要按字母顺序排列的列表,请参阅左侧边栏。</p> + +<h3 id="控制流程"><span class="short_text" id="result_box" lang="zh-CN"><span>控制流程</span></span></h3> + +<dl> + <dt>{{jsxref("Statements/block", "Block")}}</dt> + <dd>一个块语句可以用来管理零个或多个语句。该区块是由一对大括号分隔。</dd> + <dt>{{jsxref("Statements/break", "break")}}</dt> + <dd>终止当前的循环,switch 或 label 语句,使程序跳到下一个语句执行。</dd> + <dt>{{jsxref("Statements/continue", "continue")}}</dt> + <dd>终止执行当前或标签循环的语句,直接执行下一个迭代循环。</dd> + <dt>{{jsxref("Statements/Empty", "Empty")}}</dt> + <dd>空语句用来表示没有语句的情况,尽管 JavaScript 语法期望有语句提供。</dd> + <dt>{{jsxref("Statements/if...else", "if...else")}}</dt> + <dd>如果指定的条件是 true ,则执行相匹配的一个语句,若为 false,则执行另一个语句。</dd> + <dt>{{jsxref("Statements/switch", "switch")}}</dt> + <dd>计算表达式,将子句于表达式的值做匹配,执行与该值相关联的语句。</dd> + <dt>{{jsxref("Statements/throw", "throw")}}</dt> + <dd>抛出一个用户定义的异常。</dd> + <dt>{{jsxref("Statements/try...catch", "try...catch")}}</dt> + <dd>标记一个语句块,并指定一个应该抛出异常的反馈。(Marks a block of statements to try, and specifies a response, should an exception be thrown.)</dd> +</dl> + +<h3 id="声明">声明</h3> + +<dl> + <dt>{{jsxref("Statements/var", "var")}}</dt> + <dd>声明一个变量,可同时将其初始化为一个值。</dd> + <dt>{{jsxref("Statements/let", "let")}}</dt> + <dd>声明一个块级本地变量,可同时将其初始化为一个值。</dd> + <dt>{{jsxref("Statements/const", "const")}}</dt> + <dd>声明一个只读的命名常量。</dd> +</dl> + +<h3 id="函数和类">函数和类</h3> + +<dl> + <dt>{{jsxref("Statements/function", "function")}}</dt> + <dd>声明一个指定参数的函数。</dd> + <dt>{{jsxref("Statements/function*", "function*")}}</dt> + <dd>生成器函数使<a href="/zh-CN/docs/Web/JavaScript/Guide/The_Iterator_protocol">迭代器</a>更容易使用。</dd> + <dt>{{jsxref("Statements/async_function", "async function")}}</dt> + <dd>使用指定的参数声明一个异步函数。</dd> + <dt>{{jsxref("Statements/return", "return")}}</dt> + <dd>指定函数的返回值。</dd> + <dt>{{jsxref("Statements/class", "class")}}</dt> + <dd>声明一个类。</dd> +</dl> + +<h3 id="迭代器">迭代器</h3> + +<dl> + <dt>{{jsxref("Statements/do...while", "do...while")}}</dt> + <dd>创建一个循环来执行语句,直到该语句条件表达式的值为 false。先执行语句,再执行条件表达式,该语句至少会执行一次。</dd> + <dt>{{jsxref("Statements/for", "for")}}</dt> + <dd>创建一个由3个可选的表达式组成的循环,该循环用括号包裹,分号分割,并在循环体中执行语句。</dd> + <dt>{{jsxref("Statements/for...in", "for...in")}}</dt> + <dd>无序遍历对象的可枚举属性。语句针对每个唯一的属性。</dd> + <dt>{{jsxref("Statements/for...of", "for...of")}}</dt> + <dd>遍历可迭代的对象(包括 {{jsxref("Global_Objects/Array","数组")}}、类数组对象、<a href="/zh-CN/docs/JavaScript/Guide/Iterators_and_Generators">迭代器和生成器</a>),对每个不同属性的属性,调用一个自定义的有执行语句的迭代钩子。</dd> + <dt>{{jsxref("Statements/for-await...of", "for await...of")}}</dt> + <dd>在异步可迭代对象、类数组对象、<a href="/zh-CN/docs/JavaScript/Guide/Iterators_and_Generators">迭代器和生成器</a>上迭代,调用自定义迭代钩子,其中包含要为每个不同属性的值执行的语句。</dd> + <dt>{{jsxref("Statements/while", "while")}}</dt> + <dd>创建一个循环语句,循环会一直持续到该语句条件表达式的值为false。先执行条件表达式,然后执行语句。</dd> +</dl> + +<h3 id="其他">其他</h3> + +<dl> + <dt>{{jsxref("Statements/debugger", "debugger")}}</dt> + <dd>调用可用的调试功能。如果没有调试功能可用,该语句不生效。</dd> + <dt>{{jsxref("Statements/export", "export")}}</dt> + <dd>用来导出函数,以便这些函数能够被导入到外部模块或其他脚本中。</dd> + <dt>{{jsxref("Statements/import", "import")}}</dt> + <dd>用来引入外部的模块或另一个script中导出的函数。</dd> + <dt><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/import.meta"><code>import.meta</code></a></dt> + <dd>向 JavaScript 模块公开上下文特定的元数据的元属性。</dd> + <dt>{{jsxref("Statements/label", "label")}}</dt> + <dd>带标识的语句,与 <code>break</code> 或 <code>continue</code> 语句一起使用。</dd> +</dl> + +<dl> + <dt>{{jsxref("Statements/with", "with")}} {{deprecated_inline}}</dt> + <dd>拓展一个语句的作用域。</dd> +</dl> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12', 'Statements')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition</td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12', 'Statements')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12', 'Statements')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-ecmascript-language-statements-and-declarations', 'ECMAScript Language: Statements and Declarations')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>New: function*, let, for...of, yield, class</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-ecmascript-language-statements-and-declarations', 'ECMAScript Language: Statements and Declarations')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators">表达式和操作符</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/label/index.html b/files/zh-cn/web/javascript/reference/statements/label/index.html new file mode 100644 index 0000000000..c0bf3413c7 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/label/index.html @@ -0,0 +1,203 @@ +--- +title: label +slug: Web/JavaScript/Reference/Statements/label +tags: + - JavaScript + - Statement + - 语句 +translation_of: Web/JavaScript/Reference/Statements/label +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong>标记语句</strong>可以和 {{jsxref("Statements/break", "break")}} 或 {{jsxref("Statements/continue", "continue")}} 语句一起使用。标记就是在一条语句前面加个可以引用的标识符(identifier)。</p> + +<div> {{EmbedInteractiveExample("pages/js/statement-label.html")}}</div> + + + +<div class="note"> +<p><strong>备注:</strong>使用标记的循环或语句块非常罕见。通常情况下,可以使用函数调用而不是(基于标记的)循环跳转。</p> +</div> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox"><em>label</em> : + <em>statement</em> +</pre> + +<dl> + <dt><code>label</code></dt> + <dd>任何不属于保留关键字的 JavaScript 标识符。</dd> + <dt><code>statement</code></dt> + <dd>JavaScript 语句。<code>break</code> 可用于任何标记语句,而 <code>continue</code> 可用于循环标记语句。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>可使用一个标签来唯一标记一个循环,然后使用 <code>break</code> 或 <code>continue</code> 语句来指示程序是否中断循环或继续执行。</p> + +<p>需要注意的是,JavaScript 没有 <code>goto</code> 语句,标记只能和 <code>break</code> 或 <code>continue</code> 一起使用。</p> + +<p>在<a href="/zh-CN/docs/Web/JavaScript/Reference/Strict_mode">严格模式</a>中,你不能使用 “<code>let</code>” 作为标签名称。它会抛出一个 {{jsxref("SyntaxError")}}(因为 let 是一个保留的标识符)。</p> + +<h2 id="示例">示例</h2> + +<h3 id="在_for_循环中使用带标记的_continue_语句">在 <code>for</code> 循环中使用带标记的 <code>continue</code> 语句</h3> + +<pre class="brush: js"> var i, j; + + loop1: + for (i = 0; i < 3; i++) { //The first for statement is labeled "loop1" + loop2: + for (j = 0; j < 3; j++) { //The second for statement is labeled "loop2" + if (i === 1 && j === 1) { + continue loop1; + } + console.log('i = ' + i + ', j = ' + j); + } + } + +// Output is: +// "i = 0, j = 0" +// "i = 0, j = 1" +// "i = 0, j = 2" +// "i = 1, j = 0" +// "i = 2, j = 0" +// "i = 2, j = 1" +// "i = 2, j = 2" +// Notice how it skips both "i = 1, j = 1" and "i = 1, j = 2" +</pre> + +<h3 id="使用带标记的_continue_语句">使用带标记的 <code>continue</code> 语句</h3> + +<p>若给定一个数据数组和一个测试数组,则下面的例子会统计通过测试的数据的数量。</p> + +<pre class="brush: js">var itemsPassed = 0; +var i, j; + +top: +for (i = 0; i < items.length; i++) { + for (j = 0; j < tests.length; j++) { + if (!tests[j].pass(items[i])) { + continue top; + } + } + + itemsPassed++; +}</pre> + +<h3 id="在_for_循环中使用带标记的_break">在 <code>for</code> 循环中使用带标记的 <code>break</code></h3> + +<pre class="brush: js">var i, j; + +loop1: +for (i = 0; i < 3; i++) { //The first for statement is labeled "loop1" + loop2: + for (j = 0; j < 3; j++) { //The second for statement is labeled "loop2" + if (i == 1 && j == 1) { + break loop1; + } + console.log("i = " + i + ", j = " + j); + } +} + +// Output is: +// "i = 0, j = 0" +// "i = 0, j = 1" +// "i = 0, j = 2" +// "i = 1, j = 0" +// Notice the difference with the previous continue example</pre> + +<h3 id="Example_3" name="Example_3">使用带标记的 <code>break</code> 语句</h3> + +<p>若给定一个数据数组和一个测试数组,则下面的例子会判断是否所有数据均通过了测试。</p> + +<pre class="brush: js">var allPass = true; +var i, j; + +top: +for (i = 0; items.length; i++) + for (j = 0; j < tests.length; i++) + if (!tests[j].pass(items[i])){ + allPass = false; + break top; + }</pre> + +<h3 id="在标记块中使用_break">在标记块中使用 <code>break</code></h3> + +<p>你可以在代码块中使用标记,但只有 <code>break</code> 语句可以使用非循环标记。</p> + +<pre class="brush: js">foo: { + console.log('face'); + break foo; + console.log('this will not be executed'); +} +console.log('swap'); + +// this will log: + +// "face" +// "swap</pre> + +<h3 id="标记函数声明">标记函数声明</h3> + +<p>从ECMAScript 2015开始,标准的函数声明现在对规范的 <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-labelled-function-declarations">Web 兼容性附件</a>中的非严格代码进行了标准化。</p> + +<pre class="brush: js">L: function F() {}</pre> + +<p>在<a href="/zh-CN/docs/Web/JavaScript/Reference/Strict_mode">严格模式</a>中,这会抛出 {{jsxref("SyntaxError")}}:</p> + +<pre class="brush: js">'use strict'; +L: function F() {} +// SyntaxError: functions cannot be labelled +</pre> + +<p>无论是否处于严格模式下,<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/function*">生成器函数</a>都不能被标记:</p> + +<pre class="brush: js">L: function* F() {} +// SyntaxError: generator functions cannot be labelled</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Initial definition. Implemented in JavaScript 1.2</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.12', 'Labelled statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-labelled-statements', 'Labelled statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-labelled-statements', 'Labelled statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements.label")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Statements/break", "break")}}</li> + <li>{{jsxref("Statements/continue", "continue")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/let/index.html b/files/zh-cn/web/javascript/reference/statements/let/index.html new file mode 100644 index 0000000000..84898ef237 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/let/index.html @@ -0,0 +1,279 @@ +--- +title: let +slug: Web/JavaScript/Reference/Statements/let +tags: + - ECMAScript 2015 + - ECMAScript6 + - JavaScript + - let + - 变量 + - 变量声明 + - 声明 +translation_of: Web/JavaScript/Reference/Statements/let +--- +<div>{{jsSidebar("Statements")}}</div> + +<div></div> + +<div><strong>let</strong> 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。</div> + +<div>{{EmbedInteractiveExample("pages/js/statement-let.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox notranslate">let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>var1</code>, <code>var2</code>, …, <code>varN</code></dt> + <dd>变量名。必须是合法的标识符。</dd> + <dt><code>value1</code>, <code>value2</code>, …, <code>valueN</code> </dt> + <dd>变量的初始值。可以是任意合法的表达式。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p><strong><code>let</code></strong>允许你声明一个作用域被限制在 {{jsxref("statements/block", "块")}}级中的变量、语句或者表达式。与 {{jsxref("statements/var", "var")}} 关键字不同的是, {{jsxref("statements/var", "var")}}声明的变量只能是全局或者整个函数块的。 {{jsxref("statements/var", "var")}} 和 <code>let</code> 的不同之处在于后者是在编译时才初始化(<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/let#暂存死区">见下面</a>)。</p> + +<p>就像{{jsxref("statements/const", "const", "Description")}} 一样,<code>let</code>不会在全局声明时(在最顶部的范围)创建{{domxref('window')}} 对象的属性。</p> + +<p>可以从<a href="https://stackoverflow.com/questions/37916940/js-why-let-have-this-name">这里</a>了解我们为什么使用“<strong>let</strong>”。</p> + +<h3 id="作用域规则">作用域规则</h3> + +<p><code><strong>let</strong></code>声明的变量只在其声明的块或子块中可用,这一点,与<code><strong>var</strong></code>相似。二者之间最主要的区别在于<code><strong>var</strong></code>声明的变量的作用域是整个封闭函数。</p> + +<pre class="brush: js notranslate">function varTest() { + var x = 1; + { + var x = 2; // 同样的变量! + console.log(x); // 2 + } + console.log(x); // 2 +} + +function letTest() { + let x = 1; + { + let x = 2; // 不同的变量 + console.log(x); // 2 + } + console.log(x); // 1 +} +</pre> + +<p id="Scoping_rules">在程序和方法的最顶端,<strong><code>let</code></strong>不像 <strong><code>var</code></strong> 一样,<strong><code>let</code></strong>不会在全局对象里新建一个属性。比如:</p> + +<p>位于函数或代码顶部的<strong><code>var</code></strong>声明会给全局对象新增属性, 而<strong><code>let</code></strong>不会。例如:</p> + +<pre class="brush: js notranslate">var x = 'global'; +let y = 'global'; +console.log(this.x); // "global" +console.log(this.y); // undefined +</pre> + +<h3 id="模仿私有成员">模仿私有成员</h3> + +<p>在处理<a href="https://developer.mozilla.org/en-US/docs/Glossary/Constructor">构造函数</a>的时候,可以通过<code><strong>let</strong></code>声明而不是闭包来创建一个或多个私有成员。</p> + +<pre class="brush: js notranslate">var Thing; + +{ + let privateScope = new WeakMap(); + let counter = 0; + + Thing = function() { + this.someProperty = 'foo'; + + privateScope.set(this, { + hidden: ++counter, + }); + }; + + Thing.prototype.showPublic = function() { + return this.someProperty; + }; + + Thing.prototype.showPrivate = function() { + return privateScope.get(this).hidden; + }; +} + +console.log(typeof privateScope); +// "undefined" + +var thing = new Thing(); + +console.log(thing); +// Thing {someProperty: "foo"} + +thing.showPublic(); +// "foo" + +thing.showPrivate(); +// 1</pre> + +<p>可以使用<code>var</code>创建和闭包具有相同隐私模式的局部变量,但是它们需要函数作用域(通常是模块模式中的IIFE),而不仅仅是上面示例中的块作用域。</p> + +<h3 id="重复声明">重复声明</h3> + +<p>在同一个函数或块作用域中重复声明同一个变量会引起{{jsxref("SyntaxError")}}。</p> + +<pre class="brush: js example-bad notranslate">if (x) { + let foo; + let foo; // SyntaxError thrown. +} +</pre> + +<p>在 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/switch"><code>switch</code></a> 语句中只有一个块,你可能因此而遇到错误。</p> + +<pre class="brush: js example-bad notranslate">let x = 1; +switch(x) { + case 0: + let foo; + break; + + case 1: + let foo; // SyntaxError for redeclaration. + break; +} +</pre> + +<p>然而,需要特别指出的是,一个嵌套在 case 子句中的块会创建一个新的块作用域的词法环境,就不会产生上诉重复声明的错误。</p> + +<pre class="notranslate">let x = 1; + +switch(x) { + case 0: { + let foo; + break; + } + case 1: { + let foo; + break; + } +} +</pre> + +<h3 id="暂存死区">暂存死区</h3> + +<p>与通过 <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting">var</a></code> 声明的有初始化值 <code>undefined</code> 的变量不同,通过 <code>let</code> 声明的变量直到它们的定义被执行时才初始化。在变量初始化前访问该变量会导致 <code><a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/ReferenceError">ReferenceError</a></code>。该变量处在一个自块顶部到初始化处理的“暂存死区”中。</p> + +<pre class="brush: js notranslate">function do_something() { + console.log(bar); // undefined + console.log(foo); // ReferenceError + var bar = 1; + let foo = 2; +}</pre> + +<h3 id="暂存死区与_typeof">暂存死区与 <code>typeof</code></h3> + +<p>与通过<code>var</code>声明的变量, 有初始化值 <code>undefined</code>和只是未声明的变量不同的是,如果使用<code>typeof</code>检测在暂存死区中的变量, 会抛出<code>ReferenceError</code>异常:</p> + +<pre class="notranslate"><code>// prints out 'undefined' +console.log(typeof undeclaredVariable); + +// results in a 'ReferenceError' +console.log(typeof i); +let i = 10;</code> +</pre> + +<h3 id="暂存死区和静态作用域词法作用域的相关例子">暂存死区和静态作用域/词法作用域的相关例子</h3> + +<p>由于词法作用域,表达式<code>(foo + 55)</code>内的标识符<code>foo</code>被认为是if块的foo变量,而不是值为33的块外面的变量foo。</p> + +<p>在同一行,这个if块中的<code>foo</code>已经在词法环境中被创建了,但是还没有到达(或者终止)它的初始化(这是语句本身的一部分)。</p> + +<p>这个if块里的<code>foo</code>还依旧在暂存死区里。</p> + +<pre class="brush: js example-bad notranslate">function test(){ + var foo = 33; + if (foo) { + let foo = (foo + 55); // ReferenceError + } +} +test();</pre> + +<p>在以下情况下,这种现象可能会使您感到困惑。 <code>let n of n.a</code>已经在for循环块的私有范围内。因此,标识符<code>n.a</code>被解析为位于指令本身("let n")中的“ n”对象的属性“ a”。</p> + +<p>在没有执行到它的初始化语句之前,它仍旧存在于暂存死区中。</p> + +<pre class="brush: js example-bad notranslate">function go(n) { + // n here is defined! + console.log(n); // Object {a: [1,2,3]} + + for (let n of n.a) { // ReferenceError + console.log(n); + } +} + +go({a: [1, 2, 3]});</pre> + +<h2 id="其他情况">其他情况</h2> + +<p>用在块级作用域中时, <strong><code>let</code></strong>将变量的作用域限制在块内, 而<code><strong>var</strong></code>声明的变量的作用域是在函数内.</p> + +<pre class="brush: js notranslate">var a = 1; +var b = 2; + +if (a === 1) { + var a = 11; // the scope is global + let b = 22; // the scope is inside the if-block + + console.log(a); // 11 + console.log(b); // 22 +} + +console.log(a); // 11 +console.log(b); // 2</pre> + +<p>而这种<code><strong>var</strong></code> 与 <strong><code>let</code></strong>合并的声明方式会报<code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a></code>错误, 因为<code><strong>var</strong></code>会将变量提升至块的顶部, 这会导致隐式地重复声明变量.</p> + +<pre class="brush: js example-bad notranslate">let x = 1; + +{ + var x = 2; // SyntaxError for re-declaration +}</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>{{SpecName('ES6', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>Initial definition. Does not specify let expressions or let blocks.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-let-and-const-declarations', 'Let and Const Declarations')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements.let")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/var"><code>var</code></a></li> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/const"><code>const</code></a></li> + <li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/">ES6 In Depth: <code>let</code> and <code>const</code></a></li> + <li><a href="https://blog.mozilla.org/addons/2015/10/14/breaking-changes-let-const-firefox-nightly-44/">Breaking changes in <code>let</code> and <code>const</code> in Firefox 44.</a></li> + <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md">You Don't Know JS: Scope & Closures: Chapter 3: Function vs. Block Scope</a></li> + <li><a href="https://stackoverflow.com/a/33198850/1125029">StackOverflow: What is the Temporal Dead Zone.</a></li> + <li><a href="https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable">StackOverflow: What is the difference between using let and var?</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/return/index.html b/files/zh-cn/web/javascript/reference/statements/return/index.html new file mode 100644 index 0000000000..a8ae7459e0 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/return/index.html @@ -0,0 +1,149 @@ +--- +title: return +slug: Web/JavaScript/Reference/Statements/return +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/return +--- +<div> +<div>{{jsSidebar("Statements")}}</div> +</div> + +<p><strong><code>return</code>语句</strong>终止函数的执行,并返回一个指定的值给函数调用者。</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox">return [[expression]]; </pre> + +<dl> + <dt><code>expression</code></dt> + <dd>表达式的值会被返回。如果忽略,则返回 <code>undefined</code>。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>当在函数体中使用<code>return</code>语句时,函数将会停止执行。如果指定一个值,则这个值返回给函数调用者。例如,以下函数返回其参数<code>x</code>的平方,其中<code>x</code>是数字。</p> + +<pre class="brush: js">function square(x) { + return x * x; +} +var demo = square(3); +// demo will equal 9</pre> + +<p>如果省略该值,则返回<code>undefined</code>。</p> + +<p>下面的 return 语句都会终止函数的执行:</p> + +<pre class="brush: js">return; +return true; +return false; +return x; +return x + y / 3; +</pre> + +<h3 id="自动插入分号">自动插入分号</h3> + +<p><a href="/zh-CN/docs/Web/JavaScript/Reference/Lexical_grammar#Automatic_semicolon_insertion">自动插入分号(ASI)</a> 规则会影响 <code>return</code> 语句。在 <code>return</code> 关键字和被返回的表达式之间不允许使用行终止符。</p> + +<pre class="brush: js">return +a + b;</pre> + +<p class="brush: js">根据 ASI,被转换为:</p> + +<pre class="brush: js">return; +a + b;</pre> + +<p>控制台会警告“unreachable code after return statement”。</p> + +<div class="note"> +<p>从 Gecko 40 {{geckoRelease(40)}}开始,如果在一个 return 语句后发现无法访问的代码,控制台将会显示一个警告。</p> +</div> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example:_Using_return" name="Example:_Using_return">中断一个函数的执行</h3> + +<p>函数将会在<code>return</code>语句执行后立即中止。</p> + +<pre class="brush: js">function counter() { + for (var count = 1; ; count++) { // 无限循环 + console.log(count + "A"); // 执行5次 + if (count === 5) { + return; + } + console.log(count + "B"); // 执行4次 + } + console.log(count + "C"); // 永远不会执行 +} + +counter(); + +// Output: +// 1A +// 1B +// 2A +// 2B +// 3A +// 3B +// 4A +// 4B +// 5A +</pre> + +<h3 id="返回一个函数">返回一个函数</h3> + +<p>另见关于<a href="/zh-CN/docs/Web/JavaScript/Guide/Closures">闭包</a>的文章。</p> + +<pre class="brush: js">function magic(x) { + return function calc(x) { return x * 42}; +} + +var answer = magic(); +answer(1337); // 56154 +</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>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.9', 'Return statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-return-statement', 'Return statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-return-statement', 'Return statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.return")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions_and_function_scope" title="En/Core_JavaScript_1.5_Reference/Functions">函数和函数作用域</a></li> + <li><a href="/zh-CN/docs/Web/JavaScript/Guide/Closures">闭包</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/switch/index.html b/files/zh-cn/web/javascript/reference/statements/switch/index.html new file mode 100644 index 0000000000..64cce4f231 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/switch/index.html @@ -0,0 +1,308 @@ +--- +title: switch +slug: Web/JavaScript/Reference/Statements/switch +tags: + - JavaScript + - Reference + - Statement + - Web + - 参考 + - 声明 +translation_of: Web/JavaScript/Reference/Statements/switch +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>switch</code> 语句</strong>评估一个<a href="/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_Operators">表达式</a>,将表达式的值与<code>case</code>子句匹配,并执行与该情况相关联的<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements">语句</a>。</p> + +<div>{{EmbedInteractiveExample("pages/js/statement-switch.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="brush: js notranslate">switch (expression) { + case value1: + // 当 expression 的结果与 value1 匹配时,执行此处语句 + [break;] + case value2: + // 当 expression 的结果与 value2 匹配时,执行此处语句 + [break;] + ... + case valueN: + // 当 expression 的结果与 valueN 匹配时,执行此处语句 + [break;] + [default: + // 如果 expression 与上面的 value 值都不匹配,执行此处语句 + [break;]] +}</pre> + +<dl> + <dt><code>expression</code></dt> + <dd>一个用来与 case 子语句匹配的表达式。</dd> + <dt><code>case valueN</code> {{optional_inline}}</dt> + <dd>用于匹配 <code>expression</code> 的 <code>case</code> 子句。如果 <code>expression</code> 与给定的 <code>valueN</code> 相匹配,则执行该 case 子句中的语句直到该 <code>switch</code> 语句结束或遇到一个 <code>break</code> 。</dd> + <dt><code>default</code> {{optional_inline}}</dt> + <dd>一个 <code>default</code> 子句;如果给定,这条子句会在 <code>expression</code> 的值与任一 <code>case</code> 语句均不匹配时执行。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>一个 switch 语句首先会计算其 expression 。然后,它将从第一个 case 子句开始直到寻找到一个其表达式值与所输入的 expression 的值所相等的子句(使用 <a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">严格运算符</a>,<code>===</code>)并将控制权转给该子句,执行相关语句。(如果多个 case 与提供的值匹配,则选择匹配的第一个 case,即使这些 case 彼此间并不相等。)</p> + +<p>如果没有 <code>case</code> 子句相匹配,程序则会寻找那个可选的 <code>default</code> 子句,如果找到了,将控制权交给它,执行相关语句。若没有 <code>default</code> 子句,程序将继续执行直到 <code>switch</code> 结束。按照惯例,<code>default</code> 子句是最后一个子句,不过也不需要这样做。</p> + +<p>可选的 <code><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/break" title="JavaScript/Reference/Statements/break">break</a></code> 语句确保程序立即从相关的 case 子句中跳出 switch 并接着执行 switch 之后的语句。若 <code>break</code> 被省略,程序会继续执行 <code>switch</code> 语句中的下一条语句。</p> + +<h2 id="示例">示例</h2> + +<h3 id="使用_switch">使用 <code>switch</code></h3> + +<p>下面的例子中,如果 <code>expr</code> 计算为 "Bananas",程序就会匹配值为 "Bananas" 的 case 然后执行相关语句。当遇到 <code>break</code> 时,程序就跳出 <code>switch</code> 然后执行 <code>switch</code> 后的语句。若 <code>break</code> 被省略,值为 "Cherries" 的 case 中的语句就也将被执行。</p> + +<pre class="brush: js notranslate">switch (expr) { + case 'Oranges': + console.log('Oranges are $0.59 a pound.'); + break; + case 'Apples': + console.log('Apples are $0.32 a pound.'); + break; + case 'Bananas': + console.log('Bananas are $0.48 a pound.'); + break; + case 'Cherries': + console.log('Cherries are $3.00 a pound.'); + break; + case 'Mangoes': + case 'Papayas': + console.log('Mangoes and papayas are $2.79 a pound.'); + break; + default: + console.log('Sorry, we are out of ' + expr + '.'); +} + +console.log("Is there anything else you'd like?"); +</pre> + +<h3 id="如果忘记_break_会怎么样?">如果忘记 break 会怎么样?</h3> + +<p>如果你忘记添加 break,那么代码将会从值所匹配的 case 语句开始运行,然后持续执行下一个 case 语句而不论值是否匹配。例子如下:</p> + +<pre class="brush: js notranslate">var foo = 0; +switch (foo) { + case -1: + console.log('negative 1'); + break; + case 0: // foo 的值为 0 所以匹配这里所以这一块会运行 + console.log(0); + // 注意:那个没写的 break 原本在这儿 + case 1: // 'case 0:' 里没有 break 语句所以这个 case 也会运行 + console.log(1); + break; // 遇到了 break,所以不会再继续进入 'case 2:' 了 + case 2: + console.log(2); + break; + default: + console.log('default'); +}</pre> + +<h3 id="我能把_default_放到_case_之间吗?">我能把 default 放到 case 之间吗?</h3> + +<p>可以啊!JavaScript 会在它找不到匹配项时跳回到那个 default :</p> + +<pre class="brush: js notranslate">var foo = 5; +switch (foo) { + case 2: + console.log(2); + break; // 遇到 break,所以不会继续进入 'default:' + default: + console.log('default') + // 掉到下面 + case 1: + console.log('1'); +} +</pre> + +<p>即使你把 default 放到其它 case 之上,它仍有效。</p> + +<h3 id="使用多准则_case_的方法">使用多准则 case 的方法</h3> + +<p>这个技术来源于此:</p> + +<p><a href="http://stackoverflow.com/questions/13207927/switch-statement-multiple-cases-in-javascript">Switch statement multiple cases in JavaScript (Stack Overflow)</a></p> + +<h4 id="多_case_-_单一操作">多 case - 单一操作</h4> + +<p>这种方法利用这样一个事实:如果 case 语句之下没有 break ,它将继续执行下一个 case 语句,而不管 case 是否符合条件。 请看“如果忘记 break 会怎么样?”部分。</p> + +<p>这是一个单操作顺序的 switch 语句,其中四个不同值的执行结果完全一样。</p> + +<pre class="brush: js notranslate">var Animal = 'Giraffe'; +switch (Animal) { + case 'Cow': + case 'Giraffe': + case 'Dog': + case 'Pig': + console.log('This animal will go on Noah\'s Ark.'); + break; + case 'Dinosaur': + default: + console.log('This animal will not.'); +}</pre> + +<h4 id="多_case_-_关联操作">多 case - 关联操作</h4> + +<p>这是一个关联操作顺序的 switch 语句,其中,根据所输入的整数,你会得到不同的输出。这表示它将以你放置 case 语句的顺序遍历,并且不必是数字顺序的。在 JavaScript 中,你甚至可以将字符串定义到这些 case 语句里。</p> + +<pre class="brush: js notranslate">var foo = 1; +var output = 'Output: '; +switch (foo) { + case 0: + output += 'So '; + case 1: + output += 'What '; + output += 'Is '; + case 2: + output += 'Your '; + case 3: + output += 'Name'; + case 4: + output += '?'; + console.log(output); + break; + case 5: + output += '!'; + console.log(output); + break; + default: + console.log('Please pick a number from 0 to 5!'); +}</pre> + +<p>这个例子的输出:</p> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Value</th> + <th scope="col">Log text</th> + </tr> + <tr> + <td>foo is NaN or not 1, 2, 3, 4, 5 or 0</td> + <td>Please pick a number from 0 to 5!</td> + </tr> + <tr> + <td>0</td> + <td>Output: So What Is Your Name?</td> + </tr> + <tr> + <td>1</td> + <td>Output: What Is Your Name?</td> + </tr> + <tr> + <td>2</td> + <td>Output: Your Name?</td> + </tr> + <tr> + <td>3</td> + <td>Output: Name?</td> + </tr> + <tr> + <td>4</td> + <td>Output: ?</td> + </tr> + <tr> + <td>5</td> + <td>Output: !</td> + </tr> + </tbody> +</table> + +<h3 id="switch_语句内的块级作用域"><code>switch</code> 语句内的块级作用域</h3> + +<p>随着绝大多数现代浏览器已支持 ECMAScript 2015 (ES6),在某些场景下您可能需要使用 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a> 和 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/const">const</a> 语句,以在块级作用域内声明变量。</p> + +<p>以这段代码为例:</p> + +<pre class="brush: js notranslate">const action = 'say_hello'; +switch (action) { + case 'say_hello': + let message = 'hello'; + console.log('0 ~5'); + break; + case 'say_hi': + let message = 'hi'; + case 6: console.log('6'); + break; + default: + console.log('Empty action received.'); + break; +}</pre> + +<p>这个示例会导致意想不到的错误 <code>Uncaught SyntaxError: Identifier 'message' has already been declared</code>.</p> + +<p>这是因为第一个 <code>let message = 'hello';</code> 与第二个 <code>let message = 'hi';</code> 语句产生了冲突,虽然他们处于各自分隔的 case 语句中,即 <code>case 'say_hello':</code> 和 <code>case 'say_hi':</code>。导致这一问题的根本原因在于两个 <code>let</code> 语句处于同一个块级作用域,所以它们被认为是同一个变量名的重复声明。</p> + +<p>通过把 case 语句包装到括号里面,我们就可以轻松解决这个问题。</p> + +<pre class="brush: js notranslate">const action = 'say_hello'; +switch (action) { + case 'say_hello': { // added brackets + let message = 'hello'; + console.log(message); + break; + } // added brackets + case 'say_hi': { // added brackets + let message = 'hi'; + console.log(message); + break; + } // added brackets + default: { // added brackets + console.log('Empty action received.'); + break; + } // added brackets +}</pre> + +<p>此时,这段代码就会在控制台输出 <code>hello</code>,不会再有任何报错。</p> + +<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>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Initial definition. Implemented in JavaScript 1.2</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.11', 'switch statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-switch-statement', 'switch statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-switch-statement', 'switch statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.statements.switch")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/if...else"><code>if...else</code></a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/throw/index.html b/files/zh-cn/web/javascript/reference/statements/throw/index.html new file mode 100644 index 0000000000..aee6a02e79 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/throw/index.html @@ -0,0 +1,195 @@ +--- +title: throw +slug: Web/JavaScript/Reference/Statements/throw +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/throw +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>throw</code>语句</strong>用来抛出一个用户自定义的异常。当前函数的执行将被停止(<code>throw</code>之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/try...catch"><code>catch</code></a>块。如果调用者函数中没有<code>catch</code>块,程序将会终止。</p> + +<p>{{EmbedInteractiveExample("pages/js/statement-throw.html")}}</p> + +<div class="hidden"> +<p>The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p> +</div> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">throw <em>expression</em>; </pre> + +<dl> + <dt><code>expression</code></dt> + <dd>要抛出的表达式。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p>使用<code>throw</code>语句来抛出一个异常。当你抛出异常时,<code>expression</code> 指定了异常的内容。下面的每行都抛出了一个异常:</p> + +<pre class="brush: js">throw "Error2"; // 抛出了一个值为字符串的异常 +throw 42; // 抛出了一个值为整数42的异常 +throw true; // 抛出了一个值为true的异常</pre> + +<p>注意<code>throw</code>语句同样受到<a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Automatic_semicolon_insertion">自动分号插入(ASI</a>)机制的控制,在<code>throw</code>关键字和值之间不允许有行终止符。</p> + +<h2 id="示例">示例</h2> + +<h3 id="抛出一个对象">抛出一个对象</h3> + +<p>你可以在抛出异常时指定一个对象。然后可以在<code>catch</code>块中引用对象的属性。以下示例创建一个类型为<code>UserException</code>的对象,并在<code>throw</code>语句中使用它。</p> + +<pre class="brush: js">function UserException(message) { + this.message = message; + this.name = "UserException"; +} +function getMonthName(mo) { + mo = mo-1; // 调整月份数字到数组索引 (1=Jan, 12=Dec) + var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", + "Aug", "Sep", "Oct", "Nov", "Dec"]; + if (months[mo] !== undefined) { + return months[mo]; + } else { + throw new UserException("InvalidMonthNo"); + } +} + +try { + // statements to try + var myMonth = 15; // 15 超出边界并引发异常 + var monthName = getMonthName(myMonth); +} catch (e) { + var monthName = "unknown"; + console.log(e.message, e.name); // 传递异常对象到错误处理 +} +</pre> + +<h3 id="另一个抛出异常对象的示例">另一个抛出异常对象的示例</h3> + +<p>下面的示例中测试一个字符串是否是美国邮政编码。如果邮政编码是无效的,那么<code>throw</code>语句将会抛出一个类型为 <code>ZipCodeFormatException</code>的异常对象实例。</p> + +<pre class="brush: js">/* + * 创建 ZipCode 示例. + * + * 可被接受的邮政编码格式: + * 12345 + * 12345-6789 + * 123456789 + * 12345 6789 + * + * 如果构造函数参数传入的格式不符合以上任何一个格式,将会抛出异常。 + */ + +function ZipCode(zip) { + zip = new String(zip); + pattern = /[0-9]{5}([- ]?[0-9]{4})?/; + if (pattern.test(zip)) { + // zip code value will be the first match in the string + this.value = zip.match(pattern)[0]; + this.valueOf = function() { + return this.value + }; + this.toString = function() { + return String(this.value) + }; + } else { + throw new ZipCodeFormatException(zip); + } +} + +function ZipCodeFormatException(value) { + this.value = value; + this.message = "不是正确的邮政编码"; + this.toString = function() { + return this.value + this.message + }; +} + +/* + * 这可能是一个验证美国地区中的脚本 + */ + +const ZIPCODE_INVALID = -1; +const ZIPCODE_UNKNOWN_ERROR = -2; + +function verifyZipCode(z) { + try { + z = new ZipCode(z); + } catch (e) { + if (e instanceof ZipCodeFormatException) { + return ZIPCODE_INVALID; + } else { + return ZIPCODE_UNKNOWN_ERROR; + } + } + return z; +} + +a = verifyZipCode(95060); // 返回 95060 +b = verifyZipCode(9560); // 返回 -1 +c = verifyZipCode("a"); // 返回 -1 +d = verifyZipCode("95060"); // 返回 95060 +e = verifyZipCode("95060 1234"); // 返回 95060 1234 +</pre> + +<h3 id="重新抛出异常">重新抛出异常</h3> + +<p>你可以使用<code>throw</code>来抛出异常。下面的例子捕捉了一个异常值为数字的异常,并在其值大于50后重新抛出异常。重新抛出的异常传播到闭包函数或顶层,以便用户看到它。</p> + +<pre class="brush: js">try { + throw n; // 抛出一个数值异常 +} catch (e) { + if (e <= 50) { + // 异常在 1-50 之间时,直接处理 + } else { + // 异常无法处理,重新抛出 + throw e; + } +} +</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>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Initial definition. Implemented in JavaScript 1.4</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.13', 'throw statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-throw-statement', 'throw statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-throw-statement', 'throw statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.throw")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch"><code>try...catch</code></a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/try...catch/index.html b/files/zh-cn/web/javascript/reference/statements/try...catch/index.html new file mode 100644 index 0000000000..ff290ab4ba --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/try...catch/index.html @@ -0,0 +1,302 @@ +--- +title: try...catch +slug: Web/JavaScript/Reference/Statements/try...catch +tags: + - Error + - Exception + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/try...catch +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>try...catch</code></strong>语句标记要尝试的语句块,并指定一个出现异常时抛出的响应。</p> + +<p>{{EmbedInteractiveExample("pages/js/statement-trycatch.html")}}</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">try { + <em>try_statements</em> +} +[catch (<em>exception_var_1</em> if <em>condition_1</em>) { // non-standard + <em>catch_statements_1</em> +}] +... +[catch (<em>exception_var_2</em>) { + <em>catch_statements_2</em> +}] +[finally { + <em>finally_statements</em> +}] +</pre> + +<dl> + <dt><code>try_statements</code></dt> + <dd>需要被执行的语句。</dd> +</dl> + +<dl> + <dt><code>catch_statements_1</code>, <code>catch_statements_2</code></dt> + <dd>如果在<code>try</code>块里有异常被抛出时执行的语句。</dd> +</dl> + +<dl> + <dt><code>exception_var_1</code>, <code>exception_var_2</code></dt> + <dd>用于保存关联<code>catch</code>子句的异常对象的标识符。</dd> +</dl> + +<dl> + <dt><code>condition_1</code></dt> + <dd>一个条件表达式。</dd> +</dl> + +<dl> + <dt><code>finally_statements</code></dt> + <dd>在<code>try</code>语句块之后执行的语句块。无论是否有异常抛出或捕获这些语句都将执行。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p><code>try</code>语句包含了由一个或者多个语句组成的<code>try</code>块, 和至少一个<code>catch</code>块或者一个<code>finally</code>块的其中一个,或者两个兼有, 下面是三种形式的<code>try</code>声明:</p> + +<ol> + <li><code>try...catch</code></li> + <li><code>try...finally</code></li> + <li><code>try...catch...finally</code></li> +</ol> + +<p><code>catch</code>子句包含<code>try</code>块中抛出异常时要执行的语句。也就是,你想让<code>try</code>语句中的内容成功, 如果没成功,你想控制接下来发生的事情,这时你可以在<code>catch</code>语句中实现。 如果在<code>try</code>块中有任何一个语句(或者从<code>try</code>块中调用的函数)抛出异常,控制立即转向<code>catch</code>子句。如果在<code>try</code>块中没有异常抛出,会跳过<code>catch</code>子句。</p> + +<p><code>finally</code>子句在<code>try</code>块和<code>catch</code>块之后执行但是在下一个<code>try</code>声明之前执行。无论是否有异常抛出或捕获它总是执行。</p> + +<p>你可以嵌套一个或者更多的<code>try</code>语句。如果内部的<code>try</code>语句没有<code>catch</code>子句,那么将会进入包裹它的<code>try</code>语句的<code>catch</code>子句。</p> + +<p>你也可以用<code>try</code>语句去处理 JavaScript 异常。参考<a href="/zh-CN/docs/Web/JavaScript/Guide">JavaScript 指南</a>了解更多关于 Javascript 异常的信息。</p> + +<h3 id="无条件的catch块">无条件的<code>catch</code>块</h3> + +<p>当使用单个无条件<code>catch</code>子句时,抛出的任何异常时都会进入到<code>catch</code>块。例如,当在下面的代码中发生异常时,控制转移到<code>catch</code>子句。</p> + +<pre class="brush: js">try { + throw "myException"; // generates an exception +} +catch (e) { + // statements to handle any exceptions + logMyErrors(e); // pass exception object to error handler +} +</pre> + +<p><code>catch</code>块指定一个标识符(在上面的示例中为e),该标识符保存由<code>throw</code>语句指定的值。<code>catch</code>块是唯一的,因为当输入<code>catch</code>块时,JavaScript 会创建此标识符,并将其添加到当前作用域;标识符仅在<code>catch</code>块执行时存在;<code>catch</code>块执行完成后,标识符不再可用。</p> + +<h3 id="条件catch块">条件<code>catch</code>块</h3> + +<p>{{non-standard_header}}</p> + +<p>你也可以用一个或者更多条件<code>catch</code>子句来处理特定的异常。在这种情况下,当异常抛出时将会进入合适的<code>catch</code>子句中。在下面的代码中,<code>try</code>块的代码可能会抛出三种异常:{{jsxref("TypeError")}},{{jsxref("RangeError")}}和{{jsxref("EvalError")}}。当一个异常抛出时,控制将会进入与其对应的<code>catch</code>语句。如果这个异常不是特定的,那么控制将转移到无条件<code>catch</code>子句。</p> + +<p>当用一个无条件<code>catch</code>子句和一个或多个条件语句时,无条件<code>catch</code>子句必须放在最后。否则当到达条件语句之前所有的异常将会被非条件语句拦截。</p> + +<p>提醒:这个功能不符合 ECMAscript 规范。</p> + +<pre class="brush: js">try { + myroutine(); // may throw three types of exceptions +} catch (e if e instanceof TypeError) { + // statements to handle TypeError exceptions +} catch (e if e instanceof RangeError) { + // statements to handle RangeError exceptions +} catch (e if e instanceof EvalError) { + // statements to handle EvalError exceptions +} catch (e) { + // statements to handle any unspecified exceptions + logMyErrors(e); // pass exception object to error handler +} +</pre> + +<p>下面用符合 ECMAscript 规范的简单的 JavaScript 来编写相同的“条件catch子句”(显然更加<span class="s1">冗长的</span>,但是可以在任何地方运行):</p> + +<pre class="brush: js">try { + myRoutine(); +} catch (e) { + if (e instanceof RangeError) { + // statements to handle this very common expected error + } else { + throw e; // re-throw the error unchanged + } +}</pre> + +<h3 id="异常标识符">异常标识符</h3> + +<p>当<code>try</code>块中的抛出一个异常时, <em><code>exception_var</code></em>(如<code>catch (e)</code>中的<code>e</code>)用来保存被抛出声明指定的值。你可以用这个标识符来获取关于被抛出异常的信息。</p> + +<p>这个标识符是<code>catch</code>子语句内部的。换言之,当进入<code>catch</code>子语句时标识符创建,<code>catch</code>子语句执行完毕后,这个标识符将不再可用。</p> + +<pre class="brush: js">function isValidJSON(text) { + try { + JSON.parse(text); + return true; + } catch { + return false; + } +}</pre> + +<h3 id="finally块"><code>finally</code>块</h3> + +<p><code>finally</code>块包含的语句在<code>try</code>块和<code>catch</code>之后,<code>try..catch..finally</code>块后的语句之前执行。请注意,无论是否抛出异常<code>finally</code>子句都会执行。此外,如果抛出异常,即使没有<code>catch</code>子句处理异常,<code>finally</code>子句中的语句也会执行。</p> + +<p>以下示例打开一个文件,然后执行使用该文件的语句(服务器端 JavaScript 允许您访问文件)。如果文件打开时抛出异常,则<code>finally</code>子句会在脚本失败之前关闭该文件。finally中的代码最终也会在<code>try</code>或<code>catch block</code>显式返回时执行。</p> + +<pre class="brush: js">openMyFile() +try { + // tie up a resource + writeMyFile(theData); +} +finally { + closeMyFile(); // always close the resource +} +</pre> + +<h2 id="示例">示例</h2> + +<h3 id="嵌套_try_块">嵌套 try 块</h3> + +<p>首先让我们看看这里发生什么:</p> + +<pre class="brush: js">try { + try { + throw new Error("oops"); + } + finally { + console.log("finally"); + } +} +catch (ex) { + console.error("outer", ex.message); +} + +// Output: +// "finally" +// "outer" "oops" +</pre> + +<p>现在,如果我们已经在 try 语句中,通过增加一个 catch 语句块捕获了异常</p> + +<pre class="brush: js">try { + try { + throw new Error("oops"); + } + catch (ex) { + console.error("inner", ex.message); + } + finally { + console.log("finally"); + } +} +catch (ex) { + console.error("outer", ex.message); +} + +// Output: +// "inner" "oops" +// "finally" +</pre> + +<p>现在,让我们再次抛出错误。</p> + +<pre class="brush: js">try { + try { + throw new Error("oops"); + } + catch (ex) { + console.error("inner", ex.message); + throw ex; + } + finally { + console.log("finally"); + } +} +catch (ex) { + console.error("outer", ex.message); +} + +// Output: +// "inner" "oops" +// "finally" +// "outer" "oops" +</pre> + +<p>任何给定的异常只会被离它最近的封闭 catch 块捕获一次。当然,在“inner”块抛出的任何新异常 (因为 catch 块里的代码也可以抛出异常),将会被“outer”块所捕获。</p> + +<h3 id="从_finally_语句块返回">从 finally 语句块返回</h3> + +<p>如果从<code>finally</code>块中返回一个值,那么这个值将会成为整个<code>try-catch-finally</code>的返回值,无论是否有<code>return</code>语句在<code>try</code>和<code>catch</code>中。这包括在<code>catch</code>块里抛出的异常。</p> + +<pre class="brush: js">try { + try { + throw new Error("oops"); + } + catch (ex) { + console.error("inner", ex.message); + throw ex; + } + finally { + console.log("finally"); + return; + } +} +catch (ex) { + console.error("outer", ex.message); +} + +// 注: 此 try catch 语句需要在 function 中运行才能作为函数的返回值, 否则直接运行会报语法错误 +// Output: +// "inner" "oops" +// "finally" +</pre> + +<p>因为 finally 块里的 return 语句,"oops" 没有抛出到外层,从 catch 块返回的值同样适用。</p> + +<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>{{SpecName('ES3')}}</td> + <td>{{Spec2('ES3')}}</td> + <td>Initial definition. Implemented in JavaScript 1.4</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.14', 'try statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-try-statement', 'try statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-try-statement', 'try statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td>Not part of the current ECMA-262 standard: Multiple catch clauses and conditional clauses (SpiderMonkey extension, JavaScript 1.5).</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.try_catch")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Error")}}</li> + <li>{{jsxref("Statements/throw", "throw")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/var/index.html b/files/zh-cn/web/javascript/reference/statements/var/index.html new file mode 100644 index 0000000000..8e28dc4d17 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/var/index.html @@ -0,0 +1,216 @@ +--- +title: var 描述 +slug: Web/JavaScript/Reference/Statements/var +tags: + - JavaScript + - Statement + - 声明 +translation_of: Web/JavaScript/Reference/Statements/var +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong><code>var</code> 声明语句</strong>声明一个变量,并可选地将其初始化为一个值。</p> + +<p>{{EmbedInteractiveExample("pages/js/statement-var.html")}}</p> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">var <em>varname1 [</em>= <em>value1] [</em>, <em>varname2 [</em>= <em>value2] </em><em>... [</em>, <em>varnameN [</em>= <em>valueN]]]</em>;</pre> + +<dl> + <dt><code>varnameN</code></dt> + <dd>变量名。变量名可以定义为任何合法标识符。</dd> +</dl> + +<dl> + <dt><code>valueN</code></dt> + <dd>变量的初始化值。该值可以是任何合法的表达式。默认值为 <code>undefined</code>。</dd> +</dl> + +<h2 id="Description" name="Description">描述</h2> + +<p>变量声明,无论发生在何处,都在执行任何代码之前进行处理。用 <code>var</code> 声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,或者对于声明在任何函数外的变量来说是全局。如果你重新声明一个 JavaScript 变量,它将不会丢失其值。</p> + +<p>当赋值给未声明的变量, 则执行赋值后, 该变量会被隐式地创建为全局变量(它将成为全局对象的属性)。</p> + +<p>声明和未声明变量之间的差异是:</p> + +<p>1. 声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。</p> + +<pre class="brush: js">function x() { + y = 1; // 在严格模式(strict mode)下会抛出 ReferenceError 异常 + var z = 2; +} + +x(); + +console.log(y); // 打印 "1" +console.log(z); // 抛出 ReferenceError: z 未在 x 外部声明 +</pre> + +<p>2. 声明变量在任何代码执行前创建,而非声明变量只有在执行赋值操作的时候才会被创建。</p> + +<pre class="brush: js">console.log(a); // 抛出ReferenceError。 +console.log('still going...'); // 打印"still going..."。</pre> + +<pre class="brush: js">var a; +console.log(a); // 打印"undefined"或""(不同浏览器实现不同)。 +console.log('still going...'); // 打印"still going..."。</pre> + +<p>3. 声明变量是它所在上下文环境的不可配置属性,非声明变量是可配置的(如非声明变量可以被删除)。</p> + +<pre class="brush: js">var a = 1; +b = 2; + +delete this.a; // 在严格模式(strict mode)下抛出TypeError,其他情况下执行失败并无任何提示。 +delete this.b; + +console.log(a, b); // 抛出ReferenceError。 +// 'b'属性已经被删除。 +</pre> + +<p>由于这三个差异,未能声明变量将很可能导致意想不到的结果。因此,<strong>建议始终声明变量,无论它们是在函数还是全局作用域内</strong>。 而且,在 ECMAScript 5 <a href="/zh-CN/docs/Web/JavaScript/Reference/Strict_mode">严格模式</a>下,分配给未声明的变量会引发错误。</p> + +<h3 id="变量提升">变量提升</h3> + +<p>由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。这意味着变量可以在声明之前使用,这个行为叫做“hoisting”。“hoisting”就像是把所有的变量声明移动到函数或者全局代码的开头位置。</p> + +<pre class="brush: js">bla = 2 +var bla; +// ... + +// 可以隐式地(implicitly)将以上代码理解为: + +var bla; +bla = 2; +</pre> + +<p>因此,建议始终在作用域顶部声明变量(全局代码的顶部和函数代码的顶部),这可以清楚知道哪些变量是函数作用域(本地),哪些变量在作用域链上解决。</p> + +<p>重要的是,提升将影响变量声明,而不会影响其值的初始化。当到达赋值语句时,该值将确实被分配:</p> + +<pre class="brush: js">function do_something() { + console.log(bar); // undefined + var bar = 111; + console.log(bar); // 111 +} + +// is implicitly understood as: +function do_something() { + var bar; + console.log(bar); // undefined + bar = 111; + console.log(bar); // 111 +}</pre> + +<h2 id="Examples" name="Examples">例子</h2> + +<h3 id="声明并初始化两个变量:">声明并初始化两个变量:</h3> + +<pre class="brush: js">var a = 0, b = 0; +</pre> + +<h3 id="给两个变量赋值成字符串值:">给两个变量赋值成字符串值:</h3> + +<pre class="brush: js">var a = "A"; +var b = a; + +// 等效于: + +var a, b = a = "A"; +</pre> + +<p>留意其中的顺序:</p> + +<pre class="brush: js">var x = y, y = 'A'; +console.log(x + y); // undefinedA +</pre> + +<p>在这里,<code>x</code> 和 <code>y</code> 在代码执行前就已经创建了,而赋值操作发生在创建之后。当"<code>x = y</code>"执行时,<code>y</code> 已经存在,所以不抛出<code>ReferenceError</code>,并且它的值是'<code>undefined</code>'。所以 <code>x</code> 被赋予 undefined 值。然后,<code>y</code> 被赋予'A'。于是,在执行完第一行之后,<code>x === undefined && y === 'A'</code> 才出现了这样的结果。</p> + +<h3 id="多个变量的初始化">多个变量的初始化</h3> + +<pre class="brush: js">var x = 0; + +function f(){ + var x = y = 1; // x在函数内部声明,y不是! +} +f(); + +console.log(x, y); // 0, 1 +// x 是全局变量。 +// y 是隐式声明的全局变量。 </pre> + +<h3 id="隐式全局变量和外部函数作用域">隐式全局变量和外部函数作用域</h3> + +<p>看起来像是隐式全局作用域的变量也有可能是其外部函数变量的引用。</p> + +<pre class="brush: js">var x = 0; // x是全局变量,并且赋值为0。 + +console.log(typeof z); // undefined,因为z还不存在。 + +function a() { // 当a被调用时, + var y = 2; // y被声明成函数a作用域的变量,然后赋值成2。 + + console.log(x, y); // 0 2 + + function b() { // 当b被调用时, + x = 3; // 全局变量x被赋值为3,不生成全局变量。 + y = 4; // 已存在的外部函数的y变量被赋值为4,不生成新的全局变量。 + z = 5; // 创建新的全局变量z,并且给z赋值为5。 + } // (在严格模式下(strict mode)抛出ReferenceError) + + b(); // 调用b时创建了全局变量z。 + console.log(x, y, z); // 3 4 5 +} + +a(); // 调用a时同时调用了b。 +console.log(x, z); // 3 5 +console.log(typeof y); // undefined,因为y是a函数的本地(local)变量。</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES1')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition. Implemented in JavaScript 1.0</td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.2', 'var statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-variable-statement', 'variable statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-variable-statement', 'variable statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.var")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/let"><code>let</code></a></li> + <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/const"><code>const</code></a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/while/index.html b/files/zh-cn/web/javascript/reference/statements/while/index.html new file mode 100644 index 0000000000..2faf378422 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/while/index.html @@ -0,0 +1,101 @@ +--- +title: while +slug: Web/JavaScript/Reference/Statements/while +tags: + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/while +--- +<div>{{jsSidebar("Statements")}}</div> + +<p><strong>while 语句</strong>可以在某个条件表达式为真的前提下,循环执行指定的一段代码,直到那个表达式不为真时结束循环。</p> + +<div>{{EmbedInteractiveExample("pages/js/statement-while.html")}}</div> + + + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">while (<em>condition</em>) + <em>statement</em> +</pre> + +<dl> + <dt><code>condition</code></dt> + <dd>条件表达式,在每次循环前被求值。如果求值为真,<code>statement</code>就会被执行。如果求值为假,则跳出<code>while</code>循环执行后面的语句。</dd> + <dt><code>statement</code></dt> + <dd>只要条件表达式求值为真,该语句就会一直被执行。要在循环中执行多条语句,可以使用块语句(<code>{ ... }</code>)包住多条语句。</dd> + <dd>注意:使用<code>break</code>语句在<code>condition</code>计算结果为真之前停止循环。</dd> +</dl> + +<h2 id="示例">示例</h2> + +<p>下面的 <code>while</code> 循环会一直循环若干次,直到 <code>n</code> 等于 <code>3</code>。</p> + +<pre class="brush:js">var n = 0; +var x = 0; + +while (n < 3) { + n++; + x += n; +}</pre> + +<p>在每次循环中,<code>n</code> 都会自增 <code>1</code>,然后再把 <code>n</code> 加到 <code>x</code> 上。因此,在每轮循环结束后,<code>x</code> 和 <code>n</code> 的值分别是:</p> + +<ul> + <li>第一轮后:<code>n</code> = 1,<code>x</code> = 1</li> + <li>第二轮后:<code>n</code> = 2,<code>x</code> = 3</li> + <li>第三轮后:<code>n</code> = 3,<code>x</code> = 6</li> +</ul> + +<p>当完成第三轮循环后,条件表达式<code>n</code>< 3 不再为真,因此循环终止。</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-while-statement', 'while statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-while-statement', 'while statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.6.2', 'while statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.6.2', 'while statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.6.1', 'while statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.while")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Statements/do...while", "do...while")}}</li> + <li>{{jsxref("Statements/for", "for")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/statements/with/index.html b/files/zh-cn/web/javascript/reference/statements/with/index.html new file mode 100644 index 0000000000..3244d9f28d --- /dev/null +++ b/files/zh-cn/web/javascript/reference/statements/with/index.html @@ -0,0 +1,131 @@ +--- +title: with +slug: Web/JavaScript/Reference/Statements/with +tags: + - Deprecated + - JavaScript + - Statement +translation_of: Web/JavaScript/Reference/Statements/with +--- +<div class="warning">不建议使用<code>with</code>语句,因为它可能是混淆错误和兼容性问题的根源。有关详细信息,请参阅下面“描述”一节中的“语意不明的弊端”部分。</div> + +<div>{{jsSidebar("Statements")}}</div> + +<div><strong>with语句 </strong>扩展一个语句的作用域链。</div> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox notranslate">with (expression) { + <em>statement</em> +} +</pre> + +<dl> + <dt><code>expression</code></dt> + <dd>将给定的表达式添加到在评估语句时使用的作用域链上。表达式周围的括号是必需的。</dd> + <dt><code>statement</code></dt> + <dd>任何语句。要执行多个语句,请使用一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/block">块</a>语句 ({ ... })对这些语句进行分组。</dd> +</dl> + +<h2 id="Description" name="Description">描述</h2> + +<p>JavaScript查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的context或者包含这个变量的函数有关。'with'语句将某个对象添加到作用域链的顶部,如果在statement中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出{{jsxref("ReferenceError")}}异常。</p> + +<div class="note">不推荐使用<code>with</code>,在 ECMAScript 5 <a href="/zh-CN/docs/Web/JavaScript/Reference/Strict_mode">严格模式</a>中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。</div> + +<h3 id="性能方面的利与弊">性能方面的利与弊</h3> + +<p><strong>利:</strong><code>with</code>语句可以在不造成性能损失的情況下,减少变量的长度。其造成的附加计算量很少。使用'with'可以减少不必要的指针路径解析运算。需要注意的是,很多情況下,也可以不使用with语句,而是使用一个临时变量来保存指针,来达到同样的效果。</p> + +<p><strong>弊:</strong><code>with</code>语句使得程序在查找变量值时,都是先在指定的对象中查找。所以那些本来不是这个对象的属性的变量,查找起来将会很慢。如果是在对性能要求较高的场合,'with'下面的statement语句中的变量,只应该包含这个指定对象的属性。</p> + +<h3 id="语义不明的弊端">语义不明的弊端</h3> + +<p><strong>弊端:</strong><code>with</code>语句使得代码不易阅读,同时使得JavaScript编译器难以在作用域链上查找某个变量,难以决定应该在哪个对象上来取值。请看下面的例子:</p> + +<pre class="brush: js notranslate">function f(x, o) { + with (o) + print(x); +}</pre> + +<p><code>f</code>被调用时,<code>x</code>有可能能取到值,也可能是<code>undefined</code>,如果能取到, 有可能是在o上取的值,也可能是函数的第一个参数<code>x</code>的值(如果o中没有这个属性的话)。如果你忘记在作为第二个参数的对象o中定义<code>x</code>这个属性,程序并不会报错,只是取到另一个值而已。</p> + +<p><strong>弊端:</strong>使用<code>with</code>语句的代码,无法向前兼容,特別是在使用一些原生数据类型的时候。看下面的例子:</p> + +<div> +<pre class="brush:js notranslate">function f(foo, values) { + with (foo) { + console.log(values) + } +} +</pre> + +<p><font face="Open Sans, Arial, sans-serif">如果是在</font>ECMAScript 5环境调用<code>f([1,2,3], obj)</code>,则<code><font face="Open Sans, Arial, sans-serif">with</font></code>语句中变量<code>values</code>将指向函数的第二个参数<code>values</code>。但是,ECMAScript 6标准给<code><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype">Array.prototype</a></code>添加了一个新属性<code>values</code>,所有数组实例将继承这个属性。所以在ECMAScript 6环境中,<code><font face="Open Sans, Arial, sans-serif">with</font></code>语句中变量<code>values</code>将指向<code>[1,2,3].values</code>。</p> +</div> + +<h2 id="Examples" name="Examples">示例</h2> + +<h3 id="Example_Using_with" name="Example:_Using_with">Example: Using <code>with</code></h3> + +<p>下面的<code>with</code>语句指定<code><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math" title="JavaScript/Reference/Global_Objects/Math">Math</a></code>对象作为默认对象。<code>with</code>语句里面的变量,分別指向<code>Math</code>对象的<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/PI" title="JavaScript/Reference/Global_Objects/Math/PI"><code>PI</code></a> 、<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos" title="JavaScript/Reference/Global_Objects/Math/cos">cos</a><font face="Open Sans, Arial, sans-serif">和</font></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin" title="JavaScript/Reference/Global_Objects/Math/sin">sin</a></code>函数,不用在前面添加命名空间。后续所有引用都指向<code>Math</code>对象。</p> + +<pre class="brush:js notranslate">var a, x, y; +var r = 10; + +with (Math) { + a = PI * r * r; + x = r * cos(PI); + y = r * sin(PI / 2); +}</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>{{SpecName('ESDraft', '#sec-with-statement', 'with statement')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-with-statement', 'with statement')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-12.10', 'with statement')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td>Now forbidden in strict mode.</td> + </tr> + <tr> + <td>{{SpecName('ES3', '#sec-12.10', 'with statement')}}</td> + <td>{{Spec2('ES3')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ES1', '#sec-12.10', 'with statement')}}</td> + <td>{{Spec2('ES1')}}</td> + <td>Initial definition</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("javascript.statements.with")}}</p> + +<h2 id="See_also" name="See_also">相关链接</h2> + +<ul> + <li>{{jsxref("Statements/block", "block")}}</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">Strict mode</a></li> + <li>{{jsxref("Symbol.unscopables")}}</li> + <li>{{jsxref("Array.@@unscopables", "Array.prototype[@@unscopables]")}}</li> +</ul> |
