变量与函数的声明提升

一,变量的类型

ES5将变量分为两种类型,全局变量和局部变量(私有变量)、自由变量。

自由变量:在局部作用域中没用被声明,但是引用的变量(因此他可能是局部变量,也可能是全局变量)

二,变量的生命周期

局部变量:在函数中被声明时开始,在函数运行后被删除

全局变量:在全局中被声明时开始,在页面关闭后被删除

自由变量:在所在的作用域中声明时开始,在所在的作用域中销毁后被删除

三,三种变量区别对比

全局变量:相当于window的一个属性,在全局任何地方都可以访问

局部变量:只能在当前所在作用域中访问(除闭包外)

自由变量:在函数作用域中引用的自由变量, 会按照作用域链去查找。如果找到全局,那此变量就是全局变量;如果找到外层的局部作用域,那此变量还是局部变量

四,var声明的变量和不使用var声明的变量区别

全局作用域中,带var和不带var声明的变量效果一样,只是带var更像一种规范的写法,不带var更像是给window设置一个属性。

函数作用域中,带var声明的变量即为局部变量;不带var声明的变量为全局变量。

五,变量声明提升

5.1 概念

变量声明提升是只当栈内存作用域形成时,js代码执行之前,浏览器会先把带有varfunction关键字的变量提前声明,这种预先处理的机制就叫做变量提升机制也叫预定义。

变量提升只发生在当前作用域。例如,在页面加载时,只有全局作用域的变量会声明提升。

5.2 变量声明提升原理

js引擎会在代码执行之前进行一次预编译,将带有var关键字的变量提升到最顶部,默认值为undefined。然后在按顺序执行代码。

eg: console.log(a)                         js执行为==>                         var a = undefined

         var a = 12                                                                            console.log(a)

                                                                                                     a = 12

六,函数声明提升

函数声明提升与变量声明提升的本质上基本一致,但函数声明提升,也会在堆内存开辟一个空间,他的值是函数体的字符串。所以再预编译阶段,将函数提升到顶部声明,并将默认值赋值为一个引用,引用的值是堆内存的函数体字符串。

eg: foo();                                        js执行为===>             var foo = 0xcc124 // 堆内存的引用

        function foo() {                                                             foo();

                console.log(window)                                           // 输出 f foo() { 

        }                                                                                   //                   console.log(window)

                                                                                            //                   }

七,带等号的匿名函数声明提升

print()
var print = function() {
    console.log('哈喽,世界')
}
print()
/*输出
    Uncaught TypeError: print is not a function
/

这种匿名函数会被当做变量赋值,因此等号左边会被进行提升,而函数体不会被提升。原理如下:

var print = undefined;
undefined()

八,条件判断里的变量声明提升

第一种情况:

if-else代码块中声明了变量。这样的变量无论if条件是否成立,都会被提升

eg: if (false) {

        var a = 12;         // a变量会被提升

      }

第二种情况:

if 判断条件()中的表达式不会被提升。

eg: if (function () {}) {        // 表达式function() {} 不会被提升

            // ... ...

      }

九,重名下的变量和函数声明提升

  • 如果同时使用var和function定义了a变量和a函数,那么会先进行变量提升,再进行函数提升,而函数会覆盖变量的值,因此输出的值永远是函数。
var a = 12;
var a = function() {
    console.log(window)
}

console.log(a); // f function() { console.log(window) }
  • 如果同时使用function定义了多个重名的a函数,那么提升阶段,后面的会替换前面的声明
var a = function() {
    console.log(1)
}
var a = function() {
    console.log(2)
}
var a = function() {
    console.log(3)
}

console.log(a) // function() { console.log(3) }

十,函数形参的变量提升

函数的形参也会在当前函数执行时进行变量提升。

function a(b){
  console.log(b);  
}
a(12);

// 等价于
// function a(b) {
//     var b = undefined;
//     b = 12;
// }

函数内部,声明提升只执行一次,如果函数内部再次使用var xx进行声明,则不会执行。

function a(b) {
    console.log(b);
    var b
    console.log(b+1);
}

a(1);

// 在函数执行时,会先提升形参b的声明 var b = undefined; b = 1;
// 所以第二行声明var b,不会再次进行声明

十一,IIFE自执行函数的声明提升

全局作用域下IIFE自执行函数,无论是否匿名,都不会进行声明提升

匿名的IIFE,因为他没有var 和 function定义的名称。

非匿名的IIFE,因为他有自己的作用域,所以也不会进行声明提升。

IIFE自己的作用域下:都会进行声明提升。

且,非匿名的IIFE声明提升,修改函数名称是无效的。例如:

var a = 10;
(function a(){
    console.log(a)
    a = 20  // 函数名称a无法被修改
    console.log(a)
})()
// ƒ a(){a = 20 console.log(a)}  ƒ a(){a = 20 console.log(a)}

十二,变量声明提升的应用实践

变量声明提升主要是为了了解js的运行机制,主要的应用是在开发中尽量避免使用这个特性,做到规范编写代码,先声明再使用,或者尽量使用let、const代替var。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值