ES6学习笔记之let和const

let

ES6 新增了let命令,不同于var,只在let命令所在的代码块内有效。比如:

{
    
    
  let a = 10;
  var b = 1;
}
a // ReferenceError: a is not defined.
b // 1

在代码块外a就是未声明的。

所以for循环计数器就很适合使用let。

不存在变量提升

var命令会发生“变量提升”,即变量可以在声明之前使用,值为undefined。

console.log(foo); // 输出undefined
var foo = 2;

这其实很奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。

为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

console.log(bar); // 报错ReferenceError
let bar = 2;

在let声明前变量是不存在的,所以使用就会报错。

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。如

var tmp = 123;
if (true) {
    
    
  tmp = 'abc'; // ReferenceError
  let tmp;
}

因为在语句块中let又声明了一个tmp,导致后者绑定这个块作用域,所以在let之前使用tmp就会报错。

这种情况,即在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。

typeof x; // ReferenceError
let x;

而如果一个变量根本没有被声明,那么typeof反而不会报错。

typeof undeclared_variable // "undefined"

undeclared_variable变量就是不存在,结果是undefined。

注意一些隐藏性的死区,如:

function bar(x = y, y = 2) {
    
    
    ...
}

因为参数y在后面,所以x=y的时候还未声明,另外一个情况是:

let x = x;

同样x还未声明完就去获取x的值,这时候x是未定义的,但是用var就不会用报错

var x = x;

不允许重复声明

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

function func() {
    
    
  let a = 10;
  let a = 1;
}

这样就会报错,因此,也不能在函数内部重新声明参数。

function func(arg) {
  let arg;
}
func() // 报错

const

const声明的是常量,所以声明的同时必须初始化。与let相同只在块级作用域中有效,同样不能提升、存在暂时性死区、不可重复声明。

const如果声明的是对象,那么地址指向不会变,但是对象本身是可变的,比如添加属性。如果想将对象冻结,则需要使用Object.freeze,如下:

const foo = Object.freeze({
    
    });
// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

如果想将对象的属性也冻结,下面是一个将对象彻底冻结的函数。

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

顶层对象

ES5 之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a = 2;
window.a // 2

这样的设计带来了几个很大的问题,首先是没法在编译时就报出变量未声明的错误;其次,很容易不知不觉地就创建了全局变量;最后,顶层对象的属性是到处可以读写的,不利于模块化编程。

ES6改变这一点,同时为了保持兼容性,var和function声明的全局变量,依旧是顶层对象的属性;而let、const、class声明的全局变量,不属于顶层对象的属性。

var a = 1;
window.a // 1
let b = 1;
window.b // undefined

顶层对象还有一个问题,就是在各种实现中是不统一的,比如在浏览器中是window、在node中是global等等。有一个方法是使用this变量,但是也有局限性,比如在node和ES6环境中this返回的是当前模块。针对很难找到一种方法在所有情况下都获取到顶层对象,ES2020在语言标准的层面,引入globalThis作为顶层对象。也就是说,任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指向全局环境下的this。

关注公众号:BennuCTech,获取更多干货!

猜你喜欢

转载自blog.csdn.net/chzphoenix/article/details/125096229