最近又双叒决定重学 JavaScript,在看周爱民老师的专栏,借此机会记一些笔记。
我们都知道在 JavaScript 中存在一个操作符 delete,根据 MDN 中的定义,我们可以知道:
- delete 删除的是对象中的某个属性
const obj = { foo: "bar" }
delete obj.foo
console.log(obj.foo) // undefined
但是实际上,我们发现,删除值这个操作也是合法的
delete 0
如果你仔细想一想,你会发现这是不可能的事情。如果删除的是一个值,那么 0 真的无法使用了吗?显然并不是的。
那么 delete 到底在删除什么?
想要知道这个问题,我们还是需要去看看 ECMAScript 规范:
ECMAScript 规范:
关于 delete 的运行时语义(计算规则):
// delete + 一元表达式
delete UnaryExpression
-
让
ref成为计算 UnaryExpression 的结果 -
ReturnIfAbrupt(ref)
-
如果
ref不是一个引用记录(Reference Record),返回true -
如果 IsUnresolvableReference(ref) 返回
true,那么a. 如果
[[Strict]]是 falseb. 那么返回
true -
如果 isPropertyReference(ref) 返回
true,那么a. 如果 IsPrivateReference(ref) 返回
falseb. 如果 IsSuperReference(ref) 返回
true,抛出一个Reference Error异常c. 让
baseObj是ToObject(ref.[[Base]])的结果d. 让
deleteStatus是baseObj.[[Delete]](ref.[[ReferencedName]])的结果e. 如果
deleteStatus是false,而且ref.[[Strict]]是 true,那么抛出一个TypeError异常f. 返回
deleteStatus -
如果 isPropertyReference(ref) 返回
false:a. 让
base是ref.[[Base]]b. 断言
base是否是环境记录(Environment Record)c. 返回
base.DeleteBinding(ref.[[ReferenceName]])的结果
注意 1: 如果
delete是在严格模式下执行的,尾随的一元表达式如果是变量、函数参数、或者函数名的直接引用,那么会抛出一个SyntaxError异常如果
delete是在严格模式下执行的,如果删除的属性被配置为{ [[Configurable]]: false }(或者其他不能删除的情况),那么会抛出一个TypeError异常
关于规范的解释
乍一看,规范其实是非常复杂的,没关系,我们只需要看精华即可:
真正会出现操作的只有两个地方:
baseObj.[[Delete]](ref.[[ReferencedName]])base.DeleteBinding(ref.[[ReferenceName]])
其他的部分,则都是根据不同的情况单纯的返回删除状态而已。
-
第一种操作是删除某个对象中的属性
-
第二种操作是在某个作用域中删除某个引用
得出结论
delete 操作符删除的不是一个值,而是一个表达式的结果
- 如果表达式是一个值,那么直接返回
true例如:delete 0 - 只有删除一个属性时 delete 操作符才会存在实际意义。
delete obj.xdelete x:x 是全局对象的属性with语句中的delete x
有意思的特殊情况
1. 删除 null 和删除 undefined 的区别
delete null // true
delete undefined // false
我们知道,返回值是 deleteStatus,null 可以理解,它是一个值,但是为什么 undefined 是 false 呢?
结果就是,由于历史原因,undefined 是全局对象的一个属性!
// undefined
Object.getOwnPropertyDescriptor(window, null)
// { value: undefined, writable: false, enumerable: false, configurable: false }
Object.getOwnPropertyDescriptor(window, undefined)
由于 undefined 设置了 configureable 为 false,那么根据规范无法删除,就会返回 false
不过根据上文,在严格模式下,删除 undefined 会报错(note 1.2)
2. 删除一个不存在的属性
delete is_not_exist // true
实际上,这个不存在属性会触发规范 4,即 IsUnsolvableReference,所以不会抛出异常,还是会返回 true
不过根据上文,在严格模式下,删除一个不存在的属性会报错(4.a)。