ES6——相关语法介绍

一、ES6简介

ES6(ECMAScript 6.0)是一个历史名词,也是一种泛指,指代ECMAScript5.1版本之后JavaScript的下一代标准。

二、变量声明let和const

ES6之前,通常用var关键字来声明变量。无论在何处声明,都会被视为在所在函数作用域最顶部(变量提升)。
let和const使用的好处:

  • 可以解决ES5使用var初始化变量时会出现的变量提升问题。
  • 可以解决使用闭包时出错的问题。
  • ES5只有全局作用域和函数作用域,却没有块级作用域。
  • 可以解决使用计数的for循环变量时会导致泄露为全局变量的问题。

let命令表示被声明的变量值在作用域内生效。

{
	let a = 1;
	var b = 2;
}
console.log(a);  //出错
console.log(b);  //2

从上述可以看出,let声明的代码只能在其所在的代码块内有效,出了代码块,就会报错。

对于let来说,不存在变量提升。在一般代码逻辑中,变量应该是在定义后才可以使用,但var的变量提升却可以先使用再定义,而let更改了这种语法行为。要使用一个变量必须先声明,不然就会报错。
代码示例如下所示:

console.log(a); //undefined
var a = 1;
console.log(b); //出错
let b = 2;

在let中不允许重复声明同一个变量。

在代码块内,使用let声明变量之前,该变量都是不可用的(不可访问、不可赋值等)。在语法上,这被称为“暂时性死区”。暂时性死区(TDZ)就是只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取。只有等到声明变量的哪一行代码出现,才可以获取和使用该变量。
例如:

if (true) {
	temp = "hello";  //出错
	console.log(temp);  //出错
	let temp;  //暂时性死区(TDZ)结束
	console.log(temp);
	temp = 1;
	temp = "hello";
	console.log(temp);
}

在ES5中,变量提升可能还会导致内层变量覆盖外层变量。
例如:

var i = 1;
function func() {
	console.log(i);
	if (true) {
		var i = 1;
	}
}
func() //undefined

let还引入了块级作用域的概念,传统ES5中不存在块级作用域。假如没有块级作用域,可能会出现这种问题:

var arr = [1, 2, 3, 4];
for(var i = 0; i < arr.length; i++){
	console.log(i);
}
console.log(i); //4

在上述代码中,希望达到的结果是,在for循环之后变量i被垃圾回收机制回收。但用来计数的循环变量在循环结束后并没有被回收,内存泄漏为了全局变量。在这种情况下可以用块级作用域let。进行改写后的结果为:

var arr = [1, 2, 3, 4];
for(let i = 0; i < arr.length; i++){
	console.log(i);
}
console.log(i); //ReferenceError: i is not defined

块级作用域的出现允许作用域的任意嵌套,同时内存作用域可以使用跟外层同名的变量名。

块级作用域可以使立即执行函数表达式(IIFE)不再成为必要项。
例如:

(function(){
	var a = 1;
	console.log(a);
}())

{
	let a = 1;
	console.log(a);
}

const用于声明只读的常量,一旦声明就不能改变。和let一样,const只在块级作用域内有效,不存在变量提升,存在暂时性死区和不可重复声明。

三、解构赋值

解构赋值:按照一定模式从数组或对象中提取值,对变量进行赋值。

提示:解构赋值的对象是数组或对象,作用是赋值。

const test = {
	a: '1',
	b: '2',
	c: 3
};
let {a, b, c} = test;
console.log(a, b, c); //1 2 3
let {d, e, f} = test;
console.log(d, e, f); //undefined undefined undefined

注意:在进行对象的赋值中,其相关的变量名应该与该对象的属性名相同,其相关的顺序不重要。

传统的将对象中的属性值赋给变量的操作为:

const test = {
	a: '1',
	b: '2',
	c: 3
};
let d = test.a;
let b = test.b;
let c = test.c;
console.log(d); //1
console.log(b); //2
console.log(c); //3

对象解构中指定默认值的操作如下:

var {a = 1} = {};
console.log(a); //1
var {a, b = 2} = {a: 1};
console.log(a); //1
console.log(b); //2

当解构不成功时,其相关变量的值为undefined;
代码示例如下所示:

let {a} = {b: 1};
console.log(a); //undefined

解构赋值在数组中也能进行相关的使用。
数组解构赋值示例:

let [a, b, c] = [1, 2, 3];
console.log(a); //1
console.log(b); //2
console.log(c); //3
let [x, , y] = [1, 2, 3];
console.log(x); //1
console.log(y); //3
let [e, f, ...g] = ["he"];
console.log(e); //he
console.log(f); //undefined
console.log(g); //[]

从以上的代码中可以看出其从数组中取到值后,按照对应位置赋值该对应变量。如果解构失败就会赋值为undfined。如果等号右边是不可遍历的解构,也会报错。

在数组解构中也允许给其赋初始值。
代码示例如下:

let [a = [1, 2]] = [];
console.log(a); //[1,2]
let [x, y = "hi"] = ["a", "b"];
console.log(x); //a
console.log(y); //b

四、拓展运算符(spread)…

拓展运算符是3个点…,可以将它比作rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。

1、合并数组

在ES5中要合并两个数组,写法为:

var a = [1, 2];
var b = [3, 4];
var c = a.concat(b);
console.log(c); //[ 1, 2, 3, 4 ]

在ES6中拓展运算符提供了合并数组的新写法:

var a = [1, 2];
var b = [3, 4];
var c = [...a, ...b];
console.log(c); //[ 1, 2, 3, 4 ]

如果想让一个数组添加到另一个数组后面,在ES5中这样写:

var a = [1, 2];
var b = [3, 4];
Array.prototype.push.apply(a,b); //Array.prototype属性表示Array构造函数的原型,并允许你向所有Array对象添加新的属性和方法。
console.log(a); //[ 1, 2, 3, 4 ]

上述代码中由于push()方法不能为数组,所以通过apply()方法变相使用。

在ES6的拓展运算符后可以直接使用push()方法。

var a = [1, 2];
var b = [3, 4];
a.push(...b)
console.log(a); //[ 1, 2, 3, 4 ]

2、数组复制

拓展运算符还可以用于数组复制,进行复制中其所复制的是指向底层数据结构的指针,并非复制一个全新的数组。
示例:

const x = ['a', 'b'];
const x1 = x;
console.log(x1); //[ 'a', 'b' ]

3、与解构赋值结合

拓展运算符可以和解构赋值结合用于生成新数组。

const [arr1, ...arr2] = [1, 2, 3, 4];
console.log(arr1); //1
console.log(arr2); //[ 2, 3, 4 ]

注意:使用拓展运算符给数组赋值时,必须放在参数最后的位置,不然会报错。

4、函数调用(替代apply()方法)

在ES5中要合并两个数组,写法为:

function add(a, b) {
	return a + b;
}
const num = [1, 10];
console.log(add.apply(null, num)); //11

在ES6中可以这样写:

function add(a, b) {
	return a + b;
}
const num = [1, 10];
console.log(add(...num)); //11

上述代码使用拓展运算符将一个数组变为参数序列。当然,拓展运算符也可以和普通函数参数相结合使用。例如:

function add(a, b, c, d) {
	return a + b + c + d;
}
const num = [1, 10];
console.log(add(1, ...num, -1)); //11

拓展运算符中的表达式如下:

[...(true ? [1, 2] : [3]), 'a']; //[1, 2, 'a']

5、箭头函数

ES6对于函数的拓展中增加了箭头函数=>,用于对函数的定义。
箭头函数语法很简单,先定义自变量,然后是箭头和函数主体。箭头函数相当于匿名函数简化了函数定义。
不引入参数的箭头函数示例:

var sun = () => 1 + 2; //圆括号代表参数部分
//等同于
var sum = function() {
	return 1 + 2;
}

引入参数的箭头函数示例:

//单个参数
var sum = value => value; //可以不给参数value加小括号
//等同于
var sum = function(value) {
	return value;
};
//多个参数
var sum = (a, b) => a + b;
//等同于
var sum = function(a, b){
	return a + b;
}

花括号{}内的函数主体部分写法基本等同于传统的函数写法。

如果箭头函数内要返回自定义对象,需要用小括号把对象括起来。例如:

var getInfo = id => ({
	id: 'id',
	title: 'hello'
});
//等同于
var getInfo = function(id) {
	return {
		id: 'id',
		title: 'hello'
	}
}

箭头函数于传统的JavaScript函数的主要区别:

  • 箭头函数内置this不可改变。
  • 箭头函数不能使用new关键字来实例化对象。
  • 箭头函数没有arguments对象,无法通过arguments对象访问传入的参数。

对this的绑定是JavaScript错误的常见来源。首先容易丢失函数内置数值,或得到意外结果。其次将箭头函数限制为使用固定this引用,有利于JavaScript引擎优化处理。

箭头函数看似是匿名函数的简写,但与匿名函数有明显区别,箭头函数内部的this是词法作用域,由上下文确定。如果使用了箭头函数,就不能对this进行修改,所以用call()或apply()调用箭头函数时都无法对this进行绑定,传入的第一个参数会被忽略。

提示: 词法作用域是定义在词法阶段的作用域,它在代码书写的时候就已经确定。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值