ECMAScript 6 入门

1.let 和 const 命令

let 命令

基本用法

ES 6 新增了 let 命令,用来声明变量,它的用法类似于 var ,但是,所声明的变量只在 let 命令所在的代码块中有效。

{
var a=10;
let  b=1;

a // ReferenceError: a is not defined.
b // 1
}

这个里面同时用 var 和 let 声明了变量,现在在代码块外调用,let 报错,var正常,这说明 let 只在代码块中有效。

不存在变量提升
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

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

var 发生了变量提升,从脚本开始运行时,foo已经存在了,但是没有值,所以会输出 undefined。let 不会发生变量提升,就说明在运行前,bar 还不存在,这时候用它,会发生错误。

暂时性死区
var tmp = 123;

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

ES6中明确规定,如果区域块中存在 let 和 console ,这些区域块对这些声明的变量从一开始就形成了封闭作用域,凡在声明之前就使用这些,就会报错。所以说明在 let 未声明变量之前,该变量是不可用的。

不允许重复声明

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

// 报错
function func() {
  let a = 10;
  var a = 1;
}

// 报错
function func() {
  let a = 10;
  let a = 1;
}
  • .let 为JavaScript 新增了块级作用域(let所声明的变量只在块级作用域中有用),而ES5 中是没有的。
  • .ES5 规定函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明。而ES6 引入了块级作用域,明确允许在块级作用域中声明函数。但函数声明语句的行为类似于 let ,在块级作用域之外不可引用。而且函数的声明会提升到全局作用域或函数作用域的头部,函数声明还会提升到函数作用域的头部。
// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }

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

  f();
}());
// Uncaught TypeError: f is not a function

这个会报错,因为实际上执行的是下面的代码。
因此,考虑到环境导致的行为差异太大,所以,避免在块级作用域中声明函数。如果确实有需要,应该写成函数表达式,而不是函数声明语句。

// 函数声明语句
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 函数表达式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}

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

const 命令

1.const 声明一个只读的常量,const 的值,一旦声明不能改变。
2.const 声明的变量不得改变值,const 一旦声明变量必须初始化,不能留到后面再赋值,否则会报错。
3.const 所声明的变量与let 相同,只在块级作用域内有效
4.const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

变量的解构赋值

解构:从对象或者数组中提取值,对变量进行赋值。

1.数组的解构赋值

基本用法
  • 1.解构不成功。如果解构不成功,变量的值就等于undefined。
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 // []

这种写法要符合“模式匹配”:只要等号两边的模式相同,左边的变量就会被赋予相应的值。

  • 2.不完全解构。 等号左边的模式,只匹配等号右边的一部分数组,这种情况下解构可以成功。
let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
  • 3.如果等号右边的不是数组就会报错
// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
默认值

解构赋值允许指定默认值,只有当一个数组成员严格等于undefined的时候,默认值才会有效

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null

上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。

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' };
 console.log(baz); //aaa

实际上,对象的解构赋值是下面形式的简写:

let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

也就是说对象的解构赋值,是先找到它的同名属性,然后把值赋给它的变量,真正赋值的是后者而不是前者

      let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
        console.log(baz); //aaa
        console.log(foo); //foo is not defined

对象的嵌套解构

 
      let obj = {
            p: [
                'Hello',
                { y: 'World' }
            ]
        };

        let { p, p: [x, { y }] } = obj;
        console.log(x)   //"hello"
        console.log(y)   //"world"
        console.log(p)   //"hello",{y:"world"}

对象的解构也可以指定默认值

         var { x: y = 3 } = {};
         console.log(x);  // x is not defined
         console.log(y);  //3

         var { x: y = 3 } = { x: 5 };
         console.log(y);  //5

默认值生成的条件是对象的属性值严格等于undefined

var {x = 3} = {x: undefined};
x // 3

var {x = 3} = {x: null};
x // null

如果要将一个已经声明的变量用于解构赋值,必须非常小心

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error


// 正确的写法
let x;
({x} = {x: 1});

3.字符串的解构赋值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容