ES6 学习笔记(一)let、const与作用域

2023-03-04 16:45:52 浏览数 (2)

本文最后更新于 128 天前,其中的信息可能已经有所发展或是发生改变。

一、let命令

1.1用法

1.1.1 let类似于var,但所声明的变量只在let命令所在的代码块有效。

如:

代码语言:javascript复制
{
    let a = 10
    var b = 20
}
console.log(b)
console.log(a)

输出结果: 20 D:codeWorkspaceJS_projectstest21.js:10 console.log(a) ^ ReferenceError: a is not defined

1.1.2 for循环中的变量计数器很适合使用let命令

代码语言:javascript复制
for (var i = 0; i < 3; i  ) {
    console.log(1, i)
}
console.log(2, i)

输出结果: 1 0 1 1 1 2 2 3

代码语言:javascript复制
for (let j = 0; j < 3; j  ) {
    console.log(1, j)
}
console.log(2, j)

输出结果: 1 0 1 1 1 2 D:codeWorkspaceJS_projectstest21.js:21 console.log(2, j) ^ ReferenceError: j is not defined

1.1.3 for循环在设置循环变量的部分是一个父作用域,循环体内部又是一个独立的子作用域。

如:

代码语言:javascript复制
for (let i = 0; i < 3; i  ) {
    let i = 'abc'
    console.log(i)
}

运行结果: abc abc abc

1.2 变量提升

var声明的变量无论其实际声明位置在何处,都会被是为声明于所在函数(或全局)的顶部,这就是变量提升 如:

代码语言:javascript复制
function fn() {
    console.log(a);
}
var a = 100;
fn() // 100

1.3 暂时性死区

看如下代码:

代码语言:javascript复制
var temp = 123456;
if (true) {
    temp = 'abc';
    let temp;
}

输出结果是: temp = ‘abc’; ^ ReferenceError: temp is not defined

ES6明确规定,如果区块中存在let或const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。在代码块内,使用let命令声明变量之前,该变量都是不可用的,这个区域被称为“暂时性死区”。

1.4 不允许重复声明

如:

代码语言:javascript复制
let a=10;
let a=1;
console.log(a)
// Identifier 'a' has already been declared
代码语言:javascript复制
var a=10;
let a=1;
console.log(a)
// Identifier 'a' has already been declared
代码语言:javascript复制
let a=10;
var a=1;
console.log(a)
// Identifier 'a' has already been declared

二、作用域

变量或函数在起作用的区域。 JavaScript采用的是“词法作用域”,即在变量作用域取决于变量所在的代码区域。 ES6中新增了“块作用域”,也包含了ES5中的“全局作用域”和“函数作用域”。 作用域分为全局作用域、函数作用域和块作用域。

2.1 作用域分类

在所有函数之外定义的变量拥有全局作用域,该变量为全局变量。

全局作用域 全局变量可以在当前页面中任何JavaScript代码中访问。

函数作用域: 在函数中声明的变量(包括函数参数)指定在其所声明的函数内被访问。

块作用域: 由{ }界定的代码区域,let声明的变量具备可访问块作用域

作用域实例:

代码语言:javascript复制
var a = 105
function f1(){
    var a = 100
    let b = 200
    function f2(){
        let c = 100
        console.log(a,b,c) // 100 200 100
    }
    f2()
    console.log(a,b) // 100 200
    console.log(c) // ReferenceError: c is not defined
}
f1() 

2.2 作用域链

每一段JavaScript代码(全局代码或函数)都有一个与之关联的作用域链 当JavaScript查找变量x的时候( 变量解析),会从当前作用域开始跟随作用域链向上查找,直到找到x变量的声明,若到达全局作用域中仍未找到,则抛出一个引用错误(ReferenceError)异常。

2.3 ES5可能出现的问题

由于ES5只有全局作用域和函数作用域两种作用域,可能会出现下面的问题。

2.3.1 内层变量可能会覆盖外层变量

代码语言:javascript复制
var tmp = new Date();
function f() {
    console.log(tmp);
    if (false) {
        var tmp = 'hello';
    }
}
f(); 
输出结果:
undefined

2.3.2 用来计数的循环变量泄露为全局变量

代码语言:javascript复制
var s='hello';
for(var i=0;i<s.length;i  ){
    console.log(s[i]);
}
console.log(i);
输出结果:
h
e
l
l
o
5

2.4 let为JavaScript新增了块级作用域

代码语言:javascript复制
function fl() {
    let n = 5;
    if (true) {
        let n = 10;
    }
    console.log(n);
}
fl(); //5

ES6允许块级作用域任意嵌套,一对{}即为一个块级作用域。 内层作用域可以定义与外层作用域同名变量。 块级作用域的出现使得ES5中惯用的IIFE(立即执行匿名函数)不再必要了。

三、const命令

3.1 基本用法

声明一个只读的常量,一旦声明,其值不能改变且必须立即初始化。除此之外,与let用法一致。 实例:

代码语言:javascript复制
const foo={y:10};
foo.x=100;
console.log(foo.x); // 100
foo={n:1000};
console.log(foo) // Assignment to constant variable.

当常量保存的不是一个值,而是一个地址的时候,该常量所引用的对象是可以更改成员的,只是不能更改该常量保存的地址。

3.2 顶层对象

顶层对象在浏览器环境指的是window,在Node中指的是global对象 var定义的变量会关联到顶层对象中,let和const不会。

四、小结

ES6一方面新增了let和const命令所声明的全局变量不属于顶层对象属性,另一方面也允许var和function命令声明的全局变量依旧是顶层对象的属性。 ES6为ES5提供了良好的兼容性。 由于let和const能提供更好的作用域识别,所以尽量采用let声明变量,const声明常量。

0 人点赞