变量提升
"变量提升"(Variable Hoisting)是JavaScript中的一个概念,它指的是在函数或代码块内部声明的变量(使用var关键字)在代码执行之前就被提升(hoisted)到其包含函数或全局作用域的顶部。这意味着你可以在声明之前的代码中访问这些变量,并且它们不会被认为是未定义的。
下面是一个关于变量提升的例子:
javascript
function example() {
console.log(a); // 输出:undefined,而不是ReferenceError,因为变量a被提升了
var a = 5;
console.log(a); // 输出:5
}
example();
请注意,只有使用var
声明的变量才会发生变量提升。使用let
和const
声明的变量(ES6中引入的块级作用域变量)不会经历变量提升,而是遵循所谓的"暂时性死区"(Temporal Dead Zone)规则,在声明之前的代码中访问它们会导致引用错误。
javascript
console.log(a);
var a = 5;
//等同于
var a;
cosnole.log(a);
a=5
如果使用let
或const
来声明变量,情况就会不同:
javascript
function example() {
console.log(a); // 抛出ReferenceError,因为变量a没有被提升
let a = 5;
console.log(a); // 这行代码不会执行到,因为前面的console.log已经抛出了错误
}
example();
函数提升
函数提升(Function Hoisting)是JavaScript中另一个与变量提升相关的概念。在JavaScript中,函数声明(function declarations)也会被提升到它们所在作用域的顶部。这意味着你可以在声明之前调用一个函数,并且它仍然可以正常工作。
javascript
foo(); // 这将正常调用函数foo,即使它在下面才声明
function foo() {
console.log("Hello, world!");
}
foo(); // 这也会输出"Hello, world!"
其实主要理解 js 的解析机制就行。
遇到 script 标签的话 js 就进行预解析,将变量 var 和 function 声明提升,但不会执行 function,然后就进入上下文执行,上下文执行还是执行预解析同样操作,直到没有 var 和 function,就开始执行上下文。如:
javascripta=5; show(); var a; function show(){};
预解析:
javascriptfunction show(){}; var a; a=5; show();
需要注意都是函数声明提升直接把整个函数提到执行环境的最顶端。
注意:
使用匿名函数的方式不存在函数提升,因为函数名称使用变量表示的,只存在变量提升。例:
javascript
var getName=function(){
console.log(2);
}
function getName(){
console.log(1);
}
getName();
//结果为2
可能会有人觉得最后输出的结果是 1。但是 getName 是一个变量,因此这个变量的声明也将提升到顶部,而变量的赋值依然保留在原来的位置。需要注意的是,函数优先,虽然函数声明和变量声明都会被提升,但是函数会首先被提升,然后才是变量。
javascript
//函数、变量声明提升后
function getName(){ //函数声明提升到顶部
console.log(1);
}
var getName; //变量声明提升
getName = function(){ //变量赋值依然保留在原来的位置
console.log(2);
}
getName(); // 最终输出:2
javascript
function jsFun6(){ //函数声明和函数表达式的区别
test1();//函数声明提升,在执行代码之前会先读取函数声明,不会报错
function test1(){//函数声明方式创建函数
alert("测试1");
}
//test2();报错,函数还不存在
console.log(test2)//不会报错,变量提升只是提升变量的声明,并不会把赋值也提升上来,输出undefined
var test2=function(){
alert("测试2");
};//使用函数表达式创建一个匿名函数(实际是以变量test3命名的函数)
test2();//不会报错,以创建函数
var test3=function(){
alert("测试3");
}();//加了括号立即执行
var test4 = 12;// !注意看,一旦变量被赋值后,将会输出变量
//函数提升优先级高于变量提升,所以函数先提升,然后变量提升覆盖之前的函数声明,表
//现为变量
function test4() {
alert("测试4");
}
console.log(test4); //12
var test5="test5_1";
(function(){
//js中的变量搜索顺序:找变量时,先找局部变量,如果没有局部变量;再找全局变量。
alert(test5);//此时的test5为局部变量的提升,undefined
var test5="test5_2";
})();
}
需要注意的是,函数提升和变量提升都只在同一个作用域内有效。在不同的作用域(比如嵌套函数内部)中,变量和函数提升的规则不会互相影响。