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

语法

delete expression

 expression 的计算结果应该是某个属性的引用,例如:

delete object.property 
delete object['property']

参数

object
对象的名称,或计算结果为对象的表达式。
property
要删除的属性。

返回值

对于所有情况都是true,除非属性是一个自己不可配置的属性,在这种情况下,非严格模式返回 false

异常

严格模式下,如果是属性是一个自己不可配置的属性,会抛出Global_objects/SyntaxError

描述

与通常的看法不同,delete操作符与直接释放内存无关。内存管理 通过断开引用来间接完成的,查看内存管理页可了解详情。

delete 操作符会从某个对象上移除指定属性。成功删除的时候回返回 true,否则返回 false。但是,以下情况需要重点考虑:

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

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

不可配置属性

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

var Employee = {};
Object.defineProperty(Employee, 'name', {configurable: false});

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

varlet以及const创建的不可设置的属性不能被delete操作删除。

var nameOther = 'XYZ';

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

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

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

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

严格模式与非严格模式的对比

在严格模式下,如果对一个变量的直接引用、函数的参数或者函数名使用delete操作,将会抛出语法错误(SyntaxError)。

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

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

Employee();

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

"use strict";

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

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

function DemoFunction() {
  //some code
}

delete DemoFunction; // SyntaxError

示例

// 在全局作用域创建 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
}

delete 和原型链

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

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);

删除数组元素

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

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

var trees = ["redwood","bay","cedar","oak","maple"];
delete trees[3];
if (3 in trees) {
   // 这里不会执行
}

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

var trees = ["redwood","bay","cedar","oak","maple"];
trees[3] = undefined;
if (3 in trees) {
   // 这里会被执行
}

如果你想通过改变数组的内容来移除一个数组元素,请使用splice方法。在下面的例子中,通过使用splice,将trees[3]从数组中移除。

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);
console.log(trees); // ["redwood", "bay", "cedar", "maple"]

规范

Specification Status Comment
ECMAScript Latest Draft (ECMA-262)
The delete Operator
Draft  
ECMAScript 2015 (6th Edition, ECMA-262)
The delete Operator
Standard  
ECMAScript 5.1 (ECMA-262)
The delete Operator
Standard  
ECMAScript 1st Edition (ECMA-262)
The delete Operator
Standard Initial definition. Implemented in JavaScript 1.2.

浏览器兼容性

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
deleteChrome Full support YesEdge Full support YesFirefox Full support 1IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesEdge Mobile Full support YesFirefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes
Temporal dead zoneChrome ? Edge ? Firefox Full support 36IE ? Opera ? Safari ? WebView Android ? Chrome Android ? Edge Mobile ? Firefox Android Full support 36Opera Android ? Safari iOS ? Samsung Internet Android ? nodejs ?

Legend

Full support  
Full support
Compatibility unknown  
Compatibility unknown

跨浏览器提示

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

如果你想让对象的遍历顺序兼容所有的浏览器,那么你可以使用两个数组来模拟 (一个做为keys,一个做为 values), 或者建立一个由单一属性对象组成的数组等。

参见