delete只对对象自有可配置属性有效,不能删除变量、函数声明或不可配置属性;赋值undefined不删除属性,而delete真正移除属性;数组中delete产生空槽,应使用splice等方法。
直接说结论:delete 只对对象的**自有可配置属性**有效。它不是“删除变量”的工具,也不能删 var、let、const 声明的绑定,也不能删函数声明(function foo() {})本身。
常见误解是以为 delete obj 类似于
.keyobj.key = undefined —— 实际上二者语义完全不同:delete 真正移除属性(从对象内部属性列表中剔除),而赋值 undefined 只是改值,属性依然存在、仍会被 for...in 遍历到。
delete 返回布尔值:true 表示删除成功(或目标本就不存在),false 表示失败(如属性不可配置)TypeError;非严格模式下静默失败(返回 false)var 声明的变量,其属性被自动设为不可配置,所以 delete window.xxx 一定失败对象属性是否可删,取决于它的 [[Configurable]] 内部特性。默认情况下:
Object.defineProperty(obj, 'key', { value: 1 }) 创建的属性,configurable 默认为 false → delete 失败obj.key = 1 或 obj['key'] = 1 创建的属性,configurable 默认为 true → delete 成功get/set)若未显式设 configurable: true,也删不掉const obj = {};
Object.defineProperty(obj, 'locked', { value: 42 });
console.log(delete obj.locked); // false(不可配置)
obj.normal = 'ok';
console.log(delete obj.normal); // true(可配置)
delete arr[2] 不会改变数组长度,也不会移动后续元素,而是把对应位置变成“空槽”(empty),该索引在 for...in 中仍会出现,但 arr[2] 访问返回 undefined,且 Array.isArray(arr) 仍为 true。
splice()、filter() 或 pop()/shift()
delete 后的数组用 forEach、map 会跳过空槽,但 for...in 仍会遍历到那个索引delete 会让 V8 引擎将数组退化为“字典模式”,后续操作变慢const arr = ['a', 'b', 'c', 'd']; delete arr[2]; console.log(arr); // ['a', 'b',, 'd'] console.log(arr.length); // 4(没变!) console.log('2' in arr); // false(但注意:这和 hasOwnProperty 不同)
Reflect.deleteProperty(obj, key) 是 delete 的函数式封装,行为完全一致,但它更适合作为高阶操作使用(比如配合 Proxy 或统一错误处理)。它不会在严格模式下抛异常,而是始终返回布尔值,便于逻辑判断。
delete 一样,只影响自有可配置属性Reflect.deleteProperty(obj, someKey) 比 delete obj[someKey] 在某些静态检查工具中更友好)delete 操作“函数化”,不是增强版const obj = { a: 1, b: 2 };
const key = 'a';
console.log(Reflect.deleteProperty(obj, key)); // true
console.log(obj); // { b: 2 }
真正容易被忽略的是:很多开发者在循环中边遍历边 delete 对象属性,却没意识到这不会影响当前遍历顺序(因为 for...in 遍历的是属性快照,不是实时结构),也不影响 Object.keys() 的结果(它只返回可枚举自有属性,且生成时已确定)。要安全地批量删属性,先收集键名再统一删,比边遍历边删更可靠。