变量声明提前和 函数声明提取
//变量声明提前
console.log(a);
var a = 1; //返回undefined,,但不会报错 但是let 不会变量提前
//函数声明提前,不止函数名声明提前了,整个函数也被创建好了
fn();
function fn() {
console.log('函数声明提前了'); //返回函数声明提前了
}
//函数表达式形式的函数声明不会提前也不会被创建
fn2(); //报错
var fn2 = function() {
console.log('函数声明提前');
}
补充:
- 什么是声明提前
声明提前是发生在js引擎”预编译“的时候,是在代码运行之前。当程序开始执行前,会先将var声明的变量和function声明的函数提前到当前 作用域 中创建,赋值留在原地。 - 声明提前的坏处
声明提前破坏了程序的执行顺序,会降低代码可读性,还容易造成程序错误
解决:
采用 匿名函数自调 包住当前的代码块的方式来解决声明提前的问题
使用用ES6中的 let关键字 来代替var
函数声明提升和变量声明提升的顺序
对于同名的变量声明,Javascript采用的是忽略原则,后声明的会被忽略,变量声明和赋值操作可以写在一起,但是只有声明会被提升,提升后变量的值默认为undefined,结果是在赋值操作执行前变量的值必为undefined
对于同名的函数声明,Javascript采用的是覆盖原则,先声明的会被覆盖,因为函数在声明时会指定函数的内容,所以同一作用域下一系列同名函数声明的最终结果是调用时函数的内容和最后一次函数声明相同
对于同名的函数声明和变量声明,采用的是忽略原则,由于在提升时函数声明会提升到变量声明之前,变量声明一定会被忽略,所以结果是函数声明有效
例题
下面再看一个例子:
console.log(xxp) //‘undefined’
var xxp= 1
function fn() {
console.log(xxp) // 函数本身 function xxp() { console.log(xxp)}
var xxp= 2
function xxp() { console.log(xxp)}
console.log(xxp) // 2
xxp() //报错
}
fn()
上面的代码等同于下面的代码:
console.log(xxp) // ‘undefined ’ 声明提前
var xxp= 1
function fn() {
function xxp() {console.log(xxp)}
var xxp
console.log(xxp) // 函数本身 (当名字相同时,再次定义【没有赋值】会被忽略)
xxp=2
console.log(xxp) // 2 这里进行了赋值操作 (函数已经不存在了,只有变量xxp)
xxp() // 报错; 这里没有函数了,只有变量xxp
}
fn()