首页 > 其他分享 >从变量声明到作用域到闭包

从变量声明到作用域到闭包

时间:2022-10-05 11:45:28浏览次数:48  
标签:闭包 函数 作用域 var 声明 变量

Es6新增加了两种声明变量的方式let ,const 从客观上为这门语言更精确地声明作用域和语义提供了更好的支持。以下是三种声明方式的区别与对比

  作用域      初始化值 变量提升(hoist) 全局声明
var 函数作用域           × 非必须 √ 拉到函数作用域的顶部,可以重复声明 √  全局作用域中的声明会成为window对象的属性
let 块级作用域 × 非必须 × 声明前会有“暂时性死区”(temporal dead zone),不可以重复声明 ×
const 块级作用域 √ 必须有初始化值 ,并且不可更改值的引用             ×不可以重复声明 ×

现在我们把注意力放到作用域方面,下面的例子是一道常见的面试题,这里使用了var 关键字声明了循环变量i,由于var的作用域是函数作用域那么这个变量并不会被限制在for循环内,而是在匿名函数内。当setTimeout执行时,for循环已执行完毕,(此处关于js事件循环)此时 i == 5,于是输出了5次 5

var fn = function(){
    for(var i = 0;i<5;i++){
        setTimeout(function(){console.log(i)},0)
    }
};    
fn() // 5 5 5 5 5 

如果我们在此使用let 去声明变量呢

var fn = function(){
    for(let i = 0;i<5;i++){
        setTimeout(function(){console.log(i)},0)
    }
};    
fn() //  0 1 2 3 4

此时可以输出每次计算后的i 值,因为此时i 处在块级作用域中,也就是相当于每次遍历的时候都生成了一套上下文。

那如果我就是想要用var声明并且也想按照循序输出 i 的值呢?这时候就需要引出闭包了。

var fn = function(){
    for(var i = 0;i<5;i++){
        (function(j){setTimeout(function(){console.log(j)},0)})(i)
    }
};    
fn()//0 1 2 3 4


这里我们用了一个立即执行函数把 i 作为参数传给了匿名函数,并在setTimeout中引用他。

对于闭包,在第4版JS高级程序中的定义为--闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。从这个定义中我们可以发现他内涵的两个特点,1.会有两个函数,他们是嵌套关系,也就是一个函数中内部还有一个函数 2.一个函数会引用另一个函数的变量,既然是嵌套关系 那只能是 内部的函数引用外部函数的变量 。

示例1

function outer () {
        var o = 1;
        return function inner (){
            console.log(o);
        }
}

var test = outer();
test(); // 1

至此我们已经可以写出一个简单的闭包函数,并了解了他的特点。那么他有什么用呢?

 

标签:闭包,函数,作用域,var,声明,变量
From: https://www.cnblogs.com/chancepeng/p/16739010.html

相关文章