JS 中 delete 關鍵詞的使用解析

在 JavaScript 中,delete是專門用於刪除對象屬性或數組元素的一元運算符,核心作用是移除對象上的指定屬性(包括繼承的屬性,但若屬性為不可配置則刪除失敗),或刪除數組指定索引的元素(不會改變數組長度,僅將對應位置置為undefined)。它的返回值是布爾值:刪除成功(或屬性不存在)返回true,刪除失敗(如不可配置屬性)返回false(嚴格模式下會報錯)。掌握delete的使用規則,是管理對象和數組數據、避免內存冗餘的重要技能。

一、delete 的基礎用法

1. 刪除對象屬性

delete最核心的應用場景是刪除普通對象的自有屬性,語法為delete object.property或delete object['property'],兩種寫法效果一致。

// 定義普通對象
const user = {
  name: "張三",
  age: 28,
  gender: "男"
};

// 刪除對象屬性(點語法)
console.log(delete user.age); // 輸出:true(刪除成功)
console.log(user.age); // 輸出:undefined(屬性已不存在)

// 刪除對象屬性(方括號語法,適合特殊命名屬性)
const obj = { "user-name": "李四", 123: "數字屬性" };
console.log(delete obj["user-name"]); // 輸出:true
console.log(delete obj[123]); // 輸出:true

// 刪除不存在的屬性(返回true,無報錯)
console.log(delete user.address); // 輸出:true
2. 刪除數組元素

刪除數組元素時,delete不會改變數組長度,僅將目標索引位置的元素置為undefined,數組的其他元素索引保持不變。

const arr = [10, 20, 30, 40];

// 刪除數組索引為1的元素
console.log(delete arr[1]); // 輸出:true
console.log(arr); // 輸出:[10, empty, 30, 40](empty等價於undefined)
console.log(arr.length); // 輸出:4(數組長度未變)
console.log(arr[1]); // 輸出:undefined

// 對比數組splice方法(真正移除元素,改變長度)
arr.splice(1, 1);
console.log(arr); // 輸出:[10, 30, 40]
console.log(arr.length); // 輸出:3

二、delete 的核心規則與邊界情況

1. 不可刪除的屬性類型

delete並非能刪除所有屬性,以下類型的屬性刪除會失敗:

  • Object.defineProperty 定義的不可配置(configurable: false)屬性

  • 內置對象的內置屬性(如Math.PI、Array.prototype.length);

  • 變量聲明(var/let/const)和函數聲明(delete無法刪除作用域中的變量 / 函數);

  • 原型鏈上的屬性(僅能刪除對象自身的屬性,原型屬性需直接操作原型對象)。

// 1. 不可配置屬性刪除失敗
const obj = {};
Object.defineProperty(obj, "id", {
  value: 1001,
  configurable: false // 不可配置
});
console.log(delete obj.id); // 輸出:false(刪除失敗)
console.log(obj.id); // 輸出:1001

// 2. 內置屬性刪除失敗
console.log(delete Math.PI); // 輸出:false
console.log(delete Array.prototype.length); // 輸出:false

// 3. 變量/函數無法被delete刪除
var num = 10;
let str = "hello";
const bool = true;
function func() {}

console.log(delete num); // 輸出:false(var聲明的變量掛載在window,不可配置)
console.log(delete str); // 輸出:false(let/const聲明的變量不可配置)
console.log(delete bool); // 輸出:false
console.log(delete func); // 輸出:false

// 4. 原型屬性需操作原型對象才能刪除
function Person() {}
Person.prototype.name = "原型屬性";
const p = new Person();

console.log(delete p.name); // 輸出:true(但僅刪除p自身的name,原型的name仍存在)
console.log(p.name); // 輸出:"原型屬性"(讀取原型鏈的name)
console.log(delete Person.prototype.name); // 輸出:true(刪除原型上的屬性)
console.log(p.name); // 輸出:undefined
2. 嚴格模式下的 delete 行為

嚴格模式('use strict')會強化delete的錯誤處理:刪除不可配置屬性、變量、函數參數等時,不再返回false,而是直接拋出語法錯誤。

"use strict";

const obj = {};
Object.defineProperty(obj, "age", { value: 20, configurable: false });

// 嚴格模式下刪除不可配置屬性,報錯
delete obj.age; // 報錯:Uncaught TypeError: Cannot delete property 'age' of #<Object>

// 嚴格模式下刪除變量,報錯
let name = "張三";
delete name; // 報錯:Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
3. 刪除對象的繼承屬性

若對象自身不存在某屬性,但原型鏈上存在,delete會返回true(因為 “刪除不存在的屬性” 視為成功),但不會影響原型鏈上的屬性。

const parent = { hobby: "跑步" };
const child = Object.create(parent); // child繼承parent的hobby

console.log(child.hobby); // 輸出:"跑步"(讀取原型屬性)
console.log(delete child.hobby); // 輸出:true(child自身無hobby,刪除“不存在的屬性”)
console.log(child.hobby); // 輸出:"跑步"(原型的hobby仍存在)

三、delete 的實際應用場景

1. 清理對象冗餘屬性

在處理接口返回數據、表單提交數據時,常需要刪除對象中不需要的屬性,減少數據傳輸體積。

// 模擬接口返回的用户數據(包含冗餘字段)
const rawUser = {
  id: 1001,
  name: "李四",
  password: "123456", // 敏感字段,需刪除
  createTime: "2024-01-01",
  updateTime: "2024-01-02" // 冗餘字段,需刪除
};

// 清理冗餘/敏感屬性
delete rawUser.password;
delete rawUser.updateTime;

console.log(rawUser);
// 輸出:{ id: 1001, name: "李四", createTime: "2024-01-01" }
2. 動態控制對象屬性存在性

結合delete和條件判斷,可動態添加 / 刪除對象屬性,適配不同業務場景。

const config = {
  enableLog: true,
  timeout: 5000,
  retry: 3
};

// 非生產環境刪除日誌配置
const isProd = false;
if (!isProd) {
  delete config.enableLog;
}

// 超時時間小於1000時,刪除重試配置
if (config.timeout < 1000) {
  delete config.retry;
}

console.log(config);
// 輸出:{ timeout: 5000, retry: 3 }(enableLog已刪除)
3. 清空對象(批量刪除屬性)

通過遍歷對象屬性,結合delete可清空對象所有自有屬性(保留對象引用)。

function emptyObject(obj) {
  // 遍歷對象所有自有屬性
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      delete obj[key];
    }
  }
}

const data = { a: 1, b: 2, c: 3 };
emptyObject(data);
console.log(data); // 輸出:{}(對象為空,引用不變)
console.log(data === {}); // 輸出:false(仍為原對象引用)

四、delete 的替代方案與性能考量

1. 替代方案
  • 數組元素移除:若需真正移除數組元素並調整長度,優先使用Array.prototype.splice(),而非delete;

  • 對象屬性置空:若僅需清空屬性值(保留屬性存在性),可直接賦值undefined,比delete更高效;

  • 創建新對象過濾屬性:在 React、Vue 等框架中,為避免直接修改原對象,可通過解構賦值創建新對象,過濾不需要的屬性。

// 1. 數組移除元素:splice替代delete
const arr = [1,2,3,4];
arr.splice(2, 1); // 從索引2開始刪除1個元素
console.log(arr); // 輸出:[1,2,4]

// 2. 屬性置空替代delete(保留屬性)
const obj = { name: "張三" };
obj.name = undefined;
console.log(obj.name); // 輸出:undefined
console.log("name" in obj); // 輸出:true(屬性仍存在)

// 3. 解構賦值創建新對象(過濾屬性)
const rawData = { id: 1, name: "李四", password: "123" };
const { password, ...cleanData } = rawData;
console.log(cleanData); // 輸出:{ id: 1, name: "李四" }
2. 性能考量

delete會改變對象的內部結構(導致 V8 引擎的隱藏類重排),頻繁使用會降低代碼執行效率。在高性能場景(如循環處理大量對象),優先選擇:

  • 用undefined賦值替代delete(保留屬性);

  • 創建新對象過濾屬性(避免修改原對象);

  • 使用Map/Set替代普通對象(增刪操作更高效)。

五、delete 與 in 運算符的配合使用

in運算符用於檢測對象是否包含指定屬性(包括繼承屬性),常與delete配合,判斷屬性是否真正被刪除。

const obj = { a: 1, b: 2 };

console.log("a" in obj); // 輸出:true
delete obj.a;
console.log("a" in obj); // 輸出:false(屬性已刪除)

// 原型屬性的檢測
const parent = { c: 3 };
const child = Object.create(parent);
console.log("c" in child); // 輸出:true(繼承屬性)
delete child.c;
console.log("c" in child); // 輸出:true(原型屬性仍存在)
delete parent.c;
console.log("c" in child); // 輸出:false(原型屬性已刪除)

delete作為對象屬性管理的核心運算符,雖然用法簡單,但需重點關注不可配置屬性、嚴格模式、原型鏈屬性等邊界情況。在實際開發中,根據場景選擇 “刪除屬性”“置空屬性” 或 “創建新對象”,既能保證代碼邏輯正確,又能兼顧執行效率。