JavaScript delete运算符详解:原理、限制与最佳实践

作者:小括号时间:2026-10-29 16:51:26浏览:632

本文深入解析JavaScript中delete运算符的工作原理。重点阐述变量与函数声明生成的属性因拥有内部属性DontDelete而不可删除,而通过赋值创建的全局属性则可被删除。文章对比了delete与置为null的区别,并说明了严格模式下的行为差异,帮助开发者正确使用该操作符。

delete运算符的基本行为与限制

为何可以移除对象属性:


var x = { a: 1 };
delete x.a; // true
x.a; // undefined

却无法移除变量:


var x = 1;
delete x; // false;
x; // 1

亦无法移除函数:


function x() {};
delete x; // false;
typeof x; // "function"

注意:仅当属性不可删除时,delete 返回 false。

内部属性DontDelete机制解析

每个属性具备零至多个内部属性——如 *ReadOnly、DontEnum、DontDelete 及 Internal**。 可视其为标签——属性可能拥有或不含特定内部属性。 当前讨论聚焦于 DontDelete。

声明变量与函数时,它们成为变量对象(Variable object)——即活化对象(函数代码中)或全局对象(全局代码中)——的属性,并伴随生成内部属性 DontDelete。 然而,显式或隐式赋值的属性不生成 DontDelete。 此即为何部分属性可删而部分不可删的本质原因。


var GLOBAL_OBJECT = this;

/* 'foo' 为全局对象属性,由变量声明生成,故拥有内部属性 DontDelete

因此它不可被删除*/


var foo = 1;
delete foo; // false
typeof foo; // "number"
/* 'bar

' 为全局对象属性,由变量声明生成,故拥有 DontDelete 子

因此它同样不可被删除*/


function bar() {};
delete bar; // false
typeof bar; // "function"

/* 'baz' 亦为全局对象属性,

然而,它由属性赋值生成,故无 DontDelete

因此它可被删除*/


GLOBAL_OBJECT.baz = "baz";
delete GLOBAL_OBJECT.baz; // true
typeof GLOBAL_OBJECT.baz; // "undefined"

内建对象与函数参数的不可删除性

1.5、内建与 DontDelete | Build-ins and DontDelete

此即所有现象成因:属性之特殊内部属性控制其是否可删。 注意:内建对象部分属性拥有内部属性 DontDelete,故不可删; 特殊 arguments 变量(如活化对象属性)拥有 DontDelete; 任何函数实例的 length(返回形参长度)属性亦拥有 DontDelete:


(function() {
  //不能删除'arguments',因为有DontDelete
  delete arguments; // false;
  typeof arguments; // "object"

  //也不能删除函数的length,因为有DontDelete
  function f() {};
  delete f.length; // false;
  typeof f.length; // "number"
}) ();

与函数 arguments 关联之属性亦拥有 DontDelete,同样不可删


(function(foo,bar) {
  delete foo; // false
  foo; // 1

  delete bar; // false
  bar; // "bah"
}) (1,"bah");

未声明变量赋值与全局对象属性

1.6、未声明变量赋值 | Undeclared assignments

你可能记得,未声明变量赋值将成为全局对象属性,除非该属性在作用域链其他位置已被找到。 现知属性赋值与变量声明之别——后者生成 DontDelete 而前者不生成——此即未声明变量赋值可删之因。


var GLOBAL_OBJECT = this;

/* 通过变量声明生成全局对象的属性,拥有DontDelete */
var foo = 1;

/* 通过未声明的变量赋值生成全局对象的属性,没有DontDelete */
bar = 2;
delete foo; // false
delete bar; // true

注意:内部属性于属性生成时确定,后续赋值过程不改变已有属性之内部属性。 理解此区别至关重要。


/* 'foo'创建的同时生成DontDelete */
function foo() {};
/* 之后的赋值过程不改变已有属性的内部属性,DontDelete仍然存在 */
foo = 1;
delete foo; // false;
typeof foo; // "number"
/* 但赋值一个不存在的属性时,创建了一个没有内部属性的属性,因此没有DontDelete */
this.bar = 1;
delete bar; // true;
typeof bar; // "undefined"

核心规则总结

总结:

变量与函数声明均为活化(Activation)全局(Global)对象之属性。

属性拥有内部属性,其中——DontDelete 负责判定属性是否可删。

全局代码或函数代码中变量、函数声明均生成拥有 DontDelete 之属性。

函数参数同为活化对象属性,亦拥有 DontDelete。

删除对象属性:delete 对象.成员

仅能删除自有成员

唯 var 声明之全局变量不让 delete

使用 window. 或 window[""] 增加之全局成员可 delete

delete运算符的实际应用与注意事项

ps:Javascript 中 delete 运算符

Delete 是 Javascript 语言中使用频率较低操作之一,然有时需执行 delete 或清空动作时,便需此操作。 本文深入探讨其用法及工作原理。

删除目的,如你所想,即移除某物,具体而言,它删除对象属性,如下例:


var Benjamin = {
  "name": "zuojj",
  "url" : "http://www.zuojj.com"
};
delete Benjamin.name;
//Outputs: Object { url: "http://www.zuojj.com" }
console.log(Benjamin);

delete 运算符不会删除普通变量,如下例:


var benjamin = "http://www.zuojj.com";
delete benjamin;
//Outputs: "http://www.zuojj.com"
console.log(benjamin);

但,它可以删除“全局变量”,因它们实为全局对象(浏览器中为 window)对象之属性。


// Because var isn't used, this is a property of window
benjamin = "zuojj";
delete window.benjamin;
// ReferenceError: benjamin is not defined
console.log(benjamin);

delete 运算符亦有返回值,若删除属性成功,返回 true;若不能删除属性,因该属性不可写,将返回 false;或在严格模式下抛出错误。


var benjamin = {
  "name": "zuojj",
  "url" : "http://www.zuojj.com"
};
var nameDeleted = delete benjamin.name;
// Outputs: true
console.log(nameDeleted);
"use strict";
var benjamin_ = "zuojj";
//Outputs: Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
delete benjamin_;

你可能不知何时使用删除运算符。 答案是,只要你确需从对象中移除属性。

有时,Javascript 开发并非删除属性,而是将该属性值设为 null。 像下面这样:


var benjamin = {
  "name": "zuojj",
  "url" : "http://www.zuojj.com"
};
benjamin.name = null;

虽此有效切断原值之属性关联,但该属性本身仍存于对象上,你可看到如下:


// Outputs: Object { name: null, url: "http://www.zuojj.com" }
console.log(benjamin);

同时,in 和 for in 循环运算不会报告 null 属性之存在,若使用对象,可能用这些方法检查对象,你可能想确保真正删除任何不需属性。

最后,你应该记住,删除并未破坏属性之值,仅删除属性本身,看下面例子:


var name   = "zuojj",
    benjamin = {};
benjamin.name = name;
delete benjamin.name;
//Outputs: "zuojj"
console.log(name);

此处,name 和 benjamin.name 映射至相同值,正如你所见,删除 benjamin.name 并不影响 name。

以上,即我对 delete 运算符之概述,不妥之处,欢迎大家批评指正。

作者最新文章