JS进阶——变量和函数提升

变量提升

"变量提升"(Variable Hoisting)是JavaScript中的一个概念,它指的是在函数或代码块内部声明的变量(使用var关键字)在代码执行之前就被提升(hoisted)到其包含函数或全局作用域的顶部。这意味着你可以在声明之前的代码中访问这些变量,并且它们不会被认为是未定义的。

下面是一个关于变量提升的例子:

javascript 复制代码
function example() {  
    console.log(a); // 输出:undefined,而不是ReferenceError,因为变量a被提升了  
    var a = 5;  
    console.log(a); // 输出:5  
}  
  
example();

请注意,只有使用var声明的变量才会发生变量提升。使用letconst声明的变量(ES6中引入的块级作用域变量)不会经历变量提升,而是遵循所谓的"暂时性死区"(Temporal Dead Zone)规则,在声明之前的代码中访问它们会导致引用错误。

javascript 复制代码
console.log(a); 
var a = 5;  
//等同于

var a;
cosnole.log(a);
a=5

如果使用letconst来声明变量,情况就会不同:

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,就开始执行上下文。如:

javascript 复制代码
a=5;
show();
var a;
function show(){};

预解析:

javascript 复制代码
function 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";
    })();
                
}

需要注意的是,函数提升和变量提升都只在同一个作用域内有效。在不同的作用域(比如嵌套函数内部)中,变量和函数提升的规则不会互相影响。

相关推荐
I_Am_Me_4 分钟前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
雯0609~11 分钟前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ14 分钟前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z20 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
前端百草阁43 分钟前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜44 分钟前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4041 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish1 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue
zwjapple1 小时前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five1 小时前
TypeScript项目中Axios的封装
开发语言·前端·javascript