zoukankan      html  css  js  c++  java
  • let & const 命令

    一、let命令

    用于声明变量。

    1) 所声明的变量只在let命令所在代码块内有效。(块级作用域

    {
        let a=10;
        var b=1;
    }
    a // ReferenceError: a is not defined
    b // 1
    var li=document.getElementsByTagName("li");
    for(let i=0;i<li.length;i++){
        li[i].addEventListener("click",function(){
            console.log(i+1);
        })
    }

    在上面的代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i都是一个新变量,于是最后输出的是6。这样每个li元素输出的都是不一样的值,比如第一个li单击会输出1,第二个li单击会输出2,第三个li单击会输出3... 

    2) 不存在变量提升

    let不像var那样会发生“变量提升”现象。所以变量一定要在声明后使用,否则报错。

    console.log(foo); // ReferenceError
    let foo=2; 
    
    console.log(bar); // undefined
    var bar=2;

     所以typeof不再是一个百分之百安全的操作了。

    typeof x; // ReferenceError
    let x;

    3) 暂时性死区

    只要块级作用域内存在let命令,它所声明的变量就“绑定”到这个区域,不再受外部的影响。ES6明确规定,如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。只要在声明之前就使用这些变量,就会报错。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上称为“暂时性死区”(TDZ)。

    if(true){
        // TDZ开始
        temp="abc"; // ReferenceError
        console.log(temp); // ReferenceError
        
        let temp;  // TDZ结束
        console.log(temp); // undefined
        
        temp=123;
        console.log(temp); // 123
    }

     有些死区比较隐蔽,不太容易发现。

    function bar(x=y,y=2){
        return [x,y];
    }
    bar(); // 报错

     调用bar函数报错,是因为参数x的默认值等于另一个参数y,而此时y还没有声明,属于死区。

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

    4) 不允许重复声明

    let不允许在相同的作用域内重复声明同一个变量。

    function func(){ // 报错重复声明变量
        let a=10;
        var a=1;
    }
    
    function func(arg){
        let arg; // 报错,重复声明变量
    }
    
    function func(arg){ // 不报错
        {
            let arg;
        }
    }

     二、块级作用域

     let实际上为javascript新增了块级作用域。

    function f1(){
        let n=5;
        if(true){
            let n=10;
        }
        console.log(n); // 5
    }

    上面的函数有两个代码块,都声明了变量n,运行后输出5.这表示外层代码块不受内层代码块的影响。

    ES6允许块级作用域任意嵌套。外层作用域无法读取内层作用域的变量。内层作用域可以定义外层作用域的同名变量。

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

    function f(){console.log('I am outside');}
    (function(){
       if(false){
           function f(){console.log('I am inside');}
       }
       f();
    }());

    上面的代码在ES5中运行,会得到I am inside(函数变量提升)。但是在ES6中运行会得到I am outside。不管会不会进入if代码块,其内部声明的函数皆不会影响到作用域的外部。

    {
        let a='secret';
        function f(){
            return a;
        }
    }
    f()  // 报错

    块级作用域外部无法调用块级作用域内部定义的函数。如果确实需要调用,则要像下面这样处理

    let f;
    {
        let a='secret';
        f=function(){
            return a;
        }
    }
    f() // secret

     如果在严格模式下,函数只能在顶层作用域和函数内声明,其他情况(比如if代码块,循环代码块)下的声明都会报错

    三、const命令

    const用来声明常量。一旦声明,其值就不能改变。const一旦声明常量,就必须立即初始化,不能留到以后赋值,只声明不赋值就会报错。

    const PI=3.14;
    PI // 3.14
    PI=3; // TypeError:"PI" is read-only

     const作用域与let命令相同:只在声明所在的块级作用域内有效。const命令声明的常量也不能提升,同样存在暂时性死区,只能在声明后使用。并且不能重复声明常量。

    对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。

    const foo={};
    foo.prop=123;
    foo={} // TypeError:"foo" is read-only

    上面的代码中,常量foo储存的是一个地址,指向一个对象。不可变的只是这个地址,既不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

    const a=[];
    a.push("Hello"); // 可执行
    a.length=0;  // 可执行
    a=["Dave"]; // 报错

    如果真的想将对象冻结,应该使用Object.freeze方法。

    const foo=Object.freeze({});
    foo.prop=123; // 不起作用

    上面的代码中,常量foo指向一个冻结的对象,所以添加新属性不起作用。除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

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

    ES6有6种声明变量的方法: var function let const import class

    跨模块常量

    上面说过,const声明的常量只在当前代码块有效。如果想设置跨模块的常量,可以采用下面的写法:

    // constants.js 模块
    export const A=1;
    export const B=3;
    export const C=4;
    
    // test1.js
    import * as constants from './constants';
    console.log(constants.A);  // 1
    console.log(constants.B);  // 3
    
    // test2.js
    import {A,B} from './constants';
    console.log(A); // 1
    console.log(B); // 3

    四、全局对象的属性

    全局对象是最顶层的对象,在浏览器环境指的是window对象,在Node.js中指的是global对象。

    ES6规定var 命令和function命令声明的全局变量依旧是全局对象的属性let命令、const命令和class命令声明的全局变量不属于全局对象的属性

    window.a=1;
    a; //1
     
    a=2;
    window.a //2
    
    let b=1;
    window.b // undefined
  • 相关阅读:
    Nginx在linux环境下(centos7)的安装、负载均衡设置
    ocr识别开源软件tesseract试用记录
    Nginx在windows环境下的安装、负载均衡设置
    一个测试程序迭代的故事05
    一个测试程序迭代的故事04
    一个测试程序迭代的故事03
    一个测试程序迭代的故事02
    一个测试程序迭代的故事01
    Delphi5和Delphi7属性编辑器内存泄漏问题的解决
    使用Calibre自带工具批量转换电子书格式
  • 原文地址:https://www.cnblogs.com/YangqinCao/p/6082819.html
Copyright © 2011-2022 走看看