js闭包总结

  1. 闭包就是一个函数里面嵌套一个函数,里面的函数通过return返回出来。
    2.下面创建了4个闭包函数,每个调用都独立,互不干扰。
var num = new Array();
    for(var i=0; i<4; i++){
        //num[i] = 闭包;//闭包被调用了4次,就会生成4个独立的函数
        //每个函数内部有自己可以访问的个性化(差异)的信息
        num[i] = f1(i);
    }
    function f1(n){
       return function f2(m){
          n=n++;
           m=m++;
            alert(n+m);
        }
    }
  
  num[0](2); //alert(2)
  num[0]=null; //释放内存

二、下面是一个经典例子,闭包中变量的变化。

function fn(){
	var n= 0
	return function(){
		var m = 0;
		console.log(++n,++m)
	}
}
var fn1 = fn()
fn1()   //console 1,1
fn1()   //console 2,1

三、下面3种情况,慢慢体会

for (var i = 0; i<5; i++){
	setTimeout(function(){console.log},100)
}
//会打印5个5


for(var i = 0; i<5; i++){
	(function(i){
		setTimeout(function(){console.log(i)},100)
	}(i))
}
//用闭包,把变量放在上级,就会打印0,1,2,3,4
//直接用let也可以实现这种方法


for(var i = 0; i<5; ++i){
	(function(i){
		setTimeout(function(){console.log(i)},1000*i)
	}(i))
}
//每隔1秒执行一次定时器

四、闭包作为参数传递

var num = 11
var fn1 = function(x){
	if(x>num){
		console.log(x)
	}
}
void function(fn2){
	var num = 100
	fn2(30)
}(fn1)
//console  30
//fn1函数作为参数传递进立即执行函数,fn2(30)把30传递进fn1函数,然后执行fn1函数里面的判断。fn1里面的num作用域取的是全局作用域的num

五、闭包的常见数组按钮写法
某段dom结构如下:在该dom结构中,li在列表的下标分别是0,1,2,3,4.请分别为每个li添加点击事件,输出响应的下标,注意:使用原生的js,且只能添加事件不能添加属性.

<ul id="list">
  <li>qw</li>
  <li>er</li>
  <li>ty</li>
  <li>ui</li>
  <li>ou</li>
</ul>

var lis = document.querySelectorAll('li');
    //闭包实现
    for (var i = 0; i < lis.length; i++) {
      lis[i].onclick = (function (j) {
        return function () {
          console.log(j);
        }
      })(i);
    }
    //forEach实现
    lis.forEach(function (v, i) {
      v.onclick = function () {
        console.log(i);
      }
    })
    //ES6实现
    for(let i=0;i<lis.length;i++){
      lis[i].onclick=function(){
        console.log(i);
      }
    }

最后总结一下闭包的好处与坏处

好处
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
③匿名自执行函数可以减少内存消耗

坏处
①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

防抖函数中用闭包,储存一个变量函数

// 防抖
function debounce(fn, wait) {    
    var timeout = null;    
    return function() {        
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
// 处理函数
function handle2() {    
    console.log("防抖函数"); 
}
// 滚动事件
window.addEventListener('scroll', debounce(handle2, 1000));

节流函数

var throttle = function(func, delay) {            
    var timer = null;            
    return function() {                
        var context = this;               
        var args = arguments;                
        if (!timer) {                    
            timer = setTimeout(function() {                        
                func.apply(context, args);                        
                timer = null;                    
            }, delay);                
        }            
    }        
}
let func = function() {            
    console.log("节流函数");        
}
window.addEventListener('scroll', throttle(func, 1000));

单例模式
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。

var HeadClass = function () { };
var Head = (function () { // 匿名自执行函数
    var instance; // 声明一个instance对象
    return function () {
        if (instance) { // 如果已存在 则返回instance
            return instance;
        }
        instance = new HeadClass() // 如果不存在 则new一个HeadClass对象
        return instance;
    }
})();
var a = new Head();
var b = new Head();
console.log(a===b) // true

柯里化 currying
function Parent(x,y){
return x+y
}
function curryingParent(x){
return function(y){
return x+y
}
}
curryingParent(1)(2)

### JavaScript 原型链和闭包的概念及总结 #### 什么是原型链? 在 JavaScript 中,每个函数都有一个 `prototype` 属性,默认指向一个新的对象。这个新对象有一个特殊的属性 `__proto__`,它会链接到创建它的构造函数的 `prototype` 对象上[^2]。当通过实例访问某个不存在的属性或方法时,JavaScript 解析器会在该实例的原型链中查找。 以下是关于原型链的一个简单例子: ```javascript function Person(name) { this.name = name; } Person.prototype.sayName = function () { console.log(this.name); }; const person1 = new Person('Alice'); person1.sayName(); // Alice ``` 在这个例子中,`sayName()` 方法并不直接存在于 `person1` 实例中,而是位于其原型链上的 `Person.prototype` 上[^2]。 --- #### 什么是闭包闭包是指有权访问另一个函数作用域中的变量的函数。即使外部函数已经执行完毕并返回结果,内部函数仍然能够记住和访问这些变量[^1]。 下面是一个简单的闭包示例: ```javascript function createCounter() { let count = 0; return function () { count += 1; return count; }; } const counter = createCounter(); console.log(counter()); // 输出 1 console.log(counter()); // 输出 2 ``` 在此代码片段中,匿名函数记住了外层函数 `createCounter` 的局部变量 `count`,从而形成了闭包[^1]。 --- #### 原型链与闭包的区别 - **原型链** 是一种用于实现继承的机制,主要涉及对象之间的关系以及如何共享属性和方法。 - **闭包** 则是一种允许函数捕获并保存对外部变量引用的能力的技术,主要用于数据封装和状态保持[^2]。 两者虽然都属于高级特性,但在实际开发中有不同的应用场景。例如,在构建类库或者框架时可能会频繁用到这两种技术来优化性能、减少内存占用以及增强代码可读性和维护性。 --- #### 使用指南 为了更好地理解和运用这两项关键技术,请遵循以下建议: 1. 当需要定义多个具有相同行为的对象时,优先考虑使用原型链而不是每次重新声明相同的逻辑; 2. 如果某些特定功能依赖于私有成员,则可以通过闭包隐藏那些不希望被外界直接访问的数据结构; 3. 避免滥用复杂嵌套层次较高的闭包以免造成不必要的资源浪费甚至引发潜在错误; 4. 结合 ES6+ 新增语法糖(如箭头函数),简化传统回调地狱问题的同时也要注意它们不会绑定自己的this值这一特点可能带来的影响[^4]。 --- 问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端段

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值