名称的含义:
- ECMA是标准,JS是实现。
类似于HTML5是标准,IE10、Chrome、FF都是实现
- ECMAScript简称ECMA或ES
ECMAScript ≈ JS
兼容性问题:
浏览器不兼容ES6:(ES2015)-IE10+、Chrome、FireFox、移动端、NodeJS
浏览器支持情况:Chrome 58、Edge14、Firefox 54、Safari10以及Opera55版本以及之后版本支持es5。
可以通过编译、转换达到兼容性使用的目的:
1.在线转换
2.提前编译
babel==browser.js
一.变量
ES5 只有全局作用域和函数作用域。会导致:
- 内层变量覆盖外层变量
var tmp = new Date();
function f() {
console.log(tmp); //undefined
if (false) {
var tmp = "hello world";
}
}
复制代码
- 变量泄露,成为全局变量
var s = 'hello';
for (var i = 0; i \< s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
复制代码
ES6 提供 let 和 const 来代替 var声明变量,新的声明方式支持用大括号表示的块级作用域,这会带来一些好处:
-
不再需要立即执行的函数表达式(IIFE)
-
循环体中的闭包不再有问题
-
防止重复声明变量
- Var
-
可以重复声明
-
无法限制修改
-
没有块级作用域
- Let
-
不能重复声明
-
变量-可以修改
-
块级作用域
- Const
-
不能重复声明
-
常量-不能修改
-
块级作用域
默认使用let,只有当写保护的变量或者常量用const。
默认使用 const,只有当确实需要改变变量的值的时候才使用 let。
二. 函数
- 箭头函数
function 名字(){
}
复制代码
()=\>{
}
复制代码
-
如果只有一个参数,()可以省略
-
如果只有一个return,{}可以省略
-
=>不只是关键字function的简写,还与包围它的代码共享同一个this,有效的解决this的指向问题。
-
箭头函数,每次被执行都返回的是一个新的函数引用
- 函数的参数
- 函数的扩展/数组展开
没有展开语法的时候,只能组合使用 push,splice,concat等方法,来将已有数组元素变成新数组的一部分。有了展开语法,构造新数组会变得更简单、更优雅。
延展操作符...可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造对象时,将对象表达式按key-value的方式展开。
1). 参数扩展(延展操作符):
收集剩余的参数
function aaa(a,b,..args){}
Rest Parameter必须是参数的最后一个
展开数组
展开后的效果,跟直接把数组的内容写在这里一样
Let arr1 = [1,2,3];
Let arr2 = […arr1]
复制代码
应用场景
a. 在函数调用时使用延展操作符
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
复制代码
b.构造数组、数组拷贝和连接多个数组
- 构造
const stuendts = ['Jine','Tom'];
const persons = ['Tony',... stuendts,'Aaron','Anna'];
conslog.log(persions)// ["Tony", "Jine", "Tom", "Aaron", "Anna"]
复制代码
- 拷贝
var arr = [1, 2, 3];
var arr2 = [...arr]; // 等同于 arr.slice()
arr2.push(4);
console.log(arr2)//[1, 2, 3, 4]
复制代码
- 连接
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];
复制代码
c. 克隆对象与合并对象
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }
复制代码
和参数列表的展开类似, ... 在构造字数组时, 可以在任意位置多次使用。
展开语法和 Object.assign() 行为一致, 执行的都是浅拷贝(只遍历一层)。
在ECMAScript 2018中延展操作符增加了对对象的支持
d. 函数参数默认值
function(a,b=2,c=3){}
函数参数默认值不仅能是代码变得更加简洁而且能规避一些问题。比如:之前的默认写法var height = height || 100 ;当height为0或""时就会出问题
2). 解构赋值
通过解构赋值可以方便的交换两个变量的值。
- 左右两边结构必须一样(括号两边一一对应)
Let [a,b,c] = [1,2,3];
- 右边必须是个东西(json、数组…)
Let {a,b,c} = {a:4,b:5,c:6}
- 声明和赋值不能分开(即必须在一句话里完成)
三.数组
- map 映射 一个对一个
传入方法 一个对一个的处理数组中的元素,返回新的数组
let array = [1,2,3,4,5,6,7]
let result = array.map(item=\>item\*3)
console.log(result);
[ 3, 6, 9, 12, 15, 18, 21 ]
复制代码
- reduce 汇总 一堆出来一个,比如总数、平均数、总价、总和
传入方法包含三个参数(temp过程值,itme从1开始的元素,index下标),返回计算后的结果值
let array = [1, 2, 3, 4, 5, 6, 7]
let result = array.reduce(function(temp, item, index) {
return temp + item
})
console.log(result)
28
复制代码
- filter 过滤器
传入方法根据条件过滤返回新数组
let array = [1, 2, 3, 4, 5, 6, 7]
let result = array.filter(item =\> item % 3 === 0)
console.log(result)
[ 3, 6 ]
复制代码
- foreach 迭代
第一个参数是item,第二个是index,迭代数组
- for..of
适合遍历数组。循环出来的是元素value值。如果实在想用for...of来遍历普通对象的属性的话,可以通过和Object.keys()搭配使用,先获取对象的所有key的数组然后遍历
- for..in
for...in穷举对象的所有属性,包括自定义的添加的属性也能遍历到。适合遍历对象属性。循环出来的是key值。
- Array.prototype.includes()
includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回 tru否则返回false。
let arr = ['1', '2', '3'];
if (arr.includes('1'))
{
console.log('1存在');
}
复制代码
- Array.from()
将伪数组对象或可遍历对象转换为真数组
如果一个对象的所有键名都是正整数或零,并且有length属性,那么这个对象就很像数组,称为伪数组。典型的伪数组有函数的arguments对象,以及大多数 DOM 元素集,还有字符串。
- Array.of(data1, data2, data3)
将一系列值转换成数组。 Array.of( )方法总会创建一个包含所有传入参数的数组,而不管参数的数量与类型
当调用 new Array( )构造器时,根据传入参数的类型与数量的不同,实际上会导致一些不同的结果
let items = new Array(2) ;
console.log(items.length) ; // 2
console.log(items[0]) ; // undefined
console.log(items[1]) ;
复制代码
当使用单个数值参数来调用 Array 构造器时,数组的长度属性会被设置为该参数。
let items = new Array(1, 2) ;
console.log(items.length) ; // 2
console.log(items[0]) ; // 1
console.log(items[1]) ; // 2
复制代码
如果使用多个参数(无论是否为数值类型)来调用,这些参数也会成为目标数组的项。
let items = Array.of(1, 2);
console.log(items.length); // 2
console.log(items[0]); // 1
console.log(items[1]); // 2
items = Array.of(2);
console.log(items.length); // 1
console.log(items[0]); // 2
复制代码
- Array.every
每个值是否满足条件,如果是则返回true,如果不是则返回false
- Array.some
是否有其中一个值满足条件,如果是则返回true,如果不是则返回false
- Array.find()
数组实例的find方法,用于找出第一个符合条件的数组成员。如果没有符合条件的成员,则返回undefined。
[1, 4, -5, 10].find((n) => n < 0) // -5
- Array.findIndex()
返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
复制代码
四.字符串
- startsWith
以’XXX’开头,返回布尔值
- endsWith
以’XXX’结尾,返回布尔值
- 模板字符串
拼接字符串,不用单引号和双引号用反单引号包裹字符串,可以传参,可以换行。
参数传递时将变量放在大括号${}之中
let temp = '456'
let str = \`123\${temp}789\`
console.log(str)
//123456789
复制代码
五.面向对象
- class
增加class关键字
构造器和类分开了
Class里面可以直接加方法
constructor构造函数,实例化的时候将会被调用,如果不指定,那么会有一个不带参数的默认构造函数
React的组件就是一个个class
之前是:
function User(user,age){
this. user = user
this.age = age
}
User.prototype.showName=function(){
console.log(this.name)
}
复制代码
现在是:
class User{
constructor(name, age) {
this.name = name
this.age = age
}
showName(){
console.log(this.name)
}
}
复制代码
- extends继承
子类必须要在constructor中指定super 函数,否则在新建实例的时候会报错
如果没有置顶consructor,默认带super函数的constructor将会被添加
class superUser extends User{
constructor(name, age,love) {
super(name,age)
this.love = love
}
showLove(){
}
}
复制代码
六.JSON
JSON.stringify
JSON的字符串化
JSON.parse
字符串转JSON
- 简写
-
名字和值即key和value一样时可以只写一个
-
对象中也可以直接写变量,非常简洁
-
Json中的function可以省略到只写方法名(:function都可以去掉)
- JSON对象的标准写法:
-
只能用双引号
-
所有的名字都必须用引号包起来
七.JSON
是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
复制代码
重复元素在Set中自动被过滤:
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
复制代码
注意数字3和字符串'3'是不同的元素。
通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果:
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}
复制代码
通过delete(key)方法可以删除元素:
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}
复制代码
八.Map
Map是一组键值对的结构,具有极快的查找速度。
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
复制代码
初始化Map需要一个二维数组,或者直接初始化一个空Map。Map具有以下方法:
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
复制代码
由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:
var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88
复制代码
九.Promise
含义:
-
异步:操作之间无关联性,可以同时进行多个操作。代码复杂
-
同步:同时只能做一件事。代码简单
ES6提供了一个原生的构造函数Promise。Promise的出现是为了解决JavaScript中异步编程的问题。传统的异步编程最大的特点就是地狱般的回调嵌套,一旦嵌套次数过多,就很容易使我们的代码难以理解和维护。 Promise则可以让我们通过链式调用的方法去解决回调嵌套的问题,使我们的代码更容易理解和维护。
Promise函数体的内部包裹着一个异步的请求或者操作或者函数;然后我们可以在这个异步的操作完成的时候使用resolve函数将我们获得的结果传递出去,或者使用reject函数将错误的消息传递出去。
Promise用来消除异步操作
用同步的方式写异步代码,接收一个函数参数,传入resolve,reject
参数resolve表示成功
参数reject表示失败
-
因为Promise是一个构造函数,所以我们使用了new操作符来创建promise
-
构造函数Promise的参数是一个函数(暂时叫它func),这个函数(func)有两个参数resolve和reject,它们分别是两个函数,这两个函数的作用就是将promise的状态从pending(等待)转换为resolved(已解决)或者从pending(等待)转换为rejected(已失败)。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。promise对象初始化状态为 pending ;当调用resolve(成功),会由pending => fulfilled;当调用reject(失败),会由pending => rejected。
- 创建后的promise有一些方法,then和catch。当然我们也可以人为的在Promise函数上添加一些满足我们自己需求的方法,方便每一个promise对象使用
方法:
Promise对象可以通过使用then方法将上一步返回的结果获取过来(不管是resolved还是rejected),可以通过使用catch方法捕获Promise对象在使用catch之前的异常。
then方法可以接受两个函数作为参数,第一个函数是用来处理resolve的结果,第二个是可选的,用来处理reject的结果。也就是说,我们在创建p这个Promise对象的时候,通过函数resolve传递出去的结果可以被p的第一个then方法中的第一个函数捕获然后作为它的参数。通过函数reject传递出去的结果可以被p的第一个then方法中的第二个函数捕获然后作为它的参数。
一旦创建一个Promise对象之后,我们就可以使用then方法来进行链式的调用,而且我们可以把每一次的结果都返还给下一个then方法,然后在下一个then方法中对这个值进行处理。每一个then方法中都可以再次新创建一个Promise对象,然后返还给下一个then方法处理。
- Promise.all
接收一个数组参数,里面的值最终都返回Promise对象。包装许多个Promise实例,然后组成了一个新的Promise对象。新的Promise对象的状态由前面几个被包裹的Promise对象的状态决定,如果前面的Promise都被resolve了,那么新的Promise的状态也是resolve的;只要有一个Promise被reject了,那么组成的新的Promise的状态也是reject的。数组中的异步操作并行执行,都执行完了才会进入到then里面。
Promise.all([\$.ajax(),\$.ajax()]).then(results=\>{
//成功
}err=\>{
//失败
})
复制代码
- Promise.reac
接收一个数组参数,里面的值最终都返回Promise对象。包装许多的Promise对象,然后组成了一个新的Promise对象,但是使用Promise.race的含义是:只要包裹的的Promise对象中有一个的状态发生了改变,那么组成的这个新的Promise对象的状态就是上面那个率先改变的Promise实例的状态。数组中的异步操作并行执行,第一个执行完了就会会进入到then里面。
- Promise.resolve
将一个值转变为一个Promise对象,使它具有Promise的一些方法和特性。方法产生的Promise对象的状态是resolved的
- Promise.reject
将一个值转变为一个Promise对象,使它具有Promise的一些方法和特性。方法产生的Promise对象的状态是rejected的
十.Async与await
async/await解决回调地狱问题,使异步代码看起来像同步操作。
应用场景:
- 获取异步函数的返回值
异步函数本身会返回一个Promise,所以我们可以通过then来获取异步函数的返回值。
async function functionName(data1, data2) {
const d1=await count1(data1);
const d2=await count2(data2);
return d1+d2;
}
functionName
('person','children').then(console.log);//通过then获取异步函数的返回值。
function count1(data) {
return new Promise((resolve, reject) =\> {
setTimeout(() =\> {
resolve(data.length);
}, 1000);
});
}
复制代码
- async/await在并发场景中的应用
没有依赖关系的请求,通过Promise.all来实现await的并发调用。
async function charCountAdd(data1, data2) {
const [d1,d2]=await Promise.all([charCount(data1),charCount(data2)]);
return d1+d2;
}
charCountAdd('Hello','Hi').then(console.log);
function charCount(data) {
return new Promise((resolve, reject) =\> {
setTimeout(() =\> {
resolve(data.length);
}, 1000);
});
}
复制代码
- async/await的几种错误处理方式
- 捕捉整个async/await函数的错误
async function charCountAdd(data1, data2) {
const d1=await charCount(data1);
const d2=await charCount(data2);
return d1+d2;
}
charCountAdd('Hello','Hi')
.then(console.log)
.catch(console.log);//捕捉整个async/await函数的错误
复制代码
- 捕捉单个的await表达式的错误
async function charCountAdd(data1, data2) {
const d1=await charCount(data1)
.catch(e=\>console.log('d1 is null'));
const d2=await charCount(data2)
.catch(e=\>console.log('d2 is null'));
return d1+d2;
}
charCountAdd('Hello','Hi').then(console.log);
复制代码
- 同时捕捉多个的await表达式的错误
async function charCountAdd(data1, data2) {
let d1,d2;
try {
d1=await charCount(data1);
d2=await charCount(data2);
}catch (e){
console.log('d1 is null');
}
return d1+d2;
}
charCountAdd('Hello','Hi')
.then(console.log);
function charCount(data) {
return new Promise((resolve, reject) =\> {
setTimeout(() =\> {
resolve(data.length);
}, 1000);
});
}
复制代码
十一.Object
- Object.values()
Object.values()是一个与Object.keys()类似的新函数,但返回的是Object自身属性的所有值,不包括继承的值。
const obj = {a: 1, b: 2, c: 3};
const vals=Object.keys(obj).map(key=\>obj[key]); //es7
console.log(vals);//[1, 2, 3]
const values=Object.values(obj1); //es8
console.log(values);//[1, 2, 3]
复制代码
- Object.entries
bject.entries()函数返回一个给定对象自身可枚举属性的键值对的数组。
Object.keys(obj).forEach(key=\>{ //es7
console.log('key:'+key+' value:'+obj[key]);
})
//key:a value:1
//key:b value:2
//key:c value:3
for(let [key,value] of Object.entries(obj1)){ //es8
console.log(\`key: \${key} value:\${value}\`)
}
//key:a value:1
//key:b value:2
//key:c value:3
复制代码
十二.模块化
模块的功能主要由 export 和 import组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export来规定模块对外暴露的接口,通过import来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
- 导出(export)
ES6将一个文件视为一个模块。允许在一个模块中使用export来导出多个常量、变量或函数
export var name = 'abc'
export {name, age};
export function showName(name) {
return name;
}
复制代码
- 导入(import)
通过import引用定义好模块的输出。一条import语句可以同时导入默认函数和其它变量。
import {myModule} from 'myModule';
import {name,age} from 'user';
复制代码