解析JavaScript中delete操作符不能删除的对象

作者:小括号时间:2026-10-28 06:17:00浏览:337

本文深入解析JavaScript中delete操作符无法删除特定对象的原因。从ES3的DontDelete特性到ES5的[[Configurable]]属性,详细列举了arguments、var声明变量、函数声明、内置构造器原型等不可删除的情况,并探讨了严格模式下的异常处理及原型链继承对delete行为的影响。

ES3中DontDelete特性与不可删除对象

在ES3规范中,关于delete操作符的定义出现在8.6.2.5及11.4.1章节,具体内容如下

ES3中DontDelete特性与不可删除对象

ES3中DontDelete特性与不可删除对象

存在一些关键信息

1、从实现层面看,delete操作符会调用引擎内部的[[Delete]]方法

2、[[Delete]]方法在8.6.2章节中进行定义

ES3中DontDelete特性与不可删除对象

3、如果待删除的属性具有DontDelete特性,delete操作将直接返回false

搜索“DontDelete”关键字,会发现大量具有该特性的属性无法被删除,例如以下情况

1、激活对象中的arguments对象 (10.1.6)

代码如下:

function func() {
delete arguments;
alert(arguments);
} 
func(1);

2、变量声明 (10.2.1)


代码如下:

var a = 10;
delete a;
alert(a); // 10

这一点在许多JavaScript书籍中均有提及,即无法通过delete删除使用var声明的变量。

3、函数声明

代码如下:

function func() {}
delete func;
alert(func); // func code

4、函数的length属性


代码如下:

function func(a, b) {}
delete func.length;
alert(func.length); // 2

5、部分常量(NaN、Infinity、undefined)


代码如下:

delete NaN; // false
delete Infinity; // false
delete undefined; // false

6、内置构造器的prototype属性


代码如下:

delete Object.prototype; // false
delete Function.prototype; // false
delete Array.prototype; // false
delete ExpReg.prototype; // false
delete Date.prototype; // false
delete Error.prototype; // false
delete Number.prototype; // false
delete Boolean.prototype; // false
delete String.prototype; // false

7、数组和字符串的length属性


代码如下:

var arr = [], str = 'hello';
delete arr.length; // false
delete str.length; // false

8、Math对象的属性(Math.E、Math.LN10、Math.LN2、Math.LOG2E、Math.LOG10E、Math.PI、Math.SQRT1_2、Math.SQRT2)


代码如下:

delete Math.E; // false
... 

9、正则对象的属性(source、global、ignoreCase、multiline、lastIndex)


代码如下:

var reg = /ss/;
delete reg.source; // false
... 

ES5中[[Configurable]]属性与严格模式

ES5与ES3存在差异,ES5中不再使用“DontDelete”这一概念,转而引入[[Configurable]]属性(8.6.1)。

ES3中DontDelete特性与不可删除对象

如果该属性的[[Configurable]]值为false,则无法执行delete操作,上述列举的9种情况在ES5中均被描述为[[Configurable]]为false。

ES5新增的Object.defineProperty方法允许显式定义对象的Configurable属性,示例如下

代码如下:

var obj = {name: 'John'};
Object.defineProperty(obj, "key", {
configurable: false,
value: "static"
}); 
delete obj.name; // true
delete obj.key // false

对象obj包含name和key两个属性。name属性可以被delete删除,而key属性由于被显式设置为不可配置,因此无法删除。

此外,在ES5严格模式下,尝试delete Configurable为false的对象属性会直接抛出异常。例如

代码如下:

"use strict";
delete Object.prototype;

在Firefox浏览器控制台中会报错如下

ES3中DontDelete特性与不可删除对象

原型链继承对delete操作的影响

除了内置对象的部分方法或属性不可删除外,自定义对象中也存在无法删除的情况。例如,delete操作无法删除从原型链继承的属性

代码如下:

function Person() {}
Person.prototype.name = 'John Backus';
var p = new Person();
delete p.name;
console.log(p.name); // 仍然输出 John Backus

如果实例对象this和原型prototype上同时存在name属性,执行delete后,实例上的属性被移除,原型上的属性便会显现出来


代码如下:

function Person() {
this.name = 'John Backus';
} 
Person.prototype.name = 'John Resig';
var p = new Person();
console.log(p.name); // John Backus
delete p.name;
console.log(p.name); // John Resig, 来自原型

如果确实需要删除原型上的name属性,只能采取以下方法


代码如下:

delete Person.prototype.name

总结如下:

总结:delete操作的限制与原因

1、内置对象的属性及方法大多数无法通过delete删除(尽管部分方法如isNaN、parseInt可以删除)

2、对象从原型继承的属性和方法无法通过delete删除

其原因相对简单

1、内置对象的属性及方法大多数不可删除,这是为了保护语言的核心API。如果这些核心API被删除,JavaScript引擎将基本失效。例如delete Object.prototype会导致严重后果。

2、对象从原型继承的属性和方法不可删除,这是为了保护原型链的完整性。否则,“如果类A的对象删除了原型上的属性,那么所有继承自A的实例都将丢失该属性”,这将导致不可预知的错误。

作者最新文章