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