aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/reference/operators/delete/index.html
blob: ce03a46d292090b8e9615ab99df9c5598b4f5b06 (plain)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
---
title: delete 操作符
slug: Web/JavaScript/Reference/Operators/delete
tags:
  - JavaScript
  - Operator
  - Reference
  - delete
translation_of: Web/JavaScript/Reference/Operators/delete
---
<div>{{jsSidebar("Operators")}}</div>

<p> <strong><code>delete</code> 操作符</strong>用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放。</p>

<div>
<div>{{EmbedInteractiveExample("pages/js/expressions-deleteoperator.html")}}</div>
</div>



<h2 id="Syntax" name="Syntax">语法</h2>

<pre class="syntaxbox notranslate">delete <em>expression</em>
</pre>

<p> <em>expression</em> 的计算结果应该是某个属性的引用,例如:</p>

<pre class="syntaxbox notranslate">delete <em>object.property</em>
delete <em>object</em>['<em>property</em>']
</pre>

<h3 id="Parameters" name="Parameters">参数</h3>

<dl>
 <dt><code>object</code></dt>
 <dd>对象的名称,或计算结果为对象的表达式。</dd>
</dl>

<dl>
 <dt><code>property</code></dt>
 <dd>要删除的属性。</dd>
</dl>

<h3 id="返回值">返回值</h3>

<p>对于所有情况都是<code>true</code>,除非属性是一个{{jsxref("Object.hasOwnProperty", "自身的")}} {{jsxref("Errors/Cant_delete", "不可配置")}}的属性,在这种情况下,非严格模式返回 <code>false</code></p>

<h3 id="异常">异常</h3>

<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">严格模式</a>下,如果是属性是一个自己不可配置的属性,会抛出{{jsxref("TypeError")}}</p>

<h2 id="Description" name="Description">描述</h2>

<p>与通常的看法不同,<code>delete</code>操作符与直接释放内存<strong>无关</strong>。内存管理 通过断开引用来间接完成的,查看<a href="https://developer.mozilla.org/zh-CNdocs/Web/JavaScript/Memory_Management">内存管理</a>页可了解详情。</p>

<p><strong><code>delete </code></strong>操作符会从某个对象上移除指定属性。成功删除的时候会返回 <code>true</code>,否则返回 <code>false</code></p>

<p>但是,以下情况需要重点考虑:</p>

<ul>
 <li>如果你试图删除的属性不存在,那么delete将不会起任何作用,但仍会返回true</li>
 <li>如果对象的原型链上有一个与待删除属性同名的属性,那么删除属性之后,对象会使用原型链上的那个属性(也就是说,delete操作只会在自身的属性上起作用)</li>
 <li>任何使用 {{jsxref("Statements/var","var")}} 声明的属性不能从全局作用域或函数的作用域中删除。
  <ul>
   <li>这样的话,delete操作不能删除任何在全局作用域中的函数(无论这个函数是来自于函数声明或函数表达式)</li>
   <li>除了在全局作用域中的函数不能被删除,在对象(object)中的函数是能够用delete操作删除的。</li>
  </ul>
 </li>
 <li>任何用{{jsxref("Statements/let","let")}}{{jsxref("Statements/const","const")}}声明的属性不能够从它被声明的作用域中删除。</li>
 <li>不可设置的(Non-configurable)属性不能被移除。这意味着像{{jsxref("Math")}}, {{jsxref("Array")}}, {{jsxref("Object")}}内置对象的属性以及使用{{jsxref("Object.defineProperty()")}}方法设置为不可设置的属性不能被删除。</li>
</ul>

<p>下面的代码块给出了一个简单的例子:</p>

<pre class="brush: js notranslate">var Employee = {
  age: 28,
  name: 'abc',
  designation: 'developer'
}

console.log(delete Employee.name);   // returns true
console.log(delete Employee.age);    // returns true

// 当试着删除一个不存在的属性时
// 同样会返回true
console.log(delete Employee.salary); // returns true</pre>

<h3 id="不可配置属性">不可配置属性</h3>

<p>当一个属性被设置为不可设置,delete操作将不会有任何效果,并且会返回false。在严格模式下会抛出语法错误({{jsxref("SyntaxError")}})。</p>

<pre class="brush: js notranslate">var Employee = {};
Object.defineProperty(Employee, 'name', {configurable: false});

console.log(delete Employee.name);  // returns false</pre>

<p>{{jsxref("Statements/var","var")}}{{jsxref("Statements/let","let")}}以及{{jsxref("Statements/const","const")}}创建的不可设置的属性不能被delete操作删除。</p>

<pre class="brush: js notranslate">var nameOther = 'XYZ';

// 通过以下方法获取全局属性:
Object.getOwnPropertyDescriptor(window, 'nameOther');

// 输出: Object {value: "XYZ",
//                  writable: true,
//                  enumerable: true,
//                  configurable: false}

// 因为“nameOther”使用var关键词添加,
// 它被设置为不可设置(non-configurable)
delete nameOther;   // return false</pre>

<p>在严格模式下,这样的操作会抛出异常。</p>

<h3 id="严格模式与非严格模式的对比"><strong>严格模式与非严格模式的对比</strong></h3>

<p>在严格模式下,如果对一个变量的直接引用、函数的参数或者函数名使用delete操作,将会抛出语法错误({{jsxref("SyntaxError")}})。因此,为避免严格模式下的语法错误,必须以<code>delete object.property</code><code>delete object['property']</code>的形式使用delete运算符。</p>

<pre class="brush: js notranslate">Object.defineProperty(globalThis, 'variable1', { value: 10, configurable: true, });
Object.defineProperty(globalThis, 'variable2', { value: 10, configurable: false, });

console.log(delete variable1); // true

// SyntaxError in strict mode.
console.log(delete variable2); // false
</pre>

<pre class="brush: js notranslate">function func(param) {
  // SyntaxError in strict mode.
  console.log(delete param); // false
}

// SyntaxError in strict mode.
console.log(delete func); // false
</pre>

<div class="blockIndicator note">
<p>下文在英文原版中已删除</p>
</div>

<p>任何使用var声明的变量都会被标记为不可设置的。在下面的例子中,salary是不可设置的以及不能被删除的。在非严格模式下,下面的delete操作将会返回false。</p>

<pre class="brush: js notranslate">function Employee() {
  delete salary;
  var salary;
}

Employee();</pre>

<p>让我们来看看相同的代码在严格模式下会有怎样的表现。会抛出一个语法错误( <code>SyntaxError)而不是返回false。</code></p>

<pre class="brush: js notranslate">"use strict";

function Employee() {
  delete salary;  // SyntaxError
  var salary;
}

// 相似的,任何对任何函数
// 直接使用delete操作将会抛出语法错误。

function DemoFunction() {
  //some code
}

delete DemoFunction; // SyntaxError</pre>

<h2 id="示例">示例</h2>

<pre class="brush: js notranslate">// 在全局作用域创建 adminName 属性
adminName = 'xyz';

// 在全局作用域创建 empCount 属性
// 因为我们使用了 var,它会标记为不可配置。同样 let 或 const 也是不可配置的。
var empCount = 43;

EmployeeDetails = {
  name: 'xyz',
  age: 5,
  designation: 'Developer'
};

// adminName 是全局作用域的一个属性。
// 因为它不是用 var 创建的,所在可以删除。
// 因此,它是可配置的。
delete adminName;       // 返回 true

// 相反,empCount 是不可配置的,
// 因为创建它时使用了 var。
delete empCount;       // 返回 false

// delete 可用于删除对象的属性
delete EmployeeDetails.name; // 返回 true

// 甚至属性不存在,它也会返回 "true"
delete EmployeeDetails.salary; // 返回 true

// delete 对内建静态属性不起作用
delete Math.PI; // 返回 false

// EmployeeDetails 是全局作用域的一个属性。
// 因为定义它的时候没有使用 "var",它被标记为可配置。
delete EmployeeDetails;   // 返回 true

function f() {
  var z = 44;

  // delete 对局部变量名不起作用
  delete z;     // 返回 false
}</pre>

<h3 id="delete_和原型链"><code>delete</code> 和原型链</h3>

<p>在下面的示例中,我们删除一个对象的自己的属性,而原型链上具有相同名称的属性可用:</p>

<pre class="brush: js notranslate">function Foo() {
  this.bar = 10;
}

Foo.prototype.bar = 42;

var foo = new Foo();

// 返回 true,因为删除的是 foo 对象的自身属性
delete foo.bar;

// foo.bar 仍然可用,因为它在原型链上可用。
console.log(foo.bar);   //42

// 从原型上删除属性
delete Foo.prototype.bar; //true

// 由于已删除“ bar”属性,因此不能再从Foo继承它。
console.log(foo.bar);    //undefined
</pre>

<h3 id="Deleting_array_elements" name="Deleting_array_elements">删除数组元素</h3>

<p>当你删除一个数组元素时,数组的长度不受影响。即便你删除了数组的最后一个元素也是如此。</p>

<p>当用 <code>delete</code> 操作符删除一个数组元素时,被删除的元素已经不再属于该数组。下面的例子中用 <code>delete </code>删除了<code> trees[3]</code></p>

<pre class="brush: js notranslate">var trees = ["redwood","bay","cedar","oak","maple"];
delete trees[3];
if (3 in trees) {
   // 这里不会执行
}
</pre>

<p>如果你想让一个数组元素继续存在但是其值是 <code>undefined</code>,那么可以使用将 <code>undefined</code> 赋值给这个元素而不是使用 <code>delete</code>。下面的例子中,trees[3] 被赋值为 <code>undefined</code>,但该元素仍然存在。</p>

<pre class="brush: js notranslate">var trees = ["redwood","bay","cedar","oak","maple"];
trees[3] = undefined;
if (3 in trees) {
   // 这里会被执行
}</pre>

<p>如果你想通过改变数组的内容来移除一个数组元素,请使用{{jsxref("Array.splice()", "splice()")}} 方法。在下面的例子中,通过使用{{jsxref("Array.splice()", "splice()")}},将trees[3]从数组中移除。</p>

<pre class="brush: js notranslate">var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);
console.log(trees); // ["redwood", "bay", "cedar", "maple"]
</pre>

<h2 id="规范">规范</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Specification</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-delete-operator', 'The delete Operator')}}</td>
  </tr>
 </tbody>
</table>

<h2 id="浏览器兼容性">浏览器兼容性</h2>



<p>{{Compat("javascript.operators.delete")}}</p>

<h2 id="跨浏览器提示">跨浏览器提示</h2>

<p>尽管ECMAScript使得对象的迭代顺序依赖于实现,但似乎所有主流浏览器都支持基于最早添加的属性(至少对于不在原型上的属性)的迭代顺序(译注:ES5 标准取消了属性遍历的顺序的规定)。但是,在 IE 中,使用 <code>delete</code> 删除一个属性后,奇怪的事情发生了。在IE中,如果被删除的属性重新被添加,那么遍历时,该属性的顺序会在上次删除前的那个位置,而不是出现在遍历的最后一个。</p>

<p>如果您想在跨浏览器的环境中使用有序的关联数组,请使用{{jsxref("Map")}}对象(如果有),或使用两个单独的数组来模拟(一个用于键,另一个用于 值),或者建立<span class="short_text" id="result_box" lang="zh-CN"><span>一个</span><span>由单一</span><span>属性</span><span></span><span>对象组成的</span><span>数组</span></span>等。</p>

<h2 id="See_also" name="See_also">参见</h2>

<ul>
 <li><a href="http://perfectionkills.com/understanding-delete/">深入分析 delete</a></li>
 <li>{{jsxref("Reflect.deleteProperty()")}}</li>
 <li>{{jsxref("Map.prototype.delete()")}}</li>
</ul>