JavaScript之ES6新特性01

 概述

  ECMAScript 6(简称ES6)是于2015年6月正式发布的JavaScript语言的标准,正式名ECMAScript 2015(ES2015)。它的目标是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言 [。

另外,一些情况下ES6也泛指ES2015及之后的新增特性,虽然之后的版本应当称为ES7、ES8等

为什么学习ES6 

  •  ES6 的版本变动内容最多,具有里程碑意义
  •  ES6 加入许多新的语法特性,编程实现更简单、高效
  •  ES6 是前端发展趋势,就业必备技能 

ES6新特性

 let 关键字 

ES6 新增了 let 命令,用来声明变量。它的用法类似于 var ,但是所声明的变量,只在 let 命令所在的代码块内有效。l使用 let 声明的变量有几个特点:

  1.  不允许重复声明
  2.  块级作用域
  3. 不存在变量提升
  4. 不影响作用域链 
        //声明变量
        let a;
        let b,c,d;
        let e = 10;
        let f = 521, g = 'asd', h = [];

      //1. 变量不能重复声明
        let star = '谭梦寻';
        // let star = '小名';//报错--Cannot redeclare block-scoped variable 

      //2. 块级作用域  全局, 函数, eval
        // if else while for 
        {
            let girl = '小红';
        }
        function f1() {
            let n = 5;
            if (true) {
                let n = 10;
                }
            console.log(n); // 5
        }
        //console.log(girl);//报错--ReferenceError: girl is not defined

      //3. 不存在变量提升
        // console.log(song);//Cannot access 'song' before initialization
        // let song = '恋爱告急';

      //4. 不影响作用域链
        {
            let school = '希望小学';
            function fn(){
                console.log(school);
            }
            fn();//希望小学
        }
暂时性死区: 

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

var tmp = 123
if (true) {
  tmp = 'abc' // ReferenceError: Cannot access 'tmp' before initialization
  let tmp
}

上面代码中,存在全局变量 tmp ,但是块级作用域内 let 又声明了一个局部变量 tmp ,导致后者绑定这个块级作用域,所以在 let 声明变量前,对 tmp 赋值会报错。
        ES6 明确规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,
就会报错。
        总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ) 

 

 let和var对比学习

        var声明的变量全局有效,允许重复声明,存在变量提升(var 命令会发生”变量提升“现象,即变量可以在声明之前使用,值为 undefined )。而let不允许重复声明,存在块级作用域、不存在变量提升、不影响作用域链 。如下:

作用域1:

console.log(b);//输出undefined
var b = 2;//注意 这里不能省,否则报错
var b = 3;
{
  var s2 = "1asd";
}
console.log(s2);//输出 1asd

 作用域2:

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

解释:上面代码中,变量 i 是 var 命令声明的,在全局范围内都有效,所以全局只有一个变量 i 。每一次循环,变量 i 的值都会发生改变,而循环内被赋给数组 a的函数内部的 console.log(i) ,里面的 i 指向的就是全局的 i 。也就是说,所有数组 a 的成员里面的 i ,指向的都是同一个 i ,导致运行时输出的是最后一轮的 i 的值,也就是 10。
如果使用 let ,声明的变量仅在块级作用域内有效,最后输出的是 6 

变量注意:

        ECMAScript的变量是松散型的,即可以用来保存任何类型的数据。如下:

let c = 3;
c = "asd";
console.log(c)//输出asd

 const 关键字 

        const 声明一个只读的常量。一旦声明,常量的值就不能改变。

const 声明有以下特点: 
  • 声明必须赋初始值
  • 标识符一般为大写
  • 不允许重复声明
  • 值不允许修改
  • 块儿级作用域

注意: 对象属性修改和数组元素变化不会发生 const 错误
应用场景:声明对象类型使用 const,非对象类型声明选择 let 

例子: 值不允许修改

const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.

上面代码表明改变常量的值会报错。const 声明的变量不得改变值,这意味着, const 一旦声明变量,就必须立即初始化,不能留到以后赋值 。

声明必须赋初始值 

const f;
// SyntaxError: Missing initializer in const declaration

const 的作用域与 let 命令相同:只在声明所在的块级作用域内有效 

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

const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

var tmp = 123
if (true) {
  tmp = 'abc' 
  const tmp;//SyntaxError: Missing initializer in const declaration
}

const 声明的常量,也与 let 一样不可重复声明。 

var message = "Hello!";
let age = 25;
// 以下两行都会报错
const message = "Goodbye!";
const age = 30;

对象属性修改和数组元素变化不会发生 const 错误 

const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
const本质 

const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针, const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。

变量解构赋值 

         ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。以前为变量赋值,只能直接指定值。

数组的解构 
const F4 = ['小沈阳', '刘能', '赵四', '宋小宝']
let [xiao, liu, zhao, song] = F4
console.log(xiao)//小沈阳
console.log(liu)//刘能
console.log(zhao)//赵四
console.log(song)//宋小宝

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。 本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。

 数组解构默认值 

        解构赋值允许指定默认值。 

let [foo = true] = [];
console.log(foo); // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
注意事项: 

 只有当一个数组成员严格等于 undefined ,默认值是才会生效的。(ES6 内部使用严格相等运算符( === ),判断一个位置是否有值。)

let [n = 1] = [undefined];
console.log(n); // 1
let [n2 = 1] = [null];
console.log(n2);//null
对象的解构 

        对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。 

const zhao = {
  name: '赵本山',
  age: '不详',
  xiaopin: function () {
    console.log('我可以演小品')
  }
}

let {name, age, xiaopin} = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();

 输出结果:

JavaScript之ES6新特性01_第1张图片

也可以直接通过函数名解构出里面的函数: 

const zhao = {
  name: '赵本山',
  age: '不详',
  xiaopin: function () {
    console.log('我可以演小品')
  }
}


let { xiaopin } = zhao
xiaopin()//我可以演小品

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

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
console.log(baz); // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
console.log(f); // 'hello'
console.log(l); // 'world'
console.log(foo);//foo is not defined

解释:对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。上面代码中, foo 是匹配的模式, baz 才是变量。真正被赋值的是变量 baz ,而不是模式 foo 。

对象解构默认值 

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

// 对象解构默认值
var {x = 3} = {};
console.log(x); // 3
var {x, y = 5} = {x: 1};
console.log(x); // 1
console.log(y); // 5
var {x: y = 3} = {};
console.log(y);// 3
var {x: y = 3} = {x: 5};
console.log(y);// 5
var { message: msg = 'Something went wrong' } = {};
console.log(msg); // "Something went wrong
var {x = 3} = {x: undefined};
console.log(x); // 3
var {x = 3} = {x: null};
console.log(x); // null

如果解构失败 ,变量的值等于 undefined 。

let {foo} = {bar: 'baz'};
console.log(foo); // undefined
注意事项: 

 1、如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

let {
  user: { bar }
} = { baz: 'baz' }
//TypeError: Cannot read properties of undefined (reading 'bar')

 解释:等号左边对象的user属性,对应一个子对象。该子对象的 bar 属性,解构时会报错。原因很简单,因为 foo 这时等于 undefined ,再取子属性就会报错,请看下面的代码。

let _tmp = {baz: 'baz'};
_tmp.foo // undefined
_tmp.foo.bar // 报错

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

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

上面代码的写法会报错,因为 JavaScript 引擎会将 {x} 理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题 

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

字符串解构 

        字符串也可以解构赋值。这是因为字符串被转换成了一个类似数组的对象,且类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值。如下:

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
let {length : len} = 'hello';
len // 5

数值和布尔值的解构赋值 

         

function add([x, y]){
return x + y;
}
add([1, 2]); // 3

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错。

let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true

函数参数的解构赋值 

        函数的参数也可以使用解构赋值

function add([x, y]){
return x + y;
}
add([1, 2]); // 3

函数参数的解构也可以使用默认值 (原理同上)

function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]

你可能感兴趣的:(javascript,es6,前端)