变量声明提升和函数声明提升

最近在吃饭的时候看到一道关于函数声明提升的问题

var a=1;
function b () {
a=10;
return;
function a () {}
}
b();
console.log(a) //1

很多人在看第一眼的时候会认为结果为10,我作为一个小白第一反应也是认为函数内部的a是全局变量,所以在执行b后a的值变为10,之后再看了后面的分析后才恍然大悟,在b函数执行后a依然是1,于是琢磨这写了人生中第一篇博客,写的不好请见谅,若有技术问题,会在第一时间解决

1.变量声明

使用var声明的变量,如果变量没有赋值,系统则默认赋值为undefined

2.没有块级作用域

在ES6的let,const出现之前,JavaScript是没有块级作用域的,也就是自己的执行环境,在《JavaScript高级程序设计》中提到

if (true) {
var color = "blue";
}
alert(color);    //"blue" 

在JavaScript中,if语句中的变量声明会将变量加到当前的执行环境(这里指的是全局环境)中相当于以下代码

var color;
if (true) {
color = "blue";
}
console.log(color);  //"blue"

还有一个非常经典的问题

for(var i=0;i<10;i++){
//这里做任意事情
}
alert(i)    //10

这里可以理解为定义了i变量,然后在for循环完成后,i变量依然存在于全局环境中,而且在alert(i)的时候for循环已经结束,i的值等于10,所以alert(i)的结果就是10了

3.变量声明提升

再来回到第一个例子,如果它的条件为false

if (false) {
var color = "blue";
}
alert(color);    //undefined

实质上上述例子与以下代码是一样的

var color;
if (false) {
color = "blue";
}
console.log(color); //undefined

因为color定义了,但是if的条件为false,所以只声明了color变量却没有赋值,最后显示undefined

Js编译器会把变量声明看成两个部分分别是声明操作(var color)和赋值操作(color="blue")

声明操作在编译阶段进行,声明操作会被提升到执行环境的顶部,值是undefined(表示未初始化)

赋值操作会被留在原地等待执行阶段

注释:声明提前是在JavaScript引擎的预编译时进行,是在代码开始运行之前。

4.函数声明提升

函数的两种创建方式

  • 函数声明
  • 函数表达式

函数声明:

function sum(num1,num2) {
return num1+num2;
}

函数声明提升会在编译阶段把函数和函数体整体都提前到执行环境顶部,所以我们可以在函数声明之前调用这个函数

sum(10,10);  //20
function sum(num1,num2){
return num1+num2;
}

上述代码也等价于这样 

var sum;
sum = function (num1,num2){
return num1+num2;
}
sum(10,10);  //20

函数表达式: 

var sum = function (num1,num2){
return num1+num2;
}

 通过函数表达式创建的函数没有函数声明提升,只有定义了之后才能调用,上述代码实质上是这样的

var sum; 
sum= function (num1,num2){
return num1+num2;
}

在函数表达式创建的函数之前同样执行sum(10,10)

sum(10,10);   //报错 Uncaught TypeError: sum is not a function
var sum = function (num1,num2){
return num1+num2;
}

因为通过函数表达式创建的函数没有函数提升,所以执行sum(10,10)时根本没有创建函数,但是没有创建函数应该会显示undefined,为什么会报错呢,实质上上述代码是这样的

var sum;
sum(10,10);
sum=function (num1,num2){
return num1+num2;
}

函数表达式通过声明一个变量sum把函数赋值给sum,而通过var声明的sum存在变量提升,会提升到执行环境顶部,然后在执行sum(10,10)就会报错,提示sum不是一个函数,undefined当然不是一个函数啦,sum(10,10)这行代码执行完毕后才会对sum变量进行赋值,这时sum才指向了这个函数

函数声明提升>形参>变量声明提升

当同时存在函数声明和变量声明时,来看这个例子

getName();    //1
var getName = function () {
console.log(2);
}
function getName () {
console.log(1);
}
getName(); //2

当存在函数声明和变量声明时,函数声明在前,变量声明在后,所以上述代码是这样的

//使用函数声明创建的函数函数声明提升
var getName;         
getName = function () {
console.log(1);
}
//变量声明提升
var getName; 
getName(); //1
getName=function () {
console.log(2);
}
getName(); //2

 再来看一道面试题 

var a=1;
function b () {
a=10;
return;
function a () {}
}
b();
console.log(a) //1

 在b函数内部,因为存在函数变量声明提升,导致return后面的function a () {}被提升到了b函数内部的顶部,等同于在b函数内部声明了局部变量a(与函数外部的全局变量a不同),并且给变量a赋值给一个匿名函数,最后再给局部变量a赋值为10,最后return退出函数,局部变量a在b函数执行完后被销毁,在全局环境中console.log(a)自然就指向了第一行声明的a,即数字1

var a=1;
function b () {
var a;
a=function () {}
a=10;
return;
b();
console.log(a) //1

猜你喜欢

转载自blog.csdn.net/GB112233/article/details/81183298