var与let声明之间的区别与联系?

13 篇文章 0 订阅

前言:提及var与let,主要牵扯到的是js的作用域问题.js在es6之前是没有块级作用域的.

区别1:作用域不同

var: 在函数内使用的时候,作用域是整个函数体.即便是在代码块(简而言之就是大括号里面)内,也是如此.
let: 作用域是在代码块内.

function num() {
    if (true) {
        var a = 4; // 作用域为 num函数体内
        let b = 5; // 作用域为 if{}内
        console.log(a); // 4
        console.log(b); // 5
    }
console.log(a); // 4
console.log(b); // 无法访问
}
num();

区别2:变量提升

var: 声明的代码无论写在哪,变量的声明总会提升到作用域的顶部.(当然即便是在顶部,也只会在函数使用function声明时的下面,函数是js的一等公民.有关于变量声明的知识不在此处过多探讨)
let:我认为没有变量提升的特性.(有涉及到所谓临时死区的问题详见:[http://es6.ruanyifeng.com/#docs/let])

console.log(a);//undefined
console.log(b);//b is not defined
var a = 3;
let b = 4;
// 声明之后相当于如下代码:
// var a;
// console.log(a);
// console.log(b);
// a = 3;
// let b = 4;

区别3:重复声明

var:重复声明不会报错.
let:在同一作用域内,不允许重复声明同一个变量.const同样也不可以

var a = 3;
var a = 4;
console.log(a);//输出4
let b = 5;
let b = 6;
console.log(b);//'b' has already been declared b已经被声明

区别4:与全局对象之间的关系

var:可以使用window.变量名的方式访问变量
let:let声明的全局变量不是全局对象的属性,它们只存在于一个不可见的块的作用域中,这个块理论上是Web页面中运行的所有JS代码的外层块。

console.log(a);//3
console.log(window.a);//3
let b = 4;
console.log(b);//4
console.log(window.b);//undefined

var声明导致的一些问题

1.变量污染问题

for(var i=0; i < 5; i++) {
    console.log(i);//输出0~4
}
console.log(i)//输出5
//过分的自由导致找bug会很困难
//let就可以放心使用,块内的归块内
//全局的归全局
for(let i=0; i < 5; i++) {
    console.log(i);//输出0~4
}
console.log(i)//i is not defined

2.有关事件队列的一些问题(面试常见的一个类型的问题)

for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);//打印出的都是5,和预期的0~4并不一致
    }, 0);
}
for (let i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);//打印i的值是0~4,符合预期
    }, 0);
}
原理描述:js是单线程的任务执行顺序,setTimeout计时器函数绑定的事件会进入事件队列.而事件队列的的回调函数,会在执行栈(当前代码)执行完才去执行,此处的当前代码指的就是for循环i的自增操作,(靠,好绕!在事件循环中再详述这个问题)
总之一句话:先执行for循环i的自增,再执行定时器绑定的事件.
上面两段代码可以等同于为下面的代码:
var i = 5;
//var定义的i是全局变量,i的地址是不变的
//改变的是地址对应的值,所以setTimeout拿到的值是i最后的值5
//setTimeout打印5遍5
setTimeout(function () {
    console.log(i);
}, 0);
setTimeout(function () {
    console.log(i);
}, 0);
setTimeout(function () {
    console.log(i);
}, 0);
setTimeout(function () {
    console.log(i);
}, 0);
setTimeout(function () {
    console.log(i);
}, 0);
该代码段为伪代码,仅说明原理,无法输出期待值:
//let声明的变量仅在块级作用域内有效
// 第一次循环开始
let i = 0; 
//声明完成了3件事:
//定义一个变量名(i),分配一个地址(系统自行分配),保存了一个值(0)
setTimeout(function () {
    console.log(i);
    //取得本次循环i的值,当然i的自增结束前,不会执行该操作
    //是通过地址得到的值
}, 0);
i++;
//第一次循环结束
//第一次的循环中的i变量名,被销毁,但地址和值还在
//(也是console.log(i)和下一个循环能拿到值的原因)
// 第二次循环开始
// 声明一个新的i变量,分配一个新地址,保存了一个新值(1)
setTimeout(function () {
    console.log(i);
}, 0);
i++;
// 第二次循环结束
...

总结:let是比var更好的变量声明方式,es6中var的使用频率已经降低了很多.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值