前端js——JavaScript闭包

本文深入解析JavaScript闭包概念,探讨其工作原理与应用场景,包括函数返回值、参数使用及私有属性实现,揭示闭包如何解决变量作用域问题。

JavaScript闭包

  1. 闭包就是子函数可以有权访问父函数的变量、父函数的父函数的变量、一直到全局变量。归根结底,就是利用js的词法(静态)作用域,即作用域链在函数创建的时候就确定了。
  2. 子函数如果不被销毁,整条作用域链上的变量仍然保存在内存中。

为什么引入闭包的概念(《深入理解JavaScript系列:闭包(Closures)》详细见这里)

function testFn() {

  var localVar = 10;  // 自由变量

  function innerFn(innerParam) {
    console.log(innerParam + localVar);
  }

  return innerFn;
}

var someFn = testFn();
someFn(20); // 30

一般来说,在函数执行完毕之后,局部变量对象即被销毁,所以innerFn是不可能以返回值形式返回的,innerFn函数作为局部变量应该被销毁才对。

这是当函数以返回值时的问题,另外再看一个当函数以参数形式使用时的问题

var z = 10;

function foo() {
  alert(z);
}

foo(); // 10 – 使用静态和动态作用域的时候

(function () {

  var z = 20;
  foo(); // 10 – 使用静态作用域, 20 – 使用动态作用域

})();

// 将foo作为参数的时候是一样的
(function (funArg) {

  var z = 30;
  funArg(); // 10 – 静态作用域, 30 – 动态作用域

})(foo);

 当函数foo在不同函数中调用,z该取哪个上下文中的值呢,这就又是一个问题,所以就引入了闭包的概念,也可以理解为定义了一种规则。

函数以参数形式使用

sort

在sort的内置方法中,函数以参数形式传入回调函数,在sort的实现中调用:

[1, 2, 3].sort(function (a, b) {
  ... // 排序条件
});

map

和sort的实现一样

[1, 2, 3].map(function (element) {
  return element * 2;
}); // [2, 4, 6]

 另外利用自执行匿名函数创建的闭包

var foo = {};

// 初始化
(function (object) {

  var x = 10;

  object.getX = function() {
    return x;
  };

})(foo);

alert(foo.getX()); // 获得闭包 "x" – 10

 利用闭包实现私有属性的存取

var fnBox = [];
function foo() {
    for(var i = 0; i < 3; i++) {
        fnBox[i] = function() {
            return i;
        }
    }
}

foo();
var fn0 = fnBox[0];
var fn1 = fnBox[1];
var fn2 = fnBox[2];
console.log(fn0()); //  3
console.log(fn1()); //  3
console.log(fn2()); //  3

用伪代码来说明如下:

fn0.[[scope]]= {
    // 其他变量对象,一直到全局变量对象
    父级上下文中的活动对象AO: [data: [...], i: 3]
}

fn1.[[scope]]= {
    // 其他变量对象,一直到全局变量对象
    父级上下文中的活动对象AO: [data: [...], i: 3]
}

fn2.[[scope]]= {
    // 其他变量对象,一直到全局变量对象
    父级上下文中的活动对象AO: [data: [...], i: 3],
}

分析:

这是因为fn0,fn1,fn2的作用域链共享foo的活动对象,而且js没有块级作用域,当函数foo执行完毕的时候foo的活动对象中i的值已经变为3,当fn0,fn1,fn2执行的时候,其最顶层的作用域没有i的变量,就沿用着作用域链查找foo的活动对象中的i所以i都为3。

但这种结果往往不是我们想要的,这时就可以利用认为创建一个闭包来解决这个问题,如下:

var fnBox = [];
function foo() {
    for(var i = 0; i < 3; i++) {
        fnBox[i] = (function(num) {
            return function() {
                return num;
            }
        })(i);
    }
}
foo();
var fn0 = fnBox[0];
var fn1 = fnBox[1];
var fn2 = fnBox[2];
console.log(fn0()); //  0
console.log(fn1()); //  1
console.log(fn2()); //  2

 用伪代码来说明如下:

fn0.[[scope]]= {
    // 其他变量对象,一直到全局变量对象
    父级上下文中的活动对象AO: [data: [...], i: 3]
}

fn1.[[scope]]= {
    // 其他变量对象,一直到全局变量对象
    父级上下文中的活动对象AO: [data: [...], i: 3]
}

fn2.[[scope]]= {
    // 其他变量对象,一直到全局变量对象
    父级上下文中的活动对象AO: [data: [...], i: 3],
}

分析:

当使用自执行匿名函数创建闭包,传入i的值赋值给num,由于作用域链是在函数初始化时创建的,所以当每次循环时,函数fn0、fn1、fn2的作用域链中保存了档次循环是num的值,当fn0、fn1、fn2调用时,是按照本身的作用域链进行查找的。

总结

从理论的角度讲由于js中所有函数都是闭包,但是从应用的角度来说,只有当函数以返回值返回、或者当函数以参数形式使用、或者当函数中自由变量在函数外被引用时,才能成为明确意义上的闭包。

 

 

内容概要:本文介绍了一项创新性未发表的研究,即利用多元宇宙优化算法(Multiverse Optimizer, MVO)对分时电价下的需求响应与综合能源系统调度问题进行建模与求解,旨在实现能源系统的经济性、高效性与可持续性运行。该研究构建了包含多种能源设备(如光伏、风机、燃气轮机、储能系统等)及可调节负荷的综合能源系统模型,充分考虑了用户侧的需求响应行为在分时电价机制下的响应特性,通过MVO算法对系统运行成本、能源利用率、碳排放等多目标进行协同优化,实现了日前调度计划的智能决策。研究还提供了完整的MATLAB代码实现,便于研究人员复现实验、验证算法性能,并为进一步研究提供可靠的仿真基础。; 适合人群:具备一定电力系统、优化算法及MATLAB编程基础的科研人员、研究生以及从事能源互联网、综合能源系统规划与运行的技术工程师。; 使用场景及目标:① 学习并掌握多元宇宙优化算法在复杂能源系统调度中的具体应用方法;② 研究分时电价机制如何通过需求响应引导用户参与电网互动,实现削峰填谷;③ 实现综合能源系统(IES)中冷、热、电、气等多种能源的协同优化调度,以降低运行成本、提高新能源消纳能力和系统可靠性;④ 为相关领域的学术研究提供可复现的代码实例和仿真平台。; 阅读建议:此资源以MATLAB代码为核心载体,深入剖析了算法应用与系统建模的全过程。建议读者在学习时,不仅应关注代码的实现细节,更要理解其背后的数学模型、优化目标设定和约束条件的物理意义。建议结合文档中的模型描述,逐步调试代码,观察不同参数和场景下的优化结果,从而深刻掌握综合能源系统优化调度的设计思想与关键技术。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值