(JS three)闭包,浅拷贝,深拷贝

 **

闭包

**
(1) 什么是闭包:
闭包是指有权访问另外一个函数作用域中的变量的函数。
闭包就是函数的局部变量集合, 只是这些局部变量在函数返回后会继续存在。闭包就是 就是函数的 “堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈 上分配而是在堆上分配 。 当在一个函数内定义另外一个函数就会产生闭包。
(2) 为什么要用:
匿名自执行函数: 我们知道所有的变量, 如果不加上 var 关键字, 则默认的会添加到全 局对象的属性上去, 这样的临时变量加入全局对象有很多坏处, 比如: 别的函数可能误 用这些变量; 造成全局对象过于庞大, 影响访问速度(因为变量的取值是需要从原型链 上遍历的)。除了每次使用变量都是用var 关键字外, 我们在实际情况下经常遇到这样一 种情况, 即有的函数只需要执行一次, 其内部变量无需维护, 可以用闭包。
结果缓存: 我们开发中会碰到很多情况, 设想我们有一个处理过程很耗时的函数对象, 每次调用都会花费很长时间, 那么我们就需要将计算出来的值存储起来, 当调用这个函 数的时候, 首先在缓存中查找, 如果找不到, 则进行计算, 然后更新缓存并返回值, 如 果找到了, 直接返回查找到的值即可。 闭包正是可以做到这一点, 因为它不会释放外部 的引用, 从而函数内部的值可以得以保留。
使⽤闭包主要是为了设计私有的⽅法和变量。 闭包的优点是可以避免全局变量的污染, 缺
点是闭包会常驻内存, 会增⼤内存使⽤量, 使⽤不当很容易造成内存泄露。 在js中, 函数即 闭包, 只有函数才会产⽣作⽤域的概念
闭包 的最⼤⽤处有两个,⼀个是可以读取函数内部的变量, 另⼀个就是让这些变量始终保
持在内存中
闭包的另⼀个⽤处, 是封装对象的私有属性和私有⽅法
好处: 能够实现封装和缓存等;
坏处: 就是消耗内存、 不正当使⽤会造成内存溢出的问题

使⽤闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中, 内存消耗很⼤, 所以不能滥⽤闭包, 否
则会造成⽹⻚的性能问题, 在IE中可能导致内存泄露
解决⽅法是, 在退出函数之前, 将不使⽤的局部变量全部删除

   function fn(){
	var num = 1;
	return function(){
		var n = 0;
		console.log(++n);
		console.log(++num);
	}
}
var fn1 =fn()
fn1()
fn1()

一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这时候相当于fn1=function(){var n = 0 … },并且匿名函数内部引用着fn里的变量num,所以变量num无法被销毁,而变量n是每次被调用时新创建的,所以每次fn1执行完后它就把属于自己的变量连同自己一起销毁,于是乎最后就剩下孤零零的num,于是这里就产生了内存消耗的问题

在 JavaScript 中,  每当创建一个函数,闭包就会在函数创建的同时被创建出来。

js 中深拷贝和浅拷贝的区别?
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原 对象。
深拷贝的方法: 1 、递归拷贝
2 、使用 Object.create()方法
3 、jquery 有提供一个$.extend 也可以实现
4 、函数库 lodash ,也有提供 cloneDeep 用来实现
数组的浅拷贝:
如果是数组, 我们可以利用数组的一些方法, 比如slice, concat 方法返回一个新数组的 特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用concat 方法克隆并不完整, 如果数组元素是基本类型, 就会拷贝一份, 互不影响, 而如果是对象或数组, 就会只拷 贝对象和数组的引用, 这样我们无论在新旧数组进行了修改, 两者都会发生变化, 我们 把这种复制引用的拷贝方法称为浅拷贝,
深拷贝就是指完全的拷贝一个对象, 即使嵌套了对象, 两者也互相分离, 修改一个对象 的属性, 不会影响另一个
如何深拷贝一个数组
1 、这里介绍一个技巧, 不仅适用于数组还适用于对象! 那就是:

var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse( JSON.stringify(arr) );
console.log(new_arr);

原理是 JOSN 对象中的 stringify 可以把一个 js 对象序列化为一个 JSON 字符串, parse 可 以把 JSON 字符串反序列化为一个 js 对象,通过这两个方法,也可以实现对象的深复制。
但是这个方法不能够拷贝函数
浅拷贝的实现:
以上三个方法 concat,slice ,JSON.stringify 都是技巧类, 根据实际项目情况选择使用, 我 们可以思考下如何实现一个对象或数组的浅拷贝, 遍历对象, 然后把属性和属性值都放 在一个新的对象里即可

var shallowCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;

// 根据 obj 的类型判断是新建一个数组还是对象

var newObj = obj instanceof Array ? [] : {};

// 遍历 obj, 并且判断是 obj 的属性才拷贝


for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;

深拷贝的实现
那如何实现一个深拷贝呢? 说起来也好简单,我们在拷贝的时候判断一下属性值的类型, 如果是对象, 我们递归调用深拷贝函数不就好了~

var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值