本文深入解析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 运算符之概述,不妥之处,欢迎大家批评指正。