《es6标准入门》学习笔记-第二章 let和const命令

来源:互联网 发布:淘宝格子铺怎么入驻 编辑:程序博客网 时间:2024/04/30 21:18

以下内容使用的书籍为《es6标准入门-第2版》,阮一峰著,如有需要请购买正版
本文仅为个人读书笔记,如有不详之处请查阅原文

es5提供了var 和function两种变量声明方法,在es6中提供了额外的4中声明方法,分别为let,const,import,class,本章将讲述let和const两种

    • let
      • 基本用法
        • 不存在变量提升
        • 暂时性死区TDZ
        • 不允许重复声明
    • 块级作用域
      • 为什么要有块级作用域
      • ES6的块级作用域
    • const
      • 基本用法
      • 对象和数组
    • 跨模块常量
    • 全局对象的属性

let

基本用法

let仅在所在的代码块内有效(即被{}包裹的区间内)

{    let a=1;    var b=1;}a //ReferenceError: a is not definedb //1

for循环的计数器就很适合let

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

let仅在本轮循环中有效,相当于每次循环都是一个新的变量

不存在变量提升

typeof x;let x=1;

这将抛出一个ReferenceError异常,因为let不存在变量提升,所以变量一定要在声明之后使用。

暂时性死区(TDZ)

只要区块作用域中存在let命令,那么它声明的变量就跟这个区块绑定了,不再受外部影响

var tmp="test it";if(true){    tmp="abc"; //ReferenceError    let tmp;}

如果区块中存在let和const命令,则这个区块对这些声明变量从一开始就形成封闭作用域,只要在声明之前使用这个变量就会报错。使用let命令声明变量之前,该变量都不可以使用,这在语法上被称为“暂时性死区”(temporal dead zone,简称TDZ),所有在let生命变量之前使用该变量的区域都称为该变量的死区

有些死区比较隐蔽

function bar(x=y,y=1){    return [x,y]}bar();

这里会抛出ReferenceError,而不是返回[undefind,1]

不允许重复声明

let不允许在相同作用域内重复声明

function bar(){    let a=1;    let a=10;}//Identifier 'a' has already been declared

同样,不能在函数内部重复声明参数

function bar(a){    let a=1;    // Identifier 'a' has already been declared}function bar2(a){    {        let a=1;        // 不会报错    }}

块级作用域

为什么要有块级作用域

避免变量提升导致的内部变量覆盖外部变量

var tmp=new Date();function f(){    console.log(tmp);    if(true){            var tmp=12          }}f()//undefined

避免计数器的循环变量泄露为全局变量

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

ES6的块级作用域

let为ES6增加了块级作用域
ES6允许块级作用域任意嵌套

{{{{{{{let insane="hello word"}}}}}}}

外层作用域无法读取内层作用域的变量

{{{{{{    {let insane="hello word"}    console.log(insane)//insane is not defined    }}}}}}

内层作用域可以定义外层作用域的同名变量

{{{{{{    let insane="outside"    {    let insane="inside"    console.log(insane)//inside    }    console.log(insane)//outside    }}}}}}

函数本身的作用域在其所在的区块级作用域之内

function f(){    console.log('I am outside')}(function(){    if(false){        function f(){            console.log('I am inside')        }    }    f();})();//es5显示inside,es6显示outside

const

基本用法

const用来声明常量,一旦声明,其值就不能改变

const Pi=3.1415926console.log(Pi)//3.1415926Pi=3;//TypeError: Assignment to constant variable

const一旦声明就必须赋值

const a;//SyntaxError: Missing initializer in const declaration
  • const的作用域和let一样,只在块级作用域有效
  • const不存在变量提升,同样存在死区
  • const也不能重复声明
    以上示例参照let

对象和数组

const可以声明一个数组或者对象类型的变量,并且其值是可写的,但是不能重新赋值

const a=[];a.push(1);console.log(a);//[1]a=[];//TypeError: Assignment to constant variable.
const a={}a.b=3console.log(a);//{b:3}a={}//TypeError: Assignment to constant variable.
var b={c:1}const a=ba.c=2;console.log(a);//{c:2}console.log(b);//{c:2}a={}//TypeError: Assignment to constant variable.

如果希望a的所有属性都不可写,可以使用Object的freeze方法,将对象冻结

const foo=Object.freeze({});foo.prop=1;console.log(foo);//{}

上面的代码将foo指向一个冻结对象,所以新增属性不起作用
除了对象本身冻结,对象的属性也应该冻结,下面是一个将对象彻底冻结的函数
比部分用了其它的es6内容,可在看完后面的部分后,再回来看

var constantize=(obj)=>{    Object.freeze(obj);    Object.keys(obj).forEach((key,value)=>{        if( typeof obj[key] === 'object'){            constantize(obj[key]);        }    })  }

跨模块常量

const只对当前块级作用域有效,以下可以设置跨模块常量

//constants.jsexport const A=1;export const B=2;export const C=3;
//test1.jsimport * as constants from './constants';console.log(constants.A)//1console.log(constants.B)//2
//test2.jsimport {A,B} as constants from './constants';console.log(A//1console.log(B)//2

全局对象的属性

浏览器中的全局对象为window,node中的全局对象为global
在ES5中,全局对象的属性和全局变量是等价的
ES6中var和function声明的全局变量依旧是全局对象的属性,而let const class声明的全局变量不属于全局对象的属性

var a=1;//如果是node则下面为global.aconsole.log(window.a)//1let b=1;console.log(window.b)//undefinedwindow.b=2;//Identifier 'b' has already been declaredconsole.log(b)//1console.log(window.b)//2
0 0
原创粉丝点击