2019-04-21 11:50:48 +08:00

305 lines
24 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<article id="wikiArticle">
<div></div>
<p> <strong><code>delete</code> 操作符</strong>用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放。</p>
<div><iframe class="interactive interactive-js" frameborder="0" height="250" src="https://interactive-examples.mdn.mozilla.net/pages/js/expressions-deleteoperator.html" width="100%"></iframe></div>
<p 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 class="external" href="https://github.com/mdn/interactive-examples" rel="noopener">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p>
<h2 id="Syntax" name="Syntax">语法</h2>
<pre><code class="language-javascript">delete <em>expression</em>
</code></pre>
<p> <em>expression</em> 的计算结果应该是某个属性的引用,例如:</p>
<pre><code class="language-javascript">delete <em>object.property</em> 
delete <em>object</em>['<em>property</em>']
</code></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>,除非属性是一个自己不可配置的属性,在这种情况下,非严格模式返回 <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>下,如果是属性是一个自己不可配置的属性,会抛出<a href="Reference/Global_objects/SyntaxError" title="SyntaxError 对象代表尝试解析语法上不合法的代码的错误。"><code>Global_objects/SyntaxError</code></a></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>
<ul>
<li>如果你试图删除的属性不存在那么delete将不会起任何作用但仍会返回true</li>
<li>如果对象的原型链上有一个与待删除属性同名的属性那么删除属性之后对象会使用原型链上的那个属性也就是说delete操作只会在自身的属性上起作用</li>
<li>任何使用 <a href="Reference/Statements/var" title="var 声明语句声明一个变量,并可选地将其初始化为一个值。"><code>var</code></a> 声明的属性不能从全局作用域或函数的作用域中删除。
<ul>
<li>这样的话delete操作不能删除任何在全局作用域中的函数无论这个函数是来自于函数声明或函数表达式</li>
<li>除了在全局作用域中的函数不能被删除,在对象(object)中的函数是能够用delete操作删除的。</li>
</ul>
</li>
<li>任何用<a href="Reference/Statements/let" title="let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是var声明的变量只能是全局或者整个函数块的。"><code>let</code></a><a href="Reference/Statements/const" title="常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变并且不能重新声明。"><code>const</code></a>声明的属性不能够从它被声明的作用域中删除。</li>
<li>不可设置的(Non-configurable)属性不能被移除。这意味着像<a href="Reference/Global_Objects/Math" title="Math 是一个内置对象 它具有数学常数和函数的属性和方法。不是一个函数对象。"><code>Math</code></a>, <a href="Reference/Array" title="REDIRECT Array"><code>Array</code></a>, <a href="Reference/Global_Objects/Object" title="Object 构造函数创建一个对象包装器。"><code>Object</code></a>内置对象的属性以及使用<a href="Reference/Global_Objects/Object/defineProperty" title="Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。"><code>Object.defineProperty()</code></a>方法设置为不可设置的属性不能被删除。</li>
</ul>
<p>下面的代码块给出了一个简单的例子:</p>
<pre><code class="language-javascript">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</code></pre>
<h3 id="不可配置属性">不可配置属性</h3>
<p>当一个属性被设置为不可设置delete操作将不会有任何效果并且会返回false。在严格模式下会抛出语法错误<a href="Reference/Global_Objects/SyntaxError" title="SyntaxError 对象代表尝试解析语法上不合法的代码的错误。"><code>SyntaxError</code></a>)。</p>
<pre><code class="language-javascript">var Employee = {};
Object.defineProperty(Employee, 'name', {configurable: false});
console.log(delete Employee.name); // returns false</code></pre>
<p><a href="Reference/Statements/var" title="var 声明语句声明一个变量,并可选地将其初始化为一个值。"><code>var</code></a>, <a href="Reference/Statements/let" title="let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是var声明的变量只能是全局或者整个函数块的。"><code>let</code></a>以及<a href="Reference/Statements/const" title="常量是块级作用域,很像使用 let 语句定义的变量。常量的值不能通过重新赋值来改变并且不能重新声明。"><code>const</code></a>创建的不可设置的属性不能被delete操作删除。</p>
<pre><code class="language-javascript">var nameOther = 'XYZ';
// 通过以下方法获取全局属性:
Object.getOwnPropertyDescriptor(window, 'nameOther');
// 输出: Object {value: "XYZ",
// writable: true,
// enumerable: true,
// configurable: false}
// 因为“nameOther”使用var关键词添加
// 它被设置为不可设置non-configurable
delete nameOther; // return false</code></pre>
<p>在严格模式下,这样的操作会抛出异常。</p>
<h3 id="严格模式与非严格模式的对比"><strong>严格模式与非严格模式的对比</strong></h3>
<p>在严格模式下如果对一个变量的直接引用、函数的参数或者函数名使用delete操作将会抛出语法错误<a href="Reference/Global_Objects/SyntaxError" title="SyntaxError 对象代表尝试解析语法上不合法的代码的错误。"><code>SyntaxError</code></a>)。</p>
<p>任何使用var声明的变量都会被标记为不可设置的。在下面的例子中salary是不可设置的以及不能被删除的。在非严格模式下下面的delete操作将会返回false。</p>
<pre><code class="language-javascript">function Employee() {
delete salary;
var salary;
}
Employee();</code></pre>
<p>让我们来看看相同的代码在严格模式下会有怎样的表现。会抛出一个语法错误( <code>SyntaxError而不是返回false。</code></p>
<pre><code class="language-javascript">"use strict";
function Employee() {
delete salary; // SyntaxError
var salary;
}
// 相似的,任何对任何函数
// 直接使用delete操作将会抛出语法错误。
function DemoFunction() {
//some code
}
delete DemoFunction; // SyntaxError</code></pre>
<h2 id="示例">示例</h2>
<pre><code class="language-javascript">// 在全局作用域创建 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
}</code></pre>
<h3 id="delete_和原型链"><code>delete</code> 和原型链</h3>
<p>在下面的示例中,我们删除一个对象的自己的属性,而原型链上具有相同名称的属性可用:</p>
<pre><code class="language-javascript">function Foo() {
this.bar = 10;
}
Foo.prototype.bar = 42;
var foo = new Foo();
// 返回 true因为删除的是 foo 对象的自身属性
delete foo.bar;
// foo.bar 仍然可用,因为它在原型链上可用。
console.log(foo.bar);
// 从原型上删除属性
delete Foo.prototype.bar;
// 输出 "undefined",因为不能继承这个属性了
console.log(foo.bar);
</code></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><code class="language-javascript">var trees = ["redwood","bay","cedar","oak","maple"];
delete trees[3];
if (3 in trees) {
// 这里不会执行
}
</code></pre>
<p>如果你想让一个数组元素继续存在但是其值是 <code>undefined</code>,那么可以使用将 <code>undefined</code> 赋值给这个元素而不是使用 <code>delete</code>。下面的例子中trees[3] 被赋值为 <code>undefined</code>,但该元素仍然存在。</p>
<pre><code class="language-javascript">var trees = ["redwood","bay","cedar","oak","maple"];
trees[3] = undefined;
if (3 in trees) {
// 这里会被执行
}</code></pre>
<p>如果你想通过改变数组的内容来移除一个数组元素,请使用<code><a href="Reference/Global_Objects/Array/splice" title="splice() 方法通过删除或替换现有元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。"><code>splice</code></a></code>方法。在下面的例子中,通过使用<code><a href="Reference/Global_Objects/Array/splice" title="splice() 方法通过删除或替换现有元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。"><code>splice</code></a></code>将trees[3]从数组中移除。</p>
<pre><code class="language-javascript">var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);
console.log(trees); // ["redwood", "bay", "cedar", "maple"]</code></pre>
<h2 id="规范">规范</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
<tr>
<td><a class="external" href="https://tc39.github.io/ecma262/#sec-delete-operator" hreflang="en" lang="en" rel="noopener">ECMAScript Latest Draft (ECMA-262)<br/><small lang="zh-CN">The delete Operator</small></a></td>
<td><span class="spec-Draft">Draft</span></td>
<td> </td>
</tr>
<tr>
<td><a class="external" href="https://www.ecma-international.org/ecma-262/6.0/#sec-delete-operator" hreflang="en" lang="en" rel="noopener">ECMAScript 2015 (6th Edition, ECMA-262)<br/><small lang="zh-CN">The delete Operator</small></a></td>
<td><span class="spec-Standard">Standard</span></td>
<td> </td>
</tr>
<tr>
<td><a class="external" href="https://www.ecma-international.org/ecma-262/5.1/#sec-11.4.1" hreflang="en" lang="en" rel="noopener">ECMAScript 5.1 (ECMA-262)<br/><small lang="zh-CN">The delete Operator</small></a></td>
<td><span class="spec-Standard">Standard</span></td>
<td> </td>
</tr>
<tr>
<td><a class="external" href="https://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%201st%20edition,%20June%201997.pdf#sec-11.4.1" hreflang="en" lang="en" rel="noopener">ECMAScript 1st Edition (ECMA-262)<br/><small lang="zh-CN">The delete Operator</small></a></td>
<td><span class="spec-Standard">Standard</span></td>
<td>Initial definition. Implemented in JavaScript 1.2.</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 class="external" href="https://github.com/mdn/browser-compat-data" rel="noopener">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div>
<p></p><div class="bc-data"><a class="bc-github-link external" href="https://github.com/mdn/browser-compat-data" rel="noopener">Update compatibility data on GitHub</a><table class="bc-table bc-table-js"><thead><tr class="bc-platforms"><td></td><th class="bc-platform-desktop" colspan="6"><span>Desktop</span></th><th class="bc-platform-mobile" colspan="7"><span>Mobile</span></th><th class="bc-platform-server" colspan="1"><span>Server</span></th></tr><tr class="bc-browsers"><td></td><th class="bc-browser-chrome"><span class="bc-head-txt-label bc-head-icon-chrome">Chrome</span></th><th class="bc-browser-edge"><span class="bc-head-txt-label bc-head-icon-edge">Edge</span></th><th class="bc-browser-firefox"><span class="bc-head-txt-label bc-head-icon-firefox">Firefox</span></th><th class="bc-browser-ie"><span class="bc-head-txt-label bc-head-icon-ie">Internet Explorer</span></th><th class="bc-browser-opera"><span class="bc-head-txt-label bc-head-icon-opera">Opera</span></th><th class="bc-browser-safari"><span class="bc-head-txt-label bc-head-icon-safari">Safari</span></th><th class="bc-browser-webview_android"><span class="bc-head-txt-label bc-head-icon-webview_android">Android webview</span></th><th class="bc-browser-chrome_android"><span class="bc-head-txt-label bc-head-icon-chrome_android">Chrome for Android</span></th><th class="bc-browser-edge_mobile"><span class="bc-head-txt-label bc-head-icon-edge_mobile">Edge Mobile</span></th><th class="bc-browser-firefox_android"><span class="bc-head-txt-label bc-head-icon-firefox_android">Firefox for Android</span></th><th class="bc-browser-opera_android"><span class="bc-head-txt-label bc-head-icon-opera_android">Opera for Android</span></th><th class="bc-browser-safari_ios"><span class="bc-head-txt-label bc-head-icon-safari_ios">Safari on iOS</span></th><th class="bc-browser-samsunginternet_android"><span class="bc-head-txt-label bc-head-icon-samsunginternet_android">Samsung Internet</span></th><th class="bc-browser-nodejs"><span class="bc-head-txt-label bc-head-icon-nodejs">Node.js</span></th></tr></thead><tbody><tr><th scope="row"><code>delete</code></th><td class="bc-supports-yes bc-browser-chrome"><span class="bc-browser-name">Chrome</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-edge"><span class="bc-browser-name">Edge</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-firefox"><span class="bc-browser-name">Firefox</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
1</td><td class="bc-supports-yes bc-browser-ie"><span class="bc-browser-name">IE</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-opera"><span class="bc-browser-name">Opera</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-safari"><span class="bc-browser-name">Safari</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-webview_android"><span class="bc-browser-name">WebView Android</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-chrome_android"><span class="bc-browser-name">Chrome Android</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-edge_mobile"><span class="bc-browser-name">Edge Mobile</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-firefox_android"><span class="bc-browser-name">Firefox Android</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
4</td><td class="bc-supports-yes bc-browser-opera_android"><span class="bc-browser-name">Opera Android</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-safari_ios"><span class="bc-browser-name">Safari iOS</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-samsunginternet_android"><span class="bc-browser-name">Samsung Internet Android</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td><td class="bc-supports-yes bc-browser-nodejs"><span class="bc-browser-name">nodejs</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
Yes</td></tr><tr><th scope="row">Temporal dead zone</th><td class="bc-supports-unknown bc-browser-chrome"><span class="bc-browser-name">Chrome</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-edge"><span class="bc-browser-name">Edge</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-yes bc-browser-firefox"><span class="bc-browser-name">Firefox</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
36</td><td class="bc-supports-unknown bc-browser-ie"><span class="bc-browser-name">IE</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-opera"><span class="bc-browser-name">Opera</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-safari"><span class="bc-browser-name">Safari</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-webview_android"><span class="bc-browser-name">WebView Android</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-chrome_android"><span class="bc-browser-name">Chrome Android</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-edge_mobile"><span class="bc-browser-name">Edge Mobile</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-yes bc-browser-firefox_android"><span class="bc-browser-name">Firefox Android</span><abbr class="bc-level-yes only-icon" title="Full support">
<span>Full support</span>
</abbr>
36</td><td class="bc-supports-unknown bc-browser-opera_android"><span class="bc-browser-name">Opera Android</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-safari_ios"><span class="bc-browser-name">Safari iOS</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-samsunginternet_android"><span class="bc-browser-name">Samsung Internet Android</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td><td class="bc-supports-unknown bc-browser-nodejs"><span class="bc-browser-name">nodejs</span><abbr title="Compatibility unknown; please update this.">
?
</abbr></td></tr></tbody></table><section class="bc-legend" id="sect1"><h3 class="offscreen" id="Legend">Legend</h3><dl><dt><span class="bc-supports-yes bc-supports">
<abbr class="bc-level bc-level-yes only-icon" title="Full support">
<span>Full support</span>
 
</abbr></span></dt><dd>Full support</dd><dt><span class="bc-supports-unknown bc-supports">
<abbr class="bc-level bc-level-unknown only-icon" title="Compatibility unknown">
<span>Compatibility unknown</span>
 
</abbr></span></dt><dd>Compatibility unknown</dd></dl></section></div><p></p>
<h2 id="跨浏览器提示">跨浏览器提示</h2>
<p>尽管ECMAScript使得对象的迭代顺序依赖于实现但似乎所有主流浏览器都支持基于最早添加的属性至少对于不在原型上的属性的迭代顺序译注ES5 标准取消了属性遍历的顺序的规定)。但是,在 IE 中,使用 <code>delete</code> 删除一个属性后,奇怪的事情发生了,如果被删除的属性重新被添加,那么遍历时,该属性的顺序会是上次删除前的那个位置所应该有的顺序,而不是出现在遍历的最后一个。</p>
<p>如果你想让对象的遍历顺序兼容所有的浏览器,那么你可以使用两个数组来模拟 (一个做为keys一个做为 values) 或者建立<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 class="external" href="http://perfectionkills.com/understanding-delete/" rel="noopener">深入分析 delete</a></li>
<li><a href="Reference/Global_Objects/Reflect/deleteProperty" title="静态方法 Reflect.deleteProperty() 允许用于删除属性。它很像 delete operator ,但它是一个函数。"><code>Reflect.deleteProperty()</code></a></li>
<li><a href="Reference/Global_Objects/Map/delete" title=" delete() 方法用于移除 Map 对象中指定的元素。"><code>Map.prototype.delete()</code></a></li>
</ul>
</article>