关于delete和对象复制
本码农的惯例,开篇废话几句...
前天小生又被虐了...
没办法,作为一个资深code user,我用代码的能力,解决问题的能力自问是不弱的...
但是自身的前端基础说实话还是不过硬,最明显的表现就是,对于JS核心的研究做得比较少。
另外就是概念方面很脆弱(PS:我的习惯是用通俗的比喻来理解技术,那些乏味的概念实在记不住几个)
现实依旧一如既往的残酷,许多平时用的很少的知识点经常被用作体现一个人能力水平的指标。
其实也是合理的,毕竟用的少就不去研究,这是说不过去的。
OK,废话完毕,开始正题。
关于 delete
下面会列出许多例子,如果你要用开发者工具来调试,在测试不同例子的时候麻烦刷新一下页面,否则可能会由于用了同样的变量而出现问题。
首先来个简单的例子(其实在此之前我在工作中完全没用过 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 (删除函数失败) //再试试这种写法,声明一个变量,并将一个匿名函数赋值给它
var y = function () {};
delete y; // false;
typeof y; // function (删除函数失败)
下面,让我来毁你的三观...
z = function () {};
delete z; // true
typeof z;// undefined (删除成功了...)
为什么这次能够删除了呢?假如都是在全局上下文下面执行,那他们就都是 window 对象的属性,为什么上面的例子又删除成功了呢?
原因是上面的例子,实际上相当于执行了下面的代码
window.z = function () {}; // 对属性赋值,而不是定义
delete z; // true
typeof z;// undefined (删除成功了...)
假如一个变量没有用 var 进行声明,那么 JS 会将该变量变成 window 对象的属性,然后对属性进行赋值。
由于这个过程对开发者而言是不可见的,因此称它为隐式属性赋值。当然你也可以显式的对window对象添加一个属性并对其赋值,结果是一样的。
这种显式/隐式赋值的属性,是可以用 delete 删除的。
上面的例子都是在全局环境下的,下面我们将战场转移到局部环境,匿名函数的内部。
(function () {
this.x = 1; // 显式属性赋值
var y = 2; // 声明一个局部变量
z = 3; // 隐式属性赋值,变成window对象的一个属性 delete this.x; // true
delete x; // false
delete z; // true console.info(this.x); // undefined (删除成功)
console.info(y); // 2 (删除失败)
console.info(window.z); // undefined (删除成功)
})()
可以看到,结果全局环境下是差不多的。
我们把环境转移到更残酷的战场 —— eval
//温馨提示,测试新一段代码前注意先刷新下页面
eval('function x(){}');
typeof x; // function
delete x; // true;
typeof x; // undefined (删除成功)
然后我又来毁你三观了...
//老规矩,测试新一段代码前注意先刷新下页面,后面就不再提示了...
var x = 1;
eval('function x(){}');
typeof x; // function
delete x; // false;
typeof x; // function(删除失败!)
为什么会这样?甚至你再看看这个例子
//在 eval 后面声明一个同名变量,也删除失败
eval('function x(){}');
var x = 1;
typeof x; // function
delete x; // false;
typeof x; // function(删除失败!)
首先,这里明确一点就是,eval 里的代码声明的变量或者函数,是可以用 delete 删除的。
eval 里的代码声明的变量或者函数,如果在外部已经被声明了(不单单是 eval 的上文,还包括 eval 的下文),则会对该变量重新进行赋值,因为 eval 里代码的调用,永远在其外部上下文中其他变量和函数声明之后。
这样一来,该变量就是已经存在的,而非执行 eval 传入的代码声明的了。
所以上面的例子之所以删除失败,不是因为 eval 里代码声明的变量删除不了,而是那个变量压根就不是 eval 里的代码声明的。
OK,最后来一份比浅层总结(之所以说是浅层总结,是因为其实还有一些情况这里是没列出的,但那太过深入了,如果你有兴趣可以研究,但如非必要,我觉得还是算了吧...记住那些东西实在是累人...)
1.显示/隐式的对象属性赋值,该属性都是可以通过 delete 删除的
2.通常情况下,代码中声明的变量和函数不能通过 delete 删除
3.通过 eval 函数传入代码声明的变量和函数可以通过 delete 删除,前提是在此之前,该变量不曾在外部上下文中被声明
最后,如果你想对delete作更深入的研究,想揪其原理,这里有一篇很好很专业的文章:http://justjavac.com/javascript/2013/04/04/understanding-delete-in-javascript.html
关于对象复制
由于对象是引用类型的,所以当我们响应克隆一个对象的时候,不能用常规的赋值来完成。
// 下面的代码,实际上只是让两个不同的变量引用了同一个对象
var a = {
name : 'Jack',
sex : 'male'
};
var b = a;
假如要将对象复制,正确的做法应该是这样
var a = {
name : 'Jack',
sex : 'male'
};
var b = {}; for (var key in a) {
b[key] = a[key];
}
但...这样就够了么?万一对象的某个属性是另一个对象,或者是一个数组呢?
这样一来,就涉及到对象的浅复制和深复制了。
上面的做法,只能实现对象的浅复制,对于深复制,我们要用下面的方法来完成。
// 声明一个对象克隆函数
function clone (obj) {
var result = {}; var _clone = function (objO, objC) {
for (var key in objO) {
var curProperty = objO[key]; if (curProperty.constructor == Array) {
// 属性的值为数组时...
objC[key] = [];
for (var i = 0, len = curProperty.length; i < len; i++) {
objC[key].push(curProperty[i]);
}
} else if (curProperty.constructor == Object) {
// 属性的值为对象时...
objC[key] = {};
_clone(curProperty, objC[key]);
} else {
// 其他情况...
objC[key] = objO[key];
} }
}; _clone(obj, result); return result;
} // 测试...
var a = {
name : 'Jack',
love : ['Lily', 'Kate', 'Lucy'],
fav : {
color : ['red', 'black'],
sport : 'football'
},
eat : function () {
alert('fuck you!')
}
}; var b = clone(a);
关于delete和对象复制的更多相关文章
- JS对象复制(深拷贝、浅拷贝)
如何在 JS 中复制对象 在本文中,我们将从浅拷贝(shallow copy)和深拷贝(deep copy)两个方面,介绍多种 JS 中复制对象的方法. 在开始之前,有一些基础知识值得一提:Javas ...
- c++中的对象复制
(1)this指针 this是一个隐含于每个类的成员函数的特殊指针,该指针是一个指向正在被某个成员函数操作的对象的指针. 当一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,也就是说,当 ...
- PHP基础知识之对象复制
对象的复制默认为浅复制 进行深复制的方法为:在类中定义魔法方法__clone(),类的对象复制时,会自动调用 __clone方法,在 __clone方法中可以进行各种复制对象的个性化 class My ...
- JS对象复制
在JavaScript很多人复制一个对象的时候都是直接用"=",因为大家都觉得脚本语言是没有指针.引用.地址之类的,所以直接用"="就可以把一个对象复制给另外一 ...
- PHP写时复制, 变量复制和对象复制不同!!!
2016年3月18日 15:09:28 星期五 一直以为PHP对象也是写时复制....... 其实: PHP的变量是写时复制, 对象是引用的 写时复制: $a = $b; 如果$b的内容不改变, $a ...
- 【转】JavaScript中的对象复制(Object Clone)
JavaScript中并没有直接提供对象复制(Object Clone)的方法.因此下面的代码中改变对象b的时候,也就改变了对象a. a = {k1:1, k2:2, k3:3}; b = a; b. ...
- 对象复制、克隆、深度clone
-------------------------------------------------------------------------------- ------------------- ...
- PHP5的对象复制
今天用yii开发程序,一个bug改了一晚上,最后发现问题出在了对象复制机制上,PHP5之前的对象复制只需要$object_a = $object_b即可,但PHP5这样得到的是浅复制,及指针指向,并不 ...
- Java反射 - 2(对象复制,父类域,内省)
为什么要复制对象?假设有个类Car,包含name,color2个属性,那么将car1对象复制给car2对象,只需要car2.setName(car1.getName)与car2.setColor(ca ...
随机推荐
- 重拾C语言基础知识
从实习到工作两年多的时间了,虽然感觉学到了很多知识,但是事实上却将立足之本的基础知识给忘了个精光.也许跟自己没有出去找工作有关,没有好好的将C语言的基础牢牢掌握. 从现在开始吧!好好的重温基础,做一名 ...
- 基数排序简单Java实现
基数排序(radix sort)又称“桶子法”,在对多个正整数进行排序时可以使用.它的灵感来自于队列(Queue),它最独特的地方在于利用了数字的有穷性(阿拉伯数字只有0到9的10个). 基数排序使用 ...
- [LeetCode 题解]: Symmetric Tree
前言 [LeetCode 题解]系列传送门: http://www.cnblogs.com/double-win/category/573499.html 1.题目描述 Given a ...
- MVC ViewData与ViewBag的区别
一.ViewData 1.ViewData派生自ViewDataDictionary,所以它具有字典的属性,例如:ContainsKey .Add .Remove 和 Clear : 2.字典键值是字 ...
- Visual Studio 2017 如何 监控当前变量 占用内存空间大小
在进行VS调试时 大家是否想知道当前变量 占用了内存多少空间呢 这对系统调优还是很有帮助的吧
- UWP开发入门(八)——聊天窗口和ItemTemplateSelector
我们平常用的最多的APP可能就是企鹅和微信了.有没有想过聊天窗口如何实现的?本篇我们将简单模拟一个聊天窗口. 聊天窗口大致上就是消息的一个集合列表.集合列表最常见的展现形式无非就是ListView.可 ...
- std::shared_ptr之deleter的巧妙应用
本文由作者邹启文授权网易云社区发布. std::shared_ptr 一次创建,多处共享,通过引用计数控制生命周期. 实例 在邮箱大师PC版中,我们在实现搜索时,大致思路是这样的: 每一个账号都有一个 ...
- docker的介绍以及常用命令
一.docker的介绍 1. Docker是什么? Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚 ...
- 【经典漏洞案例】NSA黑客工具包——Windows 0day验证实验
还记得今年4月中旬,Shadow Brokers(影子经纪人)黑客组织发布出一份震惊世界的机密文档,其中包含了多个Windows 远程漏洞利用工具,此工具集覆盖大量的Windows服务 器,可以被任何 ...
- Kali Linux安全渗透-从入门到精通
Kali-Linux是基于Debian Linux发行版 针对高级渗透测试和安全审计系统.带你一起从入门到精通. 什么是Kali-Linux? kali 包含几百个软件用来执行各种信息安全的任务,如渗 ...