js中的变量提升和函数提升——精炼版

javaScript中用var定义变量时存在变量提升(ES6及之后的let/const定义变量时为块级作用域无变量提升,ES6之前js没有块级作用域),比如:

console.log(a);  // 不会报错,会打印出“undefined”
var a = 2;

上述代码中变量声明var a会提升到代码顶部,但a = 2这个赋值操作并没有提升,相当于

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

函数也有函数提升,且函数提升的优先级高于变量提升,但只有函数声明才有函数提升,函数表达式则没有函数提升,细看代码,一定要看:

foo();     //  输出 1
function foo() {       // 函数声明的形式,则函数提升到顶部
    console.log('1');   
}
var foo = function() { 	    // 函数表达式的形式,则等同于一个变量提升,优先级小于函数提升
    console.log('2'); 
}

上述代码会被引擎理解为:

function foo() { 	    
    console.log('1'); 
}  
var foo;
foo();  
foo = function() {
 	console.log('2'); 
}

再看个例子,理解作用域链是静态的及函数提升:

// 全局环境
var a = "全局变量";

function A() {
  var a = "局部变量";
  B();
}

function B() {
  console.log(a);
}
A();   // 会打印出“全局变量”

JS的函数在声明时,采用的是词法作用域(词法环境就是在JavaScript 引擎创建一个执行上下文时,创建的用来存储变量和函数声明的环境,它可以使代码在执行期间,访问到存储在其内部的变量和函数,而在代码执行完毕之后,从内存中释放掉。),即在声明时就确定好了作用域链。作用域链的定义是静态的!上述代码等价于:

// 全局环境

function A() {
  var a = "局部变量";
  B();  // 虽然函数B在函数A中被调用,但函数B在声明时它的作用域链就已经确定了,为函数B作用域 -> 全局作用域
}

function B() {      // a在B函数内未定义,则向外层找,外层就是全局环境,找到了var a = "全局变量";
  console.log(a);
}

var a = "全局变量";

A();   // 会打印出“全局变量”

B函数在声明时,js语言的作用域机制使得变量a会从本函数内向外逐层找它定义的地方,B函数内没有定义a,则向外层找,外层就是全局环境,找到了var a = "全局变量",而函数A和函数B在作用域的概念上面层级关系是同层级,即函数A/B作用域 -> 全局作用域,所以函数B中a未定义不会去函数A中找a的定义,而是去B函数的外层全局环境去找A的定义。

补充问题:为啥要函数提升?变量提升?

函数提升就是为了解决相互递归的问题,相互递归就是A/B两个函数互相在自身函数体内调用对方,如果没有函数提升,而是按照自下而上的顺序,当A函数被调用时,B函数还未声明,所以A内部无法调用B函数。所以开发者设计了函数提升这一形式,将函数提升至当前作用域的顶部。

变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。变量提升可能会出现一些难以预知的问题,在ES6后,由let/const来定义变量,不会变量提升,为了更好的维护代码,目前很多公司也明确要求尽量使用let/const来定义变量而不要用var。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值