JavaScript delete操作符详解:原理、限制与返回值机制

作者:闭包旅人时间:2026-10-23 11:33:33浏览:642

本文深入解析JavaScript中delete操作符的实际行为。文章指出delete用于删除对象属性或数组元素,但不会删除对象本身。重点探讨了Global和Activation对象中变量的删除限制,以及prototype链和预定义属性(如ignoreCase)受DontDelete特性保护无法被删除的情况。此外,详细说明了delete的返回值规则:当属性存在且拥有DontDelete特性时返回false,否则返回true,即使属性不存在或操作非属性也会返回true。

JavaScript delete操作符详解:原理、限制与返回值机制

在研读prototype库源码时,我注意到了delete操作符的使用。


相关代码如下:

unset: function(key) {
var value = this._object[key];
delete this._object[key];
return value;
} 

查阅相关文档后,我对delete运算符有了更清晰的认识。


delete 运算符


该运算符用于从对象中移除一个属性,或者从数组中移除一个元素。


语法格式为:delete expression


其中expression参数是一个有效的JScript表达式,通常代表一个属性名或数组元素。


具体说明如下:


如果expression的计算结果是一个对象,且该对象中指定的属性确实存在,但该对象禁止删除此属性,则返回false。


在其余所有情况下,均返回true。


虽然文档提到可以“从数组中删除一个元素”,但在Firefox中测试发现,它似乎只是删除了该元素的值,而非元素本身。不过,从对象中删除属性是可行的。


通过搜索,我发现有一篇文章对此解释得非常详尽,现转载如下以防遗忘:


Javascript的变量与对象属性关系

Javascript的变量


在JavaScript中,变量本质上等同于对象属性。这是因为JavaScript在执行脚本前会创建一个Global对象,所有全局变量都是该Global对象的属性;而在执行函数时,会创建一个Activation对象,所有局部变量都是该Activation对象的属性。示例如下:


代码如下:

var global = 42;
this.global; // 42, 可以通过this来访问Global对象
this.global2 = 12;
global2; // 12
function foo() {
var local = 36;
// 不过无法直接访问Activation,
// 因此无法通过 foo.local 的方式来访问local变量
}

delete操作符删除的对象

delete操作符删除的对象


C++中也有delete操作符,它用于删除指针所指向的对象。例如:


代码如下:

// C++
class Object {
public:
Object *x;
} 
Object o;
o.x = new Object();
delete o.x; // 上一行new的Object对象将被释放

然而,JavaScript的delete与C++不同,它不会删除o.x指向的对象,而是删除o.x属性本身。


代码如下:

// Javascript
var o = {};
o.x = new Object();
delete o.x; // 上一行new的Object对象依然存在
o.x; // undefined,o的名为x的属性被删除了

在实际的JavaScript运行环境中,执行delete o.x后,由于Object对象失去了所有引用,它会被垃圾回收机制回收。因此,delete o.x在效果上“相当于”删除了o.x所指向的对象。但需要注意的是,这一动作并非ECMAScript标准强制要求,也就是说,即使某个实现完全不删除Object对象,也不违反ECMAScript标准。


“删除属性而不是删除对象”这一点,可以通过以下代码验证。


代码如下:

var o = {};
var a = { x: 10 };
o.a = a;
delete o.a; // o.a属性被删除
o.a; // undefined
a.x; // 10, 因为{ x: 10 } 对象依然被 a 引用,所以不会被回收

另外,delete o.x 也可以写作 delete o["x"],两者效果相同。


对变量执行delete的情况

对变量执行delete的情况


由于变量也是Global或者是Activation对象的属性,所以对变量的delete操作结果与对属性操作一致。


代码如下:

var global = 42;
delete global; // 删除Global.global
function foo() {
var local = 36;
delete local; // 删除Activation.local
}

能删除的属性和不能删除的属性

能删除的属性和不能删除的属性


并非所有属性都能被delete删除。例如,prototype中声明的属性就无法被删除:


代码如下:

function C() { this.x = 42; }
C.prototype.x = 12;
var o = new C();
o.x; // 42, 构造函数中定义的o.x
delete o.x;
o.x; // 12, prototype中定义的o.x,即使再次执行delete o.x也不会被删除

对象的预定义属性也无法删除。可以认为这类属性带有DontDelete的特性。


代码如下:

var re = /abc/i;
delete re.ignoreCase;
re.ignoreCase; // true, ignoreCase无法删除

能删除的变量和不能删除的变量

能删除的变量和不能删除的变量


通过var声明的变量和通过function声明的函数拥有DontDelete特性,无法被删除。


代码如下:

var x = 36;
delete x;
x; // 36, x没有被删除
y = 12;
delete y;
y; // undefined
function foo() { return 42; }
delete foo;
foo(); // 42

但是有一点例外,就是通过eval执行的代码中,通过var声明的变量虽然与正常的var声明变量同属于Global对象,但它们不具有DontDelete特性,能被删除。


代码如下:

eval("var x = 36;");
x; // 42
delete x;
x; // undefined

但是这也有一点例外,eval的代码中的函数内通过var定义的变量具有DontDelete,不能被删除。


代码如下:

eval("(function() { var x = 42; delete x; return x; })();");
// 返回 42

delete的返回值

delete的返回值


delete是普通运算符,会返回true或false。规则为:当被delete的对象的属性存在并且拥有DontDelete时返回false,否则返回true。这里的一个特点是,对象属性不存在时也返回true,所以返回值并非完全等同于删除成功与否。


代码如下:

function C() { this.x = 42; }
C.prototype.y = 12;
var o = new C();
delete o.x; // true
o.x; // undefined
"x" in o; // false
// o.x存在并且没有DontDelete,返回true
delete o.y; // true
o.y; // 12
// o自身没有o.y属性,所以返回true
// 从这里也可以看到prototype链的存在,对象自身属性和prototype属性是不同的
delete o; // false
// Global.o拥有DontDelete特性所以返回false
delete undefinedProperty; // true
// Global没有名为undefinedProperty的属性因此返回true
delete 42; // true
// 42不是属性所以返回true。有的实现会抛出异常(违反ECMAScript标准)
var x = 24;
delete x++; // true
x; // 25
// 被删除的是x++的返回值(24),不是属性,所以返回true
作者最新文章