Appearance
MDN中对delete 操作符'解释'是:用于删除对象的某个属性,'语法'为'delete expression',其中'expression' 表示的是某个属性的引用
实际操作中首先delete 会调用引擎内部的[[Delete]]
方法 (PropertyName) 他主要做的是:从对象中移除指定的属性
删除后对于所有情况都是true,除非属性是一个自己不可配置的属性,在这种情况下,非严格模式返回 false。简单的说就是删除成功返回true 失败false 但也有区别在'异常'在严格模式下,如果是属性是一个自己不可配置的属性,会抛出'Global_objects/SyntaxError'。简单的说:会抛出一个语法错误( SyntaxError)而不是返回false。更多细节上规则
- 删除不存在的属性,delete 虽然不起任何作用但是返回的是true
js
var test = {
age:10,
name:'wang'
}
console.log(delete test.age) // true
console.log(delete test.sex) // 删除一个不存在的属性返回的true
console.log(test) // {name: "wang"}
- delete操作只会在自身的属性上起作用,即当前对象的原型上和当前对象有相同属性名,删除属性之后会使用原型对象上的属性
js
var Test = function () {
this.name = 'wang'
this.age = '10'
}
Test.prototype.age = '20'
Test.prototype.sex = '男'
var test = new Test()
console.log(test.age) // 10
console.log(delete test.age) // true
console.log(delete test.sex) // true
console.log(test.age) // 20
console.log(test.sex) // 男
// 再次删除也不能删除指向原型链的
console.log(delete test.age) // true
console.log(test.age) // 20
// 从原型上删除属性
delete Test.prototype.sex
- 不能删除var 变量声明的属性不能从全局作用域或者函数中删除,简单的说var let或const声明的属性不能够从它被声明的作用域中删除 ,在对象(object)中的函数是能够用delete操作删除的
js
// 在全局作用域创建 adminName 属性
adminName = 'xyz';
// 在全局作用域创建 empCount 属性
// 因为我们使用了 var,它会标记为不可配置。同样 let 或 const 也是不可配置的。
var empCount = 43;
// adminName 是全局作用域的一个属性。
// 因为它不是用 var 创建的,所在可以删除。
// 因此,它是可配置的。
delete adminName; // 返回 true
// 相反,empCount 是不可配置的,
// 因为创建它时使用了 var。
delete empCount; // 返回 false
// -------------- 函数 -----------
function func() {}
console.log(delete func) // false
console.log((func))
- 不可设置的(Non-configurable)属性不能被移除。这意味着像Math, Array, Object内置对象的属性以及使用Object.defineProperty()方法设置为不可设置的属性不能被删除。
js
console.log(delete Object.prototype) // false
console.log(delete Math.E) // false
// Object.defineProperty()方法设置为不可设置的属性不能被删除
var obj = {name: 'John'};
Object.defineProperty(obj, "key", {
configurable: false,
value: "static"
});
delete obj.name; // true
delete obj.key // false
进一步深究
ECMAScript中有3种类型的可执行代码:'Global code', 'Function code','Eval code'。这些类型在某种程度上是自我描述的,但这里有一个简短的概述:
- 当源文本被视为程序时,它将在全局范围内执行,并被视为'Global code'。在浏览器环境中,SCRIPT元素的内容通常被解析为程序,因此被评估为'Global code'。
- 直接在函数中执行的任何操作都被视为'Function code'。在浏览器中,
<p onclick="...">
通常将事件属性的内容(例如)解析为'Function code'。 - 将提供给内置eval函数的文本解析为'Eval code'。
对象属性的描述符都会具有下面说的的属性中0个或多个属性组成分别是是:'ReadOnly' ,'DontEnum','DontDelete','Internal' 依次为'只读','不可枚举','不可删除','内部' 可以通过
Object.getOwnPropertyDescriptor()
查看具体Variables and function声明是Activation或Global objects的属性(他们是具有DontDelete)
属性中的'DontDelete'负责是否可以删除一个属性。当然也有mdn中说到的Object.defineProperty()方法设置为不可设置的属性
Eval代码中的变量和函数声明总是在不使用DontDelete的情况下创建属性。因此他们是可以删除的
为什么隐式变量可以删除/var全局变量不可以
js
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 = 'blah';
delete GLOBAL_OBJECT.baz; // true
typeof GLOBAL_OBJECT.baz; // "undefined"
\* create global property via undeclared assignment; property has no DontDelete \*
bar = 2;
delete bar; // true
typeof bar; // "undefined"
具有'DontDelete' 属性一些特殊内置对象属性
下面的案例解释了为什么特殊的内置对象的属性不能被移除
js
(function(){
/* 不能删除 `arguments`, 因为它有 DontDelete属性 */
delete arguments; // false
typeof arguments; // "object"
/* 不能删除 function's `length`; 因为它有 DontDelete属性 */
function f(){}
delete f.length; // false
typeof f.length; // "number"
})();
函数的形参也是不可以删除的
js
(function(foo, bar){
delete foo; // false
foo; // 1
delete bar; // false
bar; // 'blah'
})(1, 'blah');
在属性创建期间确定属性的(即未设置任何属性)。以后的分配不会修改现有属性的属性
js
/* foo 是用DontDelete创建的属性 */
function foo(){}
/* 以后的赋值不会修改属性,所以删除不掉即使foo 看起来是一个隐式全局变量 */
foo = 1;
delete foo; // false
typeof foo; // "number"
/* 但是给一个不存在的属性赋值,
使用空属性创建该属性(因此不使用DontDelete) */
this.bar = 1;
delete bar; // true
typeof bar; // "undefined"