• let和const


    1. let命令


    let命令声明的变量只在所在的代码块中有效。for循环中很适合使用let,如果使用var则会创建一个全局变量,且for循环中声明的函数如果涉及i,指向的是同一个i值。在循环外调用永远是同一个值。

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

    如果使用let的话,每一次循环中的i都是一个由let重新声明的新变量。上面这个例子如果使用let,最后的输出会是6。之所以能有这样的效果,是因为JavaScript引擎内部会记住上一轮循环的值,从而在上一轮的基础上初始化本轮的值。

    另外,在for循环中,设置循环变量的部分是一个父作用域,而循环体是一个单独的子作用域。这意味着可以在循环体内用let单独声明i,并且与循环变量没有影响。

    此外,let还有三个重要的特性:

    • 不存在变量提升:var有着变量提升的特点,在声明之前使用变量,值为undefined。但let在声明前使用会直接报错。
    • 暂时性死区(TDZ):只要块级作用域中存在let命令,那么这个声明就“绑定”了这个区域。哪怕这个变量已经有同名的全局变量被声明。在声明语句出现之前,这个变量都是存在但不可以使用的,如果使用则会报错。因此typeof运算符也不再是绝对安全的操作了。
    • 不允许重复声明:不允许在相同作用域内重复声明一个变量,也不能在函数内部重新声明参数。

    不存在变量提升和暂时性死区的特性,都是为了减少运行时错误,防止在变量声明前就提前使用这个变量,从而导致意料之外的行为。

    2. 块级作用域


    let实际上为ES6新增了块级作用域。原本使用广泛的匿名立即执行函数表达式不再需要了。

    函数能不能在块级作用域中声明是一个很复杂的问题。ES5规定,函数不能在块级作用域中声明(如if语句中)。而ES6引入了块级作用域,允许在块级作用域中声明函数。行为类似于let,在作用域外不得引用。

    但在ES6浏览器中,为了减轻兼容带来的问题,允许浏览器有自己的行为方式。ES6浏览器会将函数声明提升到全局作用域或函数作用域头部,以及所在块级作用域的头部,所以在ES6浏览器环境下,函数声明是会报错的。

    // 浏览器的 ES6 环境
    function f() { console.log('I am outside!'); }
    
    (function () {
    	//var f = undefined;   实际上函数声明被提升到了块级作用域的头部
      if (false) {
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    // Uncaught TypeError: f is not a function
    

    由于环境导致的行为差异较大,不推荐在块级作用域中声明函数。如果一定要这么做,建议写成函数表达式的形式。

    另外需要注意,ES6的块级作用域必须用大括号包裹起来,如果没有的话JavaScript引擎不认为存在块级作用域。

    3. const命令


    const用于声明一个只读的常量,声明之后不得更改。这也说明const一旦声明必须立刻初始化,不能留到以后赋值。const与let一样,只在作用域内有效,不存在变量提升,存在暂时性死区,不能重复声明。

    const实际上保证的不是变量的值不能改动,而是变量指向的内存地址所保存的数据不能改动。对于简单数据类型,值就保存在那个内存地址中,所以等同于常量。但对符合类型的数据来说,内存地址中保存的是一个指针,const只能保证这个指针是固定的(指向不能更改),但不能保证它指向的数据结构不发生改变。

    如果真的想要将对象冻结,只能使用 Object.freeza 方法。

    彻底冻结对象,不仅仅要冻结对象本身,还要将对象的属性也全部冻结。具体实现如下:

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

    ES5只有两者变量声明方法:var 和 function 。而ES6有六种,除了这里介绍的 let 和 const,还有import 和 class。

    4. 顶层对象的属性,globalThis对象


    ES5中,顶层对象属性与全局对象是等价的。这样有很多缺点,如无法在编译时就报出变量未声明的错误,只有运行才知道(因为全局变量的可能是顶层对象的属性创造的,而属性的创造是动态的)。

    ES6为了改变这一点,使得 let 和 const 和 class 声明的全局变量不属于顶层对象的属性。

    ES2020引入globalThis对象作为顶层对象,任何环境下他都存在,并且可以指向全局环境的this。

  • 相关阅读:
    Android 监听键盘弹出/隐藏
    js 监听事件的叠加和移除
    如何用 Swift 语言构建一个自定控件
    适用于Web开发人员的20个CSS调色板
    学习Flutter应用开发有用的代码/库/专有技术列表
    学习Java的书籍资料
    可能对Flutter应用程序开发有用的代码/库/专有技术列表
    ios 动画:底部标签栏的概念设计
    iOS 开发者必不可少的 75 个工具
    创建Android Apps的30个经验教训
  • 原文地址:https://www.cnblogs.com/hermionepeng/p/13330955.html
Copyright © 2020-2023  润新知