Understanding delete

简述

        我们都知道无法通过delete关键字针对变量和函数进行操作,而对于显示的对象属性声明却可以进行,这个原因需要深究到js的实现层上去,让我们跟随 Understanding delete 来探究一番,另外本文并不考虑浏览器的兼容性实现问题。

理论

    为什么我们可以这样:

  var o = { x: 1 };
  delete o.x; // true
  o.x; // undefined

         却无法这样

var x = 1;
  delete x; // false
  x; // 1

其实,这要涉及到执行上下文的概念,而每个执行上下文都对应一个变量对象VO,在全局上下文中VO就是全局对象window,在函数上下文中,VO也是活动地向AO,而在eval中的代码在执行时,其执行上下文也就是调用eval的上下文。

         在上下文中定义的变量,函数声明以及函数的入参和AO特有的arguments对象等等,都属于VO(AO)的属性。而对于VO这样的实体对象而言,它也有自己的元数据,也就是在ES5中对象的数据特性:[[configurable]],[[enurable]],[[value]],[[writable]]。而对于VO的属性,默认的[[configurable]]是false,这样就无法针对这些变量使用delete操作。而对于显示的对象属性赋值,比如obj.name = “a”,对于name属性的[[configurable]]特性是true,因此可以删除。

var GLOBAL_OBJECT = this;

  /*  `foo` is a property of a Global object.
      It is created via variable declaration and so has DontDelete attribute.
      This is why it can not be deleted. */

  var foo = 1;
  delete foo; // false
  typeof foo; // "number"

  /*  `bar` is a property of a Global object.
      It is created via function declaration and so has DontDelete attribute.
      This is why it can not be deleted either. */

  function bar(){}
  delete bar; // false
  typeof bar; // "function"

  /*  `baz` is also a property of a Global object.
      However, it is created via property assignment and so has no DontDelete attribute.
      This is why it can be deleted. */

  GLOBAL_OBJECT.baz = 'blah';
  delete GLOBAL_OBJECT.baz; // true
  typeof GLOBAL_OBJECT.baz; // "undefined"

           另外,函数的length属性也是不可以删除的。

           而对于未初始化的变量赋值,我们知道未初始化的变量默认为全局变量,VO的属性确定是在进入上下文阶段,因此未初始化变量并不会成为VO的属性,[[configurable]]仍未true,可以删除。

/* `foo` is created as a property with DontDelete */
  function foo(){}

  /* Later assignments do not modify attributes. DontDelete is still there! */
  foo = 1;
  delete foo; // false
  typeof foo; // "number"

  /* But assigning to a property that doesn't exist,
     creates that property with empty attributes (and so without DontDelete) */

  this.bar = 1;
  delete bar; // true
  typeof bar; // "undefined"

            凡是都有例外,对于delete操作也难免。上述提到的第三种上下文--eval上下文,有个特殊的行为,就是在eval中声明的变量,函数可以在调用上下文中删除。

(function(){
    eval('var foo = 1;');
    foo; // 1
    delete foo; // true
    typeof foo; // "undefined"
    
    eval('var foo = 1;');
    foo; // 1
    delete foo; // true
    typeof foo; // "undefined"

  })();

ES5严格模式

         ES5的严格模式与上述提到的行为不同,它不准许delete删除函数入参,变量和函数,以及函数对象的length。删除未声明的 变量也会抛出语法错误SyntaxError。

(function(foo){

  "use strict"; // enable strict mode within this function

  var bar;
  function baz(){}

  delete foo; // SyntaxError (when deleting argument)
  delete bar; // SyntaxError (when deleting variable)
  delete baz; // SyntaxError (when deleting variable created with function declaration)

  /* `length` of function instances has { [[Configurable]] : false } */

  delete (function(){}).length; // TypeError

  delete i_dont_exist; // deleting undeclared variable (or in other words, unresolved Referece) throws SyntaxError
})();

总结

  •   需要知道有哪几种上下文,每个上下文对应一个VO
  •   上下文中定义的函数、变量、入参、arguments等都是VO的属性,[[configurable]]为false
  •   eval上下文的特殊性
  •   未声明变量并不是VO的属性,[[configurable]]为true
  •   删除宿主对象属性时需小心,可能有意外发生,取决于js引擎的具体实现

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大内老A

WCF技术剖析之十二:数据契约(Data Contract)和数据契约序列化器(DataContractSerializer)

大部分的系统都是以数据为中心的(Data Central),功能的实现表现在对相关数据的正确处理。而数据本身,是有效信息的载体,在不同的环境具有不同的表示。一个...

35980
来自专栏移动端开发

Swift Runtime ?

你肯定也想过       在OC中相信每一个iOS开发都知道Runtime, 现在Swift也更新到4.0版本了,要是你也学习过Swift的话你可能也会想过这样...

1.5K70
来自专栏漫漫深度学习路

pytorch学习笔记(十二):详解 Module 类

Module 是 pytorch 提供的一个基类,每次我们要 搭建 自己的神经网络的时候都要继承这个类,继承这个类会使得我们 搭建网络的过程变得异常简单。 本文...

52960
来自专栏程序员宝库

JDK 源码中的一些“小技巧”

均摘选自JDK源码 1 i++ vs i-- String源码的第985行,equals方法中: while (n--!= 0) { if...

35550
来自专栏mathor

2017百度之星资格赛

 题目大意是说,给你n个熊(那么他们编号默认就是1...n),然后给定m行输入,每一行都有u,v,w三个变量,表示u熊和v熊之间有强关系w,然后问你至少需...

8220
来自专栏Spark学习技巧

Flink DataSet编程指南-demo演示及注意事项

Flink中的DataStream程序是对数据流进行转换的常规程序(例如,过滤,更新状态,定义窗口,聚合)。数据流的最初的源可以从各种来源(例如,消息队列,套接...

4.5K120
来自专栏日常学python

一篇文章踩遍Python中的坑

这个问题是变量作用域问题,在gen=(x for _ in xrange(10))中gen是一个generator,在generator中变量有自己的一套作用域...

10120
来自专栏Golang语言社区

动手实现一个JSON验证器(上)

分析 既然要验证JSON的有效性,那么必然需要清楚的知道JSON格式,这个在JSON官网已经给我们画出来了: ? ? ? ? ? 从官方的图上面可以看出,JSO...

53270
来自专栏技术博文

Base64 的 JavaScript 实现 js-base64

base64.js 是 Base64 的 JavaScript 实现。 wiki上给的解释: https://en.wikipedia.org/wiki/Bas...

42040
来自专栏欧阳大哥的轮子

深入解构iOS的block闭包实现原理

在iOS4出来后,苹果公司在OC中推出了block机制(也许更早就有了)。并且在后续的版本中大量的推广和使用了这项技术,比如对视图动画API的改版,比如GCD技...

9830

扫码关注云+社区

领取腾讯云代金券