简记var、let、const

本文详细介绍了ES6中的块级作用域、let和const命令,对比了它们与ES5中var的区别。重点阐述了变量提升、函数提升的概念,以及在for循环中的使用差异。let和const的出现解决了变量污染和闭包问题,提高了代码的可读性和安全性。同时,还讨论了let如何解决变量提升和函数提升的问题,以及const对于对象属性的特殊性。
摘要由CSDN通过智能技术生成

ES5中只有全局作用域和函数作用域。(造成:内层变量可能会覆盖外层变量;用来计数的循环变量泄漏为全局变量)
ES6中新增了块级作用域、let命令和const命令。一对{}即为一个块级作用域。

1.变量提升

只有var才有变量提升。var只有全局作用域和函数作用域,变量提升是指将变量声明提升到它所在作用域的最开始部分。即可以在变量声明之前使用该变量,但是只有变量声明被提升,赋值不会。

console.log(person);//undefined
var person = 'tom';
console.log(person);//tom

上面代码相当于

var person;
console.log(person);
person='tom';
console.log(person);

2.函数提升

函数创建有两种方式:1.函数声明方式;2.函数字面量方式。
只有函数声明方式才有函数提升

//函数声明方式
function person(){

}
//函数字面量方式
var person = function(){

}

函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被变量赋值后覆盖

console.log(person)
console.log(person())
function person(){
    console.log('tom')
}
var person = 'jack';
console.log(person)

相当于:

function person(){
    console.log('tom')
}
var person;
console.log(person)
console.log(person())
person='jack';
console.log(person)

//打印出:
//1.ƒ person(){console.log('tom')}
//2.tom
//3.undefined;如果函数没有返回值,默认为undefined
//1.jack

3.let、const

let和const不能变量提升,它们只有块级作用域。
同一作用域下面let和const不能声明同名变量,但是var可以。
const声明的时候必须赋值,而且赋值之后不能修改。
但是,const定义的对象属性是可以改变的!!
因为对象是引用类型,const定义的变量保存的仅仅是对象的指针,它只保证指针不发生改变,修改里面的属性不影响到指针,所以是允许的。
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

4.for循环下的var、let声明变量方式区别

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

以上代码如果用var声明变量,最终输出结果为10。

因为首先for循环是瞬间执行,执行的特别快,而且这里的i是全局变量,进行了变量提升,所以等for循环执行完的时候全局变量i的值为10(for循环中声明了十个a[0]~a[9]字面量声明的函数),所以最后输出的值就为10。

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

虽然for循环是瞬间执行,但是let声明的变量只在块级作用域内有效,所以每次循环的{}中的变量i都不是同一个,所以最终输出的是6。
上面let代码可以理解为:

var a = [];
for (let i = 0; i < 10; i++) {
  let j=i;
  a[j] = function () {
    console.log(j);
  };
}
a[6](); // 6

注:for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域(同一个作用域不可使用 let 重复声明同一个变量)。

let可以解决闭包问题。
例如,想要对点击列表进行操作,需要循环列表并给每一个li绑定点击函数,但是如果用var声明变量去进行循环,最后无论点击哪一个li,都是作用于最后一个li,可以用自执函数和闭包去解决这个问题。因为每个自执函数都返回了自己的i值,在循环过后,如果自执函数里面有事件,就在事件被触发的时候把自己保存要返回的i传递出来。

<ul>
            <li>aa</li>
            <li>bb</li>
            <li>cc</li>
            <li>dd</li>
            <li>ee</li>
        </ul>
var aa = document.getElementsByTagName('li');
for (var i = 0; i < aa.length; i++) {
    aa[i].onclick = (function (){
        var index=i;
        return function(){
            alert(index)
        }
    }())
}

但是可以直接使用let就可以轻松避免闭包问题。

var aa = document.getElementsByTagName('li');
for (let i = 0; i < aa.length; i++) {
    aa[i].onclick = function (){
            alert(i)
    }
}

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
const同样存在暂时性死区,只能在声明的位置后面使用。

ES5 只有两种声明变量的方法:var命令和function命令。ES6 除了添加let和const命令,后面章节还会提到,另外两种声明变量的方法:import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。
var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

var a = 1;
window.a // 1

let b = 1;
window.b // undefined
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值