阅读 283

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

大多数人在初步学习javascript时,大多是通过分析学习别人的代码,运用到自己的项目中(包括我在内)。一旦代码出错,不能很快的定位问题,也无法完全理解导致问题的真正原因,根源大多是因为底层的基础不够扎实,今天就一起来学习一下javascript的部分基础知识。

一、变量声明提升

接下来我们先看一段代码:

console.log(a);
var  a = 5;复制代码

输出的结果应该是什么?

5?

ReferenceError还是undefined

有人会说,javascript不是解释一行执行一行吗?打印a的时候找不到,应该会报错。但运行后的结果却是undefined。

为什么那?这里我们就要深入了解javascript在执行之前都做了什么!

一段javascript代码在执行之前会经历三步,统称为“编译”。

  1. 分词/词法分析
  2. 解析/语法分析
  3. 代码生成
“编译”会发生在代码执行的前一刻进行,“编译”阶段会首先处理变量和函数的声明,当我们看到var a = 5时,可能会认为这是一个声明,但JavaScript引擎实际会把它看成两部分来处理,声明和赋值,声明发生在编译阶段,而赋值在执行阶段。因此上面的代码会被编译为:

var a;
console.log(a);
a = 5;
复制代码

这个过程就像变量声明从之前的位置移动到了最上面,被叫做提升。

二、函数声明提升

我们看看下面的代码能否正常运行:

test();
function test(){
  console.log(a);
  var a = 5;
}复制代码

答案是肯定的,因为test函数的声明被提升了,引擎会将代码解析为:

function test(){
  var a;
  console.log(a);//undefined
  a = 5;
}
test();复制代码

这里需要注意的是,因为作用域的关系,变量a提升到了test函数的顶部,而非全局的顶部。我们可以理解为变量声明和函数声明在编译过程中会被提升到当前作用域的顶端。

需要注意的是函数声明会被提升,但函数表达式不会被提升。

foo();
var foo = function(){
......
}
复制代码

上面的代码会报TypeError:foo is not a function,根据变量的提升原则,以上代码会被编译为:

var foo;
foo();
foo = function(){
......
}复制代码

这样就一目了然了,foo被声明,但未赋值,初始值undefined,foo()对undefined进行了函数调用而导致非法操作,因此抛出TypeError异常。

三、函数声明优先

变量声明和函数声明在编译时都会被提升,但需要注意函数声明会优先被提升,然后才是变量。

看看一下代码:

test();
var test;
function test(){
    console.log('first');
}
test = function(){
    console.log('sencond');
}复制代码

执行test()会打印first,为什么那?我们来看看编译过程:

function test(){
    console.log('first');
}
test();
test = function(){
    console.log('sencond');
}复制代码

我们会发现var test去哪了?因函数声明会被优先提升,在变量声明提升时引擎会发现test已经声明,因此直接忽略掉var test。

注意:重复的var声明会被忽略掉,但出现在后面的函数声明会覆盖前面的声明。

因此写程序时要注意避免重复声明,特别是变量声明和函数声明在同一作用域时,这样能省去不少麻烦!



以上为学习笔记及总结,如有错误欢迎指出,谢谢!


文章分类
前端
文章标签