深入理解javascript作用域系列第三篇——声明提升(hoisting)

本文深入解析JavaScript中的声明提升概念,包括变量和函数声明提升的细节,以及提升如何影响代码执行流程。通过具体示例说明了变量提升、函数声明提升及函数覆盖等特性。

前面的话

一般认为,javascript代码在执行时时由上到下一行一行执行的。但是实际上这并不完全正确,主要是因为声明提升的存在。

一、变量的声明提升

a = 2;
var a;
console.log(a);

直觉上,会认为是undefined,因为var a 声明在a = 2;之后,可能变量被重新赋值了,因为会被赋予默认值undefined。但是,真正的输出结果却是2。
就算是下面的代码这样,还是会输出2.

var a = 2;
var a;
console.log(a);

因为根据编译器在编译阶段的原理:编译器查找作用域是否已经有一个名称为a的变量存在于同一作用域的集合中。如果是,编译器会忽略该声明,继续进行编译;否则它会要求作用域在当前作用域集合中声明一个新的变量,并命名为a。

鉴于上面这些输出,可能认为下面这个代码片段同样会输出2。但是实际上,真正输出的是undefined。
所有这些和观感相违背的原因在于编译器的编译过程。

console.log( a ) ;
var a  =  2 ;

第一篇介绍过作用域的内部原理,引擎会在解释javascript代码之前首先会对其进行编译。编译阶段中的一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。

包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。

var a = 2;

这个代码片段实际上包括两个操作:var a 和 a = 2;
第一个定义声明是在编译阶段由编译器进行的。第二个赋值操作会被保留在原地等待引擎在执行阶段执行。

//对变量a的声明提升到最上面后,再执行代码时,控制台输出2
var a;
a = 2 ;
console.log(a);

声明提升是从它们在代码中出现的位置被“移动”当前作用域的最上面,这个过程就叫做提升(hoisting)

【注意点】:每个作用域都会进行提升操作。

console.log(a);
var a = 0;
function fn(){
    console.log(b);
    var b = 1;
    function test(){
        console.log(c);
        var c = 2;
    }
    test();
}
fn();
//变量声明提升后,变成下面这样
var a ;
console.log(a);
a = 0;
function fn(){
    var b;
    console.log(b);
    b = 1;
    function test(){
        var c ;
        console.log(c);
        c = 2;
    }
    test();
}
fn();

其实真正的提升应该是下面这样,但为了便于理解上面的这种表示更能让人接受。

//变量声明提升后,变成下面这样
var a ;
function fn(){
    var b;
    function test(){
        var c ;
        console.log(c);
        c = 2;
    }
    console.log(b);
    b = 1;
    test();
}
console.log(a);
a = 0;
fn();

二、函数声明提升

声明包括两种:变量声明和函数声明,不仅变量声明可以提升,函数声明也有提升操作。

foo();
function foo(){
    console.log(1);//1
}

上面这个代码片段之所以能够在控制台输出1,就是因为foo()函数声明进行了提升。

function foo(){
    console.log(1);
}
foo();

函数声明会提升,但函数表达式却不会提升。

foo();
var foo = function(){
    console.log(1);//TypeError: foo is not a function
}

上面这段程序中的变量标识符foo被提升并分配给全局作用域,因此foo()不会导致ReferenceError。但是foo此时并没有赋值,foo()由于对undefined值进行函数调用而导致非法操作,因此会抛出TypeError异常。

//变量提升后,代码如下所示:
var foo;
foo();
foo = function(){
    console.log(1);
}

即使是具名的函数表达式也无法被提升。

foo();//TypeError: foo is not a function
var foo = function bar(){
      console.log(1);
};
//声明提升后,代码变为:
var foo;
foo();//TypeError: foo is not a function
foo = function bar(){
      console.log(1);
};

函数表达式的的名称只能在函数体内部使用,而不能在函数体外部使用。


var foo = function bar(){
    console.log(1);
};
bar();//TypeError: bar is not a undefined

三、函数覆盖

函数声明和变量声明都会被提升,但是,函数声明会覆盖变量声明。

var a;
function a(){}
console.log(a);//'function a(){}' //函数名代表整个函数

但是,如果变量存在赋值操作,则最终的值为变量的值。

var a=1;
function a(){}
console.log(a);//1
var a;
function a(){};
console.log(a);//'function a(){}'
a = 1;
console.log(a);//1

【注意点】变量的重复声明是无用的,但函数的重复声明会覆盖前面的声明(无论是变量还是函数声明【不是很理解】)
【1】:变量的重复声明是无用

var a = 1;
var a;
console.log(a);//1

【2】:由于函数声明提升优于变量声明提升【覆盖变量声明还是提升到变量的前面】,所以变量的声明无作用。

var a;
function a(){
    console.log(1);
}
a();//1

【3】:后面的函数声明会覆盖前面的函数声明。

a();//2
function a(){
    console.log(1);
}
function a(){
    console.log(2);
}

所以,应该避免在同一作用域中重复声明。

转载自:小火柴的蓝色理想

http://www.cnblogs.com/xiaohuochai/p/5613593.html
在阅读老师的博客时,我把它当做看书来对待,所以我的博客大部分来自老师的原话以及实例,再加上自已的一些理解,并且做了适当的标注,还有对老师的代码进行了一些测试。

单向双向V2G 环境下分布式电源与电动汽车充电站联合配置方法(Matlab代码实现)内容概要:本文介绍了在单向和双向V2G(Vehicle-to-Grid)环境下,分布式电源与电动汽车充电站的联合配置方法,并提供了基于Matlab的代码实现。研究涵盖电力系统优化、可再生能源接入、电动汽车充放电调度、储能配置及微电网经济调度等多个关键技术领域,重点探讨了在不同电价机制和需求响应策略下,如何通过智能优化算法实现充电站与分布式电源的协同规划与运行优化。文中还展示了多种应用场景,如有序充电调度、鲁棒优化模型、多目标优化算法(如NSGA-II、粒子群算法)在电力系统中的实际应用,体现了较强的工程实践价值和技术综合性。; 适合人群:具备电力系统、新能源、智能优化算法等相关背景的科研人员、研究生及从事能源系统规划与优化的工程技术人员;熟悉Matlab/Simulink仿真工具者更佳。; 使用场景及目标:①用于科研项目中关于电动汽车与分布式电源协同配置的模型构建与仿真验证;②支持毕业论文、期刊投稿中的案例分析与算法对比;③指导实际电力系统中充电站布局与能源调度的优化设计。; 阅读建议:建议结合文中提供的Matlab代码与具体案例进行同步实践,重点关注优化模型的数学建模过程与算法实现细节,同时可参考文末网盘资源获取完整代码与数据集以提升学习效率。
【电动车】【超级棒】基于蒙特卡洛模拟法的电动汽车充电负荷研究(Matlab代码实现)内容概要:本文围绕基于蒙特卡洛模拟法的电动汽车充电负荷研究展开,利用Matlab代码实现对不同类型电动汽车(如常规充电、快速充电、换电模式)在不同场景下的充电负荷进行建模与仿真。通过蒙特卡洛方法模拟大量电动汽车的充电行为,结合用户出行规律、充电时间、电量需求等随机因素,分析电动汽车规模化接入电网后对电力系统负荷的影响,并探讨分时电价策略对充电负荷的引导作用,进而优化电网运行。研究涵盖充电负荷的空间分布特性、时间分布特征及对电网峰谷差的影响,旨在为电力系统规划和电动汽车有序充电管理提供理论支持和技术工具。; 适合人群:具备一定电力系统、交通工程或新能源汽车背景的研究生、科研人员及从事智能电网、电动汽车相关领域的工程技术人员。; 使用场景及目标:①用于研究大规模电动汽车接入对配电网负荷曲线的影响;②支撑分时电价、需求响应等政策制定与优化;③为充电站规划、电网调度、储能配置等提供数据支持和仿真平台;④适用于学术研究、课题复现及工程项目前期分析。; 阅读建议:建议读者结合文中提供的Matlab代码进行实践操作,重点关注蒙特卡洛模拟的参数设置、充电行为的概率建模过程,并尝试调整输入变量以观察负荷变化趋势,加深对电动汽车充电负荷不确定性和聚合效应的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值