2019年1月21日 周一

本文深入探讨了ES6中let和const命令的特性,包括它们如何引入块级作用域、变量提升、暂时性死区、重复声明的限制,以及const的只读特性。同时,文章也介绍了ES6中变量解构赋值的用法,包括数组和对象的解构,以及顶层对象属性的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

let命令

(1)for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

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

(2)不存在变量提升

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
​
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
​

(3)暂时性死区

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

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

解释:存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错。

如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错 。

在没有let之前,typeof运算符是百分之百安全的,永远不会报错。

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError
​
  let tmp; // TDZ结束
  console.log(tmp); // undefined
​
  tmp = 123;
  console.log(tmp); // 123
}
// 不报错
var x = x;
​
// 报错
let x = x;
// ReferenceError: x is not defined

解释:使用let声明变量时,只要变量在还没有声明完成前使用,就会报错。上面这行就属于这个情况,在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。

(4)let不允许在相同作用域中,重复声明一个变量

(5)let实际上为 JavaScript 新增了块级作用域:可以不再使用闭包的写法,允许在块级作用域内声明函数

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

注:上述代码中的变量n如果使用var进行声明,结果应该为10,因为ES5中只有全局作用域和函数作用域,没有块级作用域,块级作用域外层不受内层的影响。

ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

function f() { console.log('I am outside!'); }
​
(function () {
  if (false) {
    // 重复声明一次函数f
    function f() { console.log('I am inside!'); }
  }
​
  f();
}());
​

注:ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

const命令

(1)const是一个只读常量,一旦声明,其值就不能改变,也就是说const变量一经声明就应该立刻初始化,不然就会报错。

(2)通let一样,只能在块级作用域内使用,先声明后使用,也不可重复声明。

if (true) {
  const MAX = 5;
}
​
MAX // Uncaught ReferenceError: MAX is not defined

(3)本质:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。

(4)对象冻结,应该使用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] );
    }
  });
};

ES6的6中声明变量的方法

var function let const import class

顶层对象的属性

(1)顶层对象的属性与全局变量挂钩,被认为是 JavaScript 语言最大的设计败笔之一。

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1
​
let b = 1;
window.b // undefined

上面代码中,全局变量avar命令声明,所以它是顶层对象的属性;全局变量blet命令声明,所以它不是顶层对象的属性,返回undefined

(2)很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。

// 方法一
(typeof window !== 'undefined'
   ? window
   : (typeof process === 'object' &&
      typeof require === 'function' &&
      typeof global === 'object')
     ? global
     : this);
​
// 方法二
var getGlobal = function () {
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('unable to locate global object');
};

变量的解构赋值

(1)数组的解构赋值

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
​
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
​
let [x, , y] = [1, 2, 3];
x // 1
y // 3
​
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
​
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

如果解构不成功,变量的值就是undefined

Set 结构,也可以使用数组的解构赋值。

let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"

(2)对象的解构赋值

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
​
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

如果变量名与属性名不一致,必须写成下面这样。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
​
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

上述例子中foo是匹配模式,baz才是变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值