ES6新特性,let、const、数组、对象、函数参数解构赋值 的 总结

ES6新特性,let、const、数组、对象、函数参数解构赋值 的 总结

首先我们要知道什么是ES6
ES6:
ECMAScript 6.0是 JavaScript 语言的语言标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
截止目前2020年为止,ECMAScript已经发行到了第11版也就是ES11
但是现在前端程序员都在说ES6,是因为在ECMAScript 6.0这个版本的更新内容最大,具有里程碑的意义,且使用的最为广泛

版本 更新内容
ES 6,(2015年发行) let、const、模块化、面向对象语法、Promise、箭头函数、解构赋值…
ES 7,(2016年发行) 幂运算符、数组扩展、Async/await关键字
ES 8,(2017年发行) 字符串扩展、Async/await关键字
ES 9,(2018年发行) 对象的解构赋值、正则的扩展
ES 10,(2019年发行) 扩展对象和数组的方法

ECMAScript 和 JavaScript 的关系

ECMAScript 和 JavaScript 的关系是
前者是后者的规格,
后者是前者的一种实现。
日常场合,这两个词是可以互换的。

(一)、let和const命令

let用来 声明变量 ,它的用法类似于var。

//声明变量,可以只声明不赋值,也可以在一行同时声明多个变量
let a;
let b, c, d;
let e = 100;
let f = 521, g = 'iloveyou', h = [];

特性1:所声明的变量,只在let命令所在的代码块内有效。

{
  let a = 10;
  var b = 10;
}

a // ReferenceError: a is not defined.
b // 10

特性2:不允许在相同作用域内,重复声明同一个变量

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

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

// 不报错
let a = 1;
function foo() {
	let a = 2;
	console.log(a)
}
console.log(a) //输出 1
foo()	// 输出 2

特性3:块级作用域

{
    var zhangsan = "zhangsan"
    let lisi = "lisi"
}
console.log(zhangsan) // zhangsan
console.log(lisi)  //  Uncaught ReferenceError: lisi is not defined

块级作用域的经典案例:

// 要求,自动创建10个li标签,点击每个li标签,分别在控制台输出他的index序号值
var ul = document.createElement("ul");
document.body.appendChild(ul)
for (var i = 0; i < 10; i++) {
    var li = document.createElement("li");
    ul.appendChild(li)
    li.innerHTML = `这是第${i + 1}个标签`
    li.addEventListener("click", function () {
        console.log(i + 1)
    })
}
// 这种var声明的变量i,无论你点击哪个li都会弹出 10
// 正确做法,使用let声明变量i,因为块级作用域的原因
var ul = document.createElement("ul");
document.body.appendChild(ul)
for (let i = 0; i < 10; i++) {
    var li = document.createElement("li");
    ul.appendChild(li)
    li.innerHTML = `这是第${i + 1}个标签`
    li.addEventListener("click", function () {
        console.log(i + 1)
    })
}

特性4:不存在变量提升

console.log(zhangsan)  // undefined
var zhangsan = "zhangsan"
console.log(zhangsan)
let zhangsan = "zhangsan" 
// Uncaught ReferenceError: Cannot access 'zhangsan' before initialization
// 引用错误,不能在声明前使用 zhangsan

特性5:不影响作用域链,内部找不到的值,会往外层继续找

{
    let.school = "school"
    function fn() {
        console.log(school); // 打印school
        fn();
    }
}

const命令
const用来声明一个只读的常量,一旦声明,常量的值就不能改变。
特性1:因为这一特性,const一旦声明常量,就必须立马对其赋值(初始化)

const PI = 3.1415;
PI // 3.1415

PI = 3;
// 报错
// TypeError: Assignment to constant variable.
const foo;
// 报错
// SyntaxError: Missing initializer in const declaration

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

{
    const num = 5
}
console.log(num)
// 报错,Uncaught ReferenceError: num is not defined

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

console.log(num)
const num = 5
// 报错 Uncaught ReferenceError: Cannot access 'num' before initialization

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

const num = 5
const num = 10
let num = 20
// 报错 Identifier 'num' has already been declared

特性5const 声明数组,对象时,对其内部的元素进行修改,不算做对常量的修改,不会报错
【 const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了 】

【 常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性 】

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; 
// TypeError: "foo" is read-only

ES6 声明变量,一共有六种方法
ES5 只有两种声明变量的方法:var命令和function命令。ES6 除了添加letconst命令,后面章节还会提到,另外两种声明变量的方法:import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。

顶层对象的属性
顶层对象,在 浏览器 环境指的是 window 对象,在 Node 指的是 global 对象。ES5 之中,顶层对象的属性与全局变量是等价的。

顶层对象的属性赋值与全局变量的赋值,是同一件事。

window.a = 1;
a // 1

a = 2;
window.a // 2

ES6 为了改变这一点,一方面规定,为了保持兼容性,var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let 命令、const 命令、class 命令声明的全局变量,不属于顶层对象的属性。

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

let b = 1;
window.b // undefined

(二)、数组,对象的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,并变量进行赋值,这被称为解构

以前,为变量赋值,只能直接指定值。

let a = 1;
let b = 2;
let c = 3;
// a 1   b 2   c 3

ES6 允许写成下面这样。
代码表示,从数组中提取值,按照对应位置,对变量赋值

let [a, b, c] = [1, 2, 3];
// a 1   b 2   c 3

这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
如果解构不成功,变量的值就等于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 // []

另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

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

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined

对象的解构赋值

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

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

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

let { bbb } = { foo: 'aaa', bar: 'bbb' };
bbb // undefined

对象的解构赋值有一个非常好用的场景,就是可以在定义变量的同时为变量赋值
假如服务器返回值是一个对象cities,我们要拿到他的name属性的值,则这样写会非常简洁

var cities = {
    name:"hangzhou"
}
var {name} = cities
// name  "hangzhou"

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

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

var {x, y = 5} = {x: 1};
x // 1
y // 5

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

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

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

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

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

注意点

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

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

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

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

函数参数的解构赋值
函数 add 的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量 x 和 y 。
对于函数内部的代码来说,它们能感受到的参数就是 x 和 y

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]

undefined就会触发函数参数的默认值。

[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]

猜你喜欢

转载自blog.csdn.net/qq_40893035/article/details/108239748