ES6教程学习(一)--let和const命令

96 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

let命令

基本用法

let所声明的变量,只在let所在的代码块内有效

{
    let a = 1
    var b = 2
}
console.log(b); // 2
console.log(i); // Uncaught ReferenceError: i is not defined
for(let i = 0; i < 5; i++){
   console.log(i); // 0 1 2 3 4
}
console.log(i);//Uncaught ReferenceError: i is not defined

不存在变量提升

var存在变量提升,var声明的变量,在声明之前调用时undefined;let不存在变量提升,不能在声明之前调用它

console.log(a) //undefined
var a = 1

console.log(b) //Cannot access 'b' before initialization
let b = 2

暂时性死区

只要块级作用域内存在let命令,他所声明的变量就被绑定了,这个区域就不再受外界的影响

let a = 3
			
if(true){
        console.log(a) //3
}
let a = 3
			
if(true){
        console.log(a) //Cannot access 'a' before initialization
        let a
}

ES6明确规定,如果区块内存在let或者const命令,这个区块对这些命令声明的变量,从一开始就会形成封闭作用域。凡是在声明这些变量之前使用,就会报错。在代码块内,在声明之前,这些变量都是不可用的,在语法上称为暂时性死区。

let tmp = 1;
    if(true){
        tmp='123'
        console.log(tmp)//会报错 Cannot access 'tmp' before initialization
        let tmp; //以上都是死区,现在暂时性死区结束
        tmp = 'abc';
        console.log(tmp)//abc
        tmp='def'
        console.log(tmp)//def
    }

typeof

console.log(typeof a);// Cannot access 'aa' before initialization
let a = 1

console.log(typeof b); //undefined
var b = 2

隐蔽的暂时性死区

function handler(x=y,y=2){
    return [x,y]
}
handler() //Cannot access 'y' before initialization

反之
function handler(x=y,y=2){
        return [x,y]
}
console.log(handler(1)) //1
let a = a //Cannot access 'x' before initialization

var b = b //不报错

暂时性死区的本质:只要已进入当前作用域,所要使用的变量就已经存在了,但是不是可以获取,只有等到声明变量的那一行出现,才可以获取和使用该变量。

不允许重复声明

function func(){
        let a = 1
        let a = 2
}
//Identifier 'a' has already been declared

function func(){
        let a = 1
        var a = 2
}
// Identifier 'a' has already been declared 

不允许声明函数参数

function func(arg){
        let arg = 1
}
//Identifier 'arg' has already been declared 

function func(arg){
        {
                let arg = 2
        }
}
//不报错

块级作用域

为何需要快捷作用域?

ES5只用全局作用域和函数作用域,没有块级作用域

var a = 1
function func(){
        console.log(a)
        if(false){
                var a = 2
        }
}
func() //undefined(false里边的a变量提升导致)

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

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

ES6的快捷作用域

function func(){
        let a = 1
        if(true){
                let a = 2
        }
        console.log(a)
}
func()//1

//允许作用域的任意嵌套,每一层都是单独的作用域,外界访问不到

{{{
        let a = 1
        {
                console.log(a)//1
                let b = 2
        }
}}}

//访问它下一层会报错
{{{
        let a = 1
        console.log(b)//b is not defined
        {
                let b = 2
        }
}}}

//在不同作用域内也可以重名
{{{
        let a = 1
        {
                let a = 2
        }
}}}

块级作用域和函数声明

ES5规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域中声明,浏览器没有此规定

function fn() {
        console.log('我在外边')
}
(function() {
        if (false) {
                        function fn() {
                                console.log('我在里边')
                        }
                }
                fn() //fn is not a function
        }()
);

避免在块级作用域中声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

//块级作用域内部的函数声明语句,建议不要使用
{
        let a = 1
        function b(){
                return a;
        }
}
//块级作用域内部,建议使用函数表达式

{
        let c = 1
        let d = function(){
                return c;
        }
}

注意:ES6快捷作用域必须有大括号,如果没有大括号,js引擎会认为不存在块级作用域

if(true) let a = 1  //Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context (

//不报错
if(true){
   let b = 2
}

函数声明也是如此,严格模式下,函数声明只能在当前作用域的顶层

// 不报错
"use strict"
if(true){
        function fn(){}
}

// 报错
"use strict"
if(true)
        function fn(){}
//  In strict mode code, functions can only be declared at top level or inside a block. 

const命令

const声明一个只读的常量,一旦声明,常量的值就不能改变了。

const a = 1
a = 2
//Uncaught TypeError: Assignment to constant variable.

const只声明,不赋值会报错。const一旦声明变量,就立即初始化,不能留到以后赋值

const a;//Uncaught SyntaxError: Missing initializer in const declaration 

const只在所声明的代码块内有效

{
   let a = 1
}
console.log(a); //aa.html:14 Uncaught ReferenceError: a is not defined

const不存在变量提升

{
    console.log(a);//Uncaught ReferenceError: Cannot access 'a' before initialization
    a = 1
}

const也不能重复声明

const a = 1
const a = 2
//Uncaught SyntaxError: Identifier 'a' has already been declared

const保证的并不是变能被改变,而是变量指向的那个内存地址所保存的数据不能被改动。对于简单的数据类型,值就保存在变量指向的那个内存地址,因此等同于常量。对于符合类型的数据(主要是数组和对象),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针的固定的(指向固定的地址),至于他指向的数据结构是不是变化的,就完全不可控制的,因此,用const声明一个对象或者数组需注意。

const a = {}
a.name="a"
a = {}//aa.html:13 Uncaught TypeError: Assignment to constant variable.

const a = []
a[0] = 1
a = [] //Uncaught TypeError: Assignment to constant variable.

可使用Object.freeze来冻结对象或者数组,常规模式下没有错误,严格模式下会报错

let a = Object.freeze([1])
a[0] = 2
console.log(a)//[1]

"use strict"
let a = Object.freeze([1])
a[0] = 2
console.log(a)//[1] Uncaught TypeError: Cannot assign to read only property '0' of object '[object Array]'

将对象彻底冻结

function frozenHandler(obj){
    Object.freeze(obj)
    Object.keys(obj).forEach(res => {
            if(typeof obj[res] === 'object){
                    frozenHandler(obj[res])
            }
    })
}

声明变量的六种方法

let fonst function var class import

顶层对象的属性

顶层对象,在浏览器中指的是window对象,在NodeJS中指的是global对象,在ES5中顶层对象和全局对象是等价的

window.a = 1
a = 2
console.log(window.a) //2

在ES6中,var和function声明的变量依旧是全局变量,依旧是顶层对象的属性。let、const、class声明的全局变量不属于顶层变量。

window.a = 1
let a  = 2
console.log(window.a) //1

globalThis顶层对象

JS语言中存在一个顶层对象,他提供全局环境(即全局作用域),所有代码都在这个环境中运行,但是顶层变量与各个环境不统一 浏览器---window web worker----self Node ---global

ES2020,将global引入,作为顶层对象。任何环境下,globalThis都是存在的,任何环境下,都可以从他拿到顶层对象,指向全局环境的this.