【前端】ES6 语法精简整理

ECMAScript 总结

简介

ECMAScript中的变量无特定的类型,定义变量时只用var运算符
每行结尾的分号可有可无,但为了保持良好的编程习惯,最好总是加入分号
注释与 Java、C 和 PHP 语言的注释相同
括号表示代码块
ECMAScript中的变量并不一定要初始化。
ECMAScript有5种原始类型(primitive type),即Undefined、Null、Boolean、Number和String。
Undefined类型具有唯一的值,即undefined。当声明的变量未初始化时,该变量的默认值是undefined。
另一种只有一个值的类型是Null,它有唯一专用值null,即它的字面量。值undefined实际上是从值null派生来的
alert(null == undefined); //输出 “true”
undefined表示声明未赋值,null表示尚未存在的对象。如果返回的是对象,那么找不到该对象时,返回的通常是null。

运算符

逻辑NOT运算符
对象,false
数字0,true
0以外的任何数字,false
null,true
NaN,true
undefined,发生错误

加法运算符
某个运算数是NaN,那么结果为NaN。
-Infinity加-Infinity,结果为-Infinity。
Infinity加-Infinity,结果为NaN。
+0加+0,结果为+0。
-0加+0,结果为+0。
-0加-0,结果为-0。

减法运算符
在处理特殊值时,减法运算符也有一些特殊行为:
某个运算数是NaN,那么结果为NaN。
Infinity减Infinity,结果为NaN。
-Infinity减-Infinity,结果为NaN。
Infinity减-Infinity,结果为Infinity。
-Infinity减Infinity,结果为-Infinity。
+0减+0,结果为+0。
-0减-0,结果为-0。
+0减-0,结果为+0。
某个运算符不是数字,那么结果为NaN。

等号和非等号
特殊情况

null == undefined	 true
"NaN" == NaN	 false
5 == NaN		false
NaN == NaN	false
NaN != NaN	true
false == 0		true
true == 1		true
true == 2		false
undefined == 0	false
null == 0		false
"5" == 5		true

闭包

函数可以使用函数之外定义的变量

var sMessage = "hello world";
function sayHelloWorld() {
	alert(sMessage);
}
sayHelloWorld();

对象

在 ECMAScript 中,只能访问对象的引用。每次创建对象,存储在变量中的都是该对象的引用,而不是对象本身。
约定规则,私有的属性和方法:在前后加下划线: obj._color_ = "blue" (注意这只是书写规则,并不能改变变量的属性)
通过prototype属性为本地对象添加属性和方法

let&const

let
let声明的变量只在它所在的代码块有效。
变量一定要在声明后使用,否则报错。
如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
let不允许在相同作用域内,重复声明同一个变量。
let为JavaScript新增了块级作用域。 (注意:考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。)

const
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
const声明的常量不可重复声明。
const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。

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

解构赋值

经典

var [a, b, c] = [1, 2, 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。

对象的解构赋值

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

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

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

嵌套赋值

let obj = {};
let arr = [];

({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });

obj // {prop:123}
arr // [true]

对象默认值

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	

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。

函数参数的解构赋值

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]

字符串

at() 可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。

'abc'.at(0) // "a"
'????'.at(0) // "????"

normalize() 用来将字符的不同表示方法统一为同样的形式,主要用来处理欧洲语言
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
repeat(): 返回一个新字符串,表示将原字符串重复n次。

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

padStart()用于头部补全
padEnd()用于尾部补全 (如果省略第二个参数,则会用空格补全长度。)

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

(如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串。)
模板字符串,用反引号(`)标识 字符串中嵌入变量,可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

String.raw() 往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串。

String.raw`Hi\n${2+3}!`;
// "Hi\\n5!"

String.raw`Hi\u000A!`;
// 'Hi\\u000A!'

数值

Number.isFinite()用来检查一个数值是否为有限的(finite)
Number.isNaN()用来检查一个值是否为NaN。
与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,非数值一律返回false。
Number.parseInt(), Number.parseFloat() 取代传统的parseInt, parseFloat

// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45

Number.isInteger() 判断一个值是否为整数 注意3和0.3视为同一个值

Number.isInteger(25) // true
Number.isInteger(25.0) // true	

Number.EPSILON 引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的。如果这个误差能够小于Number.EPSILON,我们就可以认为得到了正确结果。

5.551115123125783e-17 < Number.EPSILON
// true

Number.EPSILON的实质是一个可以接受的误差范围。

function withinErrorMargin (left, right) {
  return Math.abs(left - right) < Number.EPSILON;
}
withinErrorMargin(0.1 + 0.2, 0.3)
// true
withinErrorMargin(0.2 + 0.2, 0.3)
// false	

Math.trunc() 去除一个数的小数部分,返回整数部分(不会四舍五入),非数值先转为数值,空值和无法截取整数的值,返回NaN
Math.sign() 用来判断一个数到底是正数、负数、还是零
参数为正数,返回+1;
参数为负数,返回-1;
参数为0,返回0;
参数为-0,返回-0;
其他值,返回NaN。
指数运算符 ** 进行指数运算

let a = 2;
a **= 2;
// 等同于 a = a * a;

let b = 3;
b **= 3;
// 等同于 b = b * b * b;

扩展运算符

扩展运算符(spread)是三个点(…)。它将一个数组转为用逗号分隔的参数序列。
主要用于函数调用

function push(array, ...items) {
  array.push(...items);
}
function add(x, y) {
  return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42

其他用法:

Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
// push方法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
//Date
new Date(...[2015, 1, 1]);

数组扩展

Array.from()将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象

let arrayLike = {
	'0': 'a',
	'1': 'b',
	'2': 'c',
	length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

Array.of方法用于将一组值,转换为数组。

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

数组实例的copyWithin() 将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组

Array.prototype.copyWithin(target, start = 0, end = this.length)
// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]

// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]

// 将3号位复制到0号位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}

数组实例的find()方法,用于找出第一个符合条件的数组成员。

[1, 4, -5, 10].find((n) => n < 0)
// -5

数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2
注意这两个方法都可以发现NaN,弥补了数组的indexOf方法的不足。
[NaN].indexOf(NaN)
// -1
[NaN].findIndex(y => Object.is(NaN, y))
// 0

数组实例的fill()方法使用给定值,填充一个数组。

['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]

数组中已有的元素,会被全部抹去。
fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

注意,如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。

数组实例的 includes() 方法返回一个布尔值,表示某个数组是否包含给定的值

[1, 2, NaN].includes(NaN) // true

该方法的第二个参数表示搜索的起始位置,默认为0

[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true

includes使用的是不一样的判断算法,不会误判NaN。

[NaN].includes(NaN)
// true

数组实例的 flat() 用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]

flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

[1, [2, [3]]].flat(Infinity)
	// [1, 2, 3]

flat()方法会跳过空位

数组实例的 flatMap() 对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。
// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
flatMap()只能展开一层数组。

函数

箭头函数

var f = () => 5;
	// 等同于
	var f = function () { return 5 };

	var sum = (num1, num2) => num1 + num2;
	// 等同于
	var sum = function(num1, num2) {
	  return num1 + num2;
	};

箭头函数可以与变量解构结合使用。

const full = ({ first, last }) => first + ' ' + last;
	// 等同于
	function full(person) {
	  return person.first + ' ' + person.last;
	}

使用注意点
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

箭头函数导致this总是指向函数定义生效时所在的对象,这是因为箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。

不适用场合
第一个场合是定义对象的方法,且该方法内部包括this。
第二个场合是需要动态this的时候,也不应使用箭头函数。(按钮绑定时间的时候)

函数参数的默认值
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x, y = 'World') {
  console.log(x, y);
}

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

函数的 length 属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

name 属性
返回该函数的函数名。

function foo() {}

如果将一个具名函数赋值给一个变量,则 ES5 和 ES6 的name属性都返回这个具名函数原本的名字。
const bar = function baz() {};
// ES5
bar.name // "baz"
// ES6
bar.name // "baz"/ "foo"

对象

Object.is() 用来比较两个值是否严格相等

注意的是:一是+0不等于-0,二是NaN等于自身。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

Object.assign() 用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}	
注意:Object.assign()方法实行的是浅拷贝

Set

构造Set

const s = new Set();
	[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
	for (let i of s) {
	  console.log(i);
	}
	// 2 3 5 4

用来去除数组重复成员

[...new Set(array)]

Set 实例的属性和方法
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
Set遍历
for…of

let set = new Set(['red', 'green', 'blue']);

		for (let x of set) {
		  console.log(x);
		}
		// red
		// green
		// blue

forEach

let set = new Set([1, 4, 9]);
	set.forEach((value, key) => console.log(key + ' : ' + value))
	// 1 : 1
	// 4 : 4
	// 9 : 9

Map

构造

const map = new Map([
	  ['name', '张三'],
	  ['title', 'Author']
	]);
	

如果对同一个键多次赋值,后面的值将覆盖前面的值。
如果读取一个未知的键,则返回undefined。

Map 实例的属性和方法
size 返回 Map 结构的成员总数
set(key, value): set方法设置键名key对应的键值为value,然后返回整个 Map 结构
get(key): get方法读取key对应的键值,如果找不到key,返回undefined。
has(key): has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中
delete(key): delete方法删除某个键,返回true。如果删除失败,返回false。
clear(): clear方法清除所有成员,没有返回值。
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回所有成员的遍历器。
forEach():遍历 Map 的所有成员。

WeakSet

WeakSet 的成员只能是对象,而不能是其他类型的值。
WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用
WeakSet 适合临时存放一组对象,防止内存泄漏
WeakSet能使用的方法: add(), delete(), has()

WeakMap

WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
WeakMap的键名所指向的对象,不计入垃圾回收机制。
WeakMap解决内存泄漏问题,只要外部的引用消失,WeakMap 内部的引用,就会自动被垃圾回收清除。
WeakMap能使用的方法 get(), set(), has(), delete()
一个典型应用场景是,在网页的 DOM 元素上添加数据,就可以使用WeakMap结构。当该 DOM 元素被清除,其所对应的WeakMap记录就会自动被移除。

for…of 循环

一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for…of循环遍历它的成员。
for…of循环可以代替数组实例的forEach方法。
注意:JavaScript 原有的for…in循环,只能获得对象的键名,不能直接获取键值。ES6 提供for…of循环,允许遍历获得键值。

var arr = ['a', 'b', 'c', 'd'];
	for (let a in arr) {
	  console.log(a); // 0 1 2 3
	}

	for (let a of arr) {
	  console.log(a); // a b c d
	}
	

for…of循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟for…in循环也不一样。

let arr = [3, 5, 7];
	arr.foo = 'hello';
	for (let i in arr) {
	  console.log(i); // "0", "1", "2", "foo"
	}
	for (let i of arr) {
	  console.log(i); //  "3", "5", "7"
	}
	

for…in 与 for…of的比较

for…in循环有几个缺点。
数组的键名是数字,但是for…in循环是以字符串作为键名“0”、“1”、“2”等等。
…in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
某些情况下,for…in循环会以任意顺序遍历键名。
总之,for…in循环主要是为遍历对象而设计的,不适用于遍历数组。

for…of循环相比上面几种做法,有一些显著的优点。
有着同for…in一样的简洁语法,但是没有for…in那些缺点。
不同于forEach方法,它可以与break、continue和return配合使用。
提供了遍历所有数据结构的统一操作接口。

Promise

Promise 是异步编程的一种解决方案。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
Promise有三种状态:1. pending; 2. fulfilled; 3.rejected。除了异步操作,其他任何操作都不能改变此状态。
Promise的状态改变只有两种可能:从pending到fulfilled; 从pending到rejected。

Promise对象是一个构造函数,用来生成Promise实例。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
	resolve(value);
  } else {
	reject(error);
  }
});

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

Promise.try让同步函数同步执行,异步函数异步执行

const f = () => console.log('now');
Promise.try(f);
console.log('next');
// now
// next

由于Promise.try为所有操作提供了统一的处理机制,所以如果想用then方法管理流程,最好都用Promise.try包装一下。这样有许多好处,其中一点就是可以更好地管理异常。

Promise.try(() => database.users.get({id: userId}))
  .then(...)
  .catch(...)

事实上,Promise.try就是模拟try代码块,就像promise.catch模拟的是catch代码块。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值