1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
---
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>
<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>
|