ECAMScript6基础知识
一、ES介绍
1.1 什么是ECAMScript
ES全称ECMAScript,是脚本语言的规范,而平时经常编写的JavaScript,是EcmaScript的一种实现,所以ES新特性其实指的就是JavaScript的新特性。
ECMAScript是由Ecma国际通过ECMA-262标准化的脚本程序设计语言。
1.2 什么是ECMA-262
Ecma国际制定了许多标准,而ECMA-262只是其中的一个,所有的标准列表查看
http://www.ecma-international.org/publications/standards/Standard.htm
1.3 ECMA-262历史
http://www.ecma-international.org/publications/standards/Ecma-262-arch.htm
注:从ES6开始,每年发布一个版本,版本号比年份最后一位大1
1.4 谁在维护ECMA-262
TC39(Technical Committee 39)是推进ECMAScript发展的委员会。其会员都是公司(其中主要是浏览器厂商,有苹果,谷歌,微软,因特尔等)。TC39定期召开会议,会议由会员公司的代表与特邀专家出席。
1.5 为什么要学习ES6
- ES6的版本变动内容最多。具有里程碑意义
- ES6加入许多新的语法特性,编程实现更简单、高效
- ES6是前端发展趋势
1.6 ES6兼容性
http://kangax.github.io/compat-table/es6/ 可查看兼容性
二、ES6-let变量声明
1、let变量声明的格式
与 var 声明变量格式一样
2、let声明变量的特性
(1)变量不能重复声明
let star = '罗志祥';
let star = '小猪';
(2)块级作用域,代码只在代码块内有效
{let girl = '周扬青';
}console.log(girl); //控制台显示 girl is not defined
(3)不存在变量提升(变量在声明之前,不能使用该变量)
console.log(song);
let song = '稻香'; //控制台显示 Cannot access 'song' before initialization
(4)不影响作用域链
{let school = '清华大学';function fn() {console.log(school);}fn();}
3、let件经典案例
let item = document.querySelectorAll('.item');
//1、常规var用法
for (var i = 0; i < item.length; i++) {item[i].addEventListener('click', function() {this.style.background = 'pink';})}//2、使用let变量声明用法
for (let i = 0; i < item.length; i++) {item[i].addEventListener('click', function() {item[i].style.background = 'pink';})}
三、ES6-conset声明常量
1、conset声明常量格式
常量:值不能修改的量
与var let 一样
2、注意事项
(1)一定要赋初始值
const A; //报错
(2)一般常量使用大写(潜规则)
const a = 1000;
(3)常量的值不能修改
const SCHOOL = '清华大学';
SCHOOL = 'ATM';
(4)块级作用域
{const PLAYER = 'UZI';
}console.log(PLAYER); //PLAYER is not defined
(5)对于数组和对象的元素修改,不算做对常量的修改,不会报错
const TEAM = ['UZI', 'MXLG', 'Ming', 'Letme'];
TEAM.push('Meiko');
四、ES6变量的解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
1、数组的解构
const F4 = ['貂蝉', '蔡文姬', '虞姬', '甄姬'];
let [diao, cai, yu, zhen] = F4;
console.log(diao); //貂蝉
console.log(cai); //蔡文姬
console.log(yu); //虞姬
console.log(zhen); //甄姬
2、对象的解构
const diao = {name: '貂蝉',age: '不详',zhandou: function() {console.log('我可以五连绝世');}};let {zhandou} = diao;
zhandou(); //我可以五连绝世
五、ES6模板字符串
ES6引入新的声明字符串的方式 :[``] 、 ' ' 、 " "。
1、声明
let str = `我也是一个字符串哦`;
console.log(str, typeof str);
2、特性
① 内容中可以直接出现换行符
let str = `<ul><li>王者荣耀</li><li>金铲铲之站</li><li>原神</li></ul>`;
② 可以直接进行变量拼装
let lovest = '林宥嘉';
let out = `${lovest}是我心目中最棒的歌手`;
console.log(out); //林宥嘉是我心目中最棒的歌手
六、对象的简化写法
ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法
这样的书写更加简洁
let name = '甄姬';let change = function() {console.log('阿宓会带来不幸');}const school = {name,change,improve() {console.log("我们可以提高你的技能");}}console.log(school);
七、箭头函数以及声明特点
ES6允许使用箭头(=>)定义函数
1、箭头函数语法结构
//1、常规写法
let fn = function() {}//2、使用箭头函数
let fn = () => {}//实例
let fn = (a, b) => {return a + b;}
let result = fn(1, 2);
console.log(result); //3
2、特点
2.1 this是静态的,this始终指向函数声明时所在的作用域下的this的值
function getName () {console.log(this.name);}let getName2 = () >= {console.log(this.name);}//设置window对象的name属性
window.name = '吃什么';
const food = {name: "西瓜",}
2.2 箭头函数不能作为构造函数去实例化对象
let Person = (name, age) => {this.name = name;this, age = age;}let me = new Person('xiao', 30);console.log(me); // Person is not a constructor
2.3 箭头函数不能使用arguments变量
let fn = () => {console.log(arguments);}
fn(1, 2, 3); //arguments is not defined
3、箭头函数的简写
3.1 当形参有且只有一个的时候,可省略小括号
//1、原始写法
let add = (n) => {return n+n;}
console.log (add(9));//2、简写
let add = n => {return n+n;}
console.log (add(9)); //18
3.2 当代码体只有一条语句的时候,此时return必须省略,语句的执行结果就是函数的返回值,此时省略花括号
//1、原始写法
let pow = (n) => {return n*n;}
console.log(pow(5));//2、简写
let pow = n => n*n;
console.log(pow(5)); //25
4、实践与应用
4.1 点击div 2s 后颜色变为天蓝色
<div class=“ad”></div>//1、原始写法
let ad = document.querySelectior('.ad');
ad.addEventListener('click',function(){// 保存this的值 因为此时定时器的初始写法为window.setTimeout(),需要特殊声明let _this = this;//定时器setTimeout(function(){_this.style.background = 'skyblue';}.2000);
});//2、简写
let ad = document.querySelectior('.ad');
ad.addEventListener('click',function(){setTimeout(() => {//此时的this指向的是声明函数下的this adthis.style.background = 'skyblue';}.2000);
});
4.2 从数组中返回偶数元素
const arr = [1, 6, 9, 10, 100, 25];
//1、原始写法
const result = arr.filter(function(item) {if(item % 2 === 0 ) {return true;}else {return false;}})
console.log(result);//2、简写
const result = arr.filter (item => item % 2 === 0);
console.log(result); //Array(3)
5、总结
箭头函数适合于this无关的回调,如:定时器,数组的方法回调。
箭头函数不适合与this 有关的回调,如:dom事件回调,对象的方法。
八、函数参数默认值
ES6允许给函数参数(形参)赋值初始值
1、形参初始值,具有默认的参数,一般位置要靠后
function add(a, b, c = 10) {return a + b + c;}
let result = add(1, 2);
console.log(result); //1+2+10=13
2、可与解构赋值相结合
function connect ({host,username,password,port}) {console.log(host);console.log(username);console.log(password);console.log(port);}
connect ({host: 'localhost';username;'root';password: 'root';port: 3306})
3、rest参数
ES6 引入rest参数,用于获取函数的实参,用来代替arguments。
rest参数必须要放到参数最后面
function date(...args) {console.log(args);
}
date('白芷', '陈皮', '决明子'); // ['白芷', '陈皮', '决明子']
function fn(a, b, ...args) {console.log(a); //1console.log(b); //2console.log(args); //[3, 4, 5, 6]
}fn(1, 2, 3, 4, 5, 6);
九、扩展运算符
1、语法结构
【...】 扩展运算符能够将数组转行为逗号分隔的参数序列
const tyboys = ['易烊千玺', '王源', '王俊凯']; // => '易烊千玺', '王源', '王俊凯'
function chunwan (){console.log(arguments);
}
chunwan(...tfboys); //等同于 chunwan('易烊千玺', '王源', '王俊凯')
2、扩展运算符的运用
2.1 数组的合并
const kuaizi = ['王太利', '肖央'];
const fenghuang = ['曾毅', '玲花'];
const zuixuanxiaopingguo = [...kuaizi,...fenghuang];
console.log(zuixuanxiaopingguo);
2.2 数组的克隆(引用类型数据,浅拷贝)
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua];
console.log(sanyecao);
2.3 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs];console.log(divArr);
十、Symbol
1、Symbol的基本使用
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
拓展:JavaScript语言的第七种数据类型 USONB
U: undefined
S: string symbol
O: object
N: null number
B: boolean
1.1 Symbol的特点
(1)Symbol的值是唯一的,用来解决命名冲突的问题
let s = Symbol();
console.log(s, typeof s);
let s2 = Symbol('王者荣耀');
let s3 = Symbol('王者荣耀');
console.log(s2 === s3); /* false */
(2)Symbol值不能与其他数据进行运算
(3)Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。
let s4 = Symbol.for('王者荣耀');
let s5 = Symbol.for('王者荣耀');
console.log(s4 === s5); /* true */
1.2 Symbol创建对象属性
let game = {name: '俄罗斯方块',up: function() {},down: function() {}};
//声明一个对象
let methods = {up : Symbol(),down : Symbol()};
game[methods.up] = function(){console.log('我可以改变形状');}
game[methods.down] = function(){console.log('我可以快速下降');}
console.log(game); //{name: '俄罗斯方块', up: ƒ, down: ƒ, Symbol(): ƒ, Symbol(): ƒ}
let youxi = {name:'狼人杀',[Symbol('say')]:function(){console.log('我可以发言');},[Symbol('zibao')]:function(){console.log('我可以自爆');}};
console.log(youxi); //{name: '狼人杀', Symbol(say): ƒ, Symbol(zibao): ƒ}
2、Symbol的内置值
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,只想语言内部使用的方法。
Symbol.hasInstance | 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法 |
Symbol.isConcatSpeadble | 对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype,concat()时,是否可以展开。 |
Symbol.unscopables | 该对象指定了使用with关键字时,哪些属性会被with环境排除。 |
Symbol.match | 当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。 |
Symbol.replace | 当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值。 |
Symbol.search | 当该对象被str.search(myObject)方法调用时,会返回该方法的返回值。 |
Symbol.split | 当该对象被str.split(myObject)方法调用时,会返回该方法的返回值。 |
Symbol.iterator | 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器。 |
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 |
Symbol.toStringTag | 在该对象上面调用toString方法时,返回该方法的返回值 |
Symbol.species | 创建衍生对象时,会使用该属性。 |
//1、Symbol.hasInstance
class Person {static[Symbol.hasInstance]() {console.log('我被用来检测类型了');}}
let o = {};
console.log(o instanceof Person); //false//2、Symbol.isConcatSpeadble
const arr = [1, 2];
const arr2 = [3, 4, 5];
arr2[Symbol.isConcatSpreadable] = false; //如果设置为false,则代表数组不可展开
console.log(arr.concat(arr2)); //[1, 2, Array(3)]
十一、迭代器
迭代器(Iterator)是一种接口,为各种不同的数据结构提供同意的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
(1)ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费
(2)原生具备iterator接口的数据(可用for of遍历)
Array Arguments Set Map String TypeArray NodeList
(3)工作原理:
① 创建一个指针对象,指向当前数据结构的起始位置
② 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
③ 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
④ 每调用next方法返回一个包含value和done属性的对象
注:需要自定义遍历数据的时候,要想到迭代器。
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用for..of 遍历
//for...of 保存的是键值(遍历数组) for...in 保存的是键名(遍历对象、数组)/*for (let v of xiyou){console.log(v);}*/let iterator = xiyou[Symbol.iterator]();//调用对象的next方法
console.log(iterator.next()); //{value: '唐僧', done: false}
console.log(iterator.next()); //{value: '孙悟空', done: false}
console.log(iterator.next()); //{value: '猪八戒', done: false}
console.log(iterator.next()); //{value: '沙僧', done: false}
console.log(iterator.next()); //{value: undefined, done: true}
//迭代器应用-自定义遍历数组
const banji = {name:"终极一班",stus: ['xiaoming','xiaoning','xiaotian','knight'],[Symbol.iterator](){//索引变量let index = 0;let _this = this;return {next:function(){if (index < _this.stus.length) {const result = {value:_this.stus[index],done:false};//下标自增index++;return result;}else {return {value:undefined;done:true}}}};}}
//遍历这个对象,使用for...of遍历,返回的是这个属性数组里的每一个成员
for (let v of banji) {console.log(v);}
十二、生成器
生成器是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同
生成器是一种特殊的函数,来进行异步编程
function * gen(){//yield作为函数代码的分隔符,三个分隔符产生四个代码yield '一只没有耳朵';yield '一只没有尾巴';yield '真奇怪';
}
for (let v of gen){console.log(v);}
function * gen (arg) {console.log(arg); //AAAlet one = yield 111;console.log(one); //BBBlet two = yield 222;console.log(two); //CCClet three = yield 333;console.log(three); //DDD}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(itrator.next()); //{value: 111, done: false}
//next方法可以传入实参
console.log(itrator.next('BBB')); //{value: 222, done: false}
console.log(itrator.next('CCC')); //{value: 333, done: false}
console.log(itrator.next('DDD')); //{value: undefined, done: true}
生成器实例
1、回调地狱
//1s 后控制台输出 111 2s后输出222 3s后输出333
setTimeout(() => {console.log(111);setTimeout(() => {console.log(222);setTimeout(() => {console.log(333);},3000);},2000);},1000);
function one() {setTimeout(() => {console.log(111);iterator.next();},1000)
}
function two() {setTimeout(() => {console.log(222);iterator.next();},2000)
}
function three() {setTimeout(() => {console.log(333);iterator.next();},3000)
}
function * gen() {yield one();yield two();yield three();
}//调用生成器函数
let iterator = gen();
iterator.next();
2、 模拟获取
//模拟获取 用户数据 订单数据 商品数据
//先后顺序,依次获取function getUsers() {setTimeout(() => {let data = '用户数据';//调用next方法,并且将数据传入iterator.next(data);}, 1000);
}function getOrders() {setTimeout(() => {let data = '订单数据';iterator.next(data);}, 1000);
}function getGoods() {setTimeout(() => {let data = '商品数据';iterator.next(data);}, 1000);
}function* gen() {let users = yield getUsers();console.log(users);let orders = yield getOrders();console.log(orders);let goods = yield getGoods();console.log(goods);
}//调用生成器函数
let iterator = gen();
iterator.next();
十三、Promise(面试常问)
1、基础
1. 1区别实例对象与函数对象
① 实例对象:new函数产生的对象,称为实例对象,简称为对象
② 函数对象:将函数作为对象使用时,称为函数对象
//括号的左边的函数, 点的左边是对象function Fn() { //Fn是函数const fn = new Fn() //此时Fn是构造函数 fn是实例对象,简称为对象console.log(Fn.prototype) //Fn是函数对象Fn.blind({}) //Fn是函数对象$('#text') //jQuery函数$.get('/test') //jQuery函数对象
}
1. 2 两种类型的回调函数
1.2.1 同步回调
概念:立即执行,完全执行完了才结束,不会放入回调队列中
例子:数组遍历相关的回调函数/Promise的excutor函数
const arr = [1, 3, 5]
arr.forEach(item => {console.log(item); //遍历的回调,同步回调函数,不会放入队列,一上来就要执行完
})
console.log('forEach()之后');
1.2.2 异步回调
概念:不会立即执行,会放入回调队列中将来执行
例子:定时器回调、Ajax回调、Promise的成功|失败的回调
setTimeout(() => {console.log('timeout callback()'); //异步回调函数,会放入队列中将来执行
}, 0);
console.log('setTimeout()之后');
1.3 JS的error处理
1.3.1 错误的类型
① Error:所有错误的父类型
② ReferenceError:引用的变量不存在
③ TypeError:数据类型不正确的错误
④ RangError:数据值不在其所允许的范围内
⑤ SyntaxError:语法错误
1.3.2 错误处理
① 捕获错误:try...catch
try {let bconsole.log(b.xxx);} catch (error) {console.log(error); //TypeError: Cannot read properties of undefined (reading 'xxx')}
② 抛出错误:throw error
function something() {if (Date.now() % 2 === 1) {console.log('当前的时间为奇数,可以执行任务');} else { //抛出异常,由调用者来处理throw new Error('当前时间为偶数,无法执行任务')}}//捕获处理异常
try {something()} catch (error) {alert(error.message)}
2、 promise的理解和使用
2.1 Promise是什么
① 抽象表达:Promise是JS中进行异步编程的新的解决方案(旧的是纯回调形式)
② 具体表达:
(1)从语法上来说:Promise是一个构造函数
(2)从功能上来说:Promise对象用来封装一个异步操作并可以获取其结果
2.2 Promise的状态改变
① pendding变为resolved
② pedding变为rejected
说明:只有这2种,且一个promise对象只能改变一次
无论变为成功还是失败,都会有一个结果数据
成功的结果数据一般称为value,失败的结果数据一般称为reason
2.3 Promise的基本流程
2.4 Promise的基本使用
//1、创建一个新的promise对象const p = new Promise((resolve, reject) => { //执行器函数//2、执行异步操作任务setTimeout(() => {const time = Date.now() //如果当前时间是偶数,就代表成功,否则代表失败// 3、(1)如果成功了,调用resolve(value)if (time % 2 == 0) {resolve('成功的数据, time =' + time)} else {// (2)如果失败了,调用rejecte(reason)reject('失败的数据,time' + time)}}, 1000);})//4、p.then(value => { //接收得到成功的value数据 onResolvedconsole.log('成功的回调', value);},reason => { //接收得到失败的reason数据 onRejectedconsole.log('失败的回调', reason);})
2.5 为什么要用Promise ?
① 使指定回调函数的方式更加灵活
(1)旧的:必须在启动异步任务前指定
(2)promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数 (甚至可以在异步任务启动后就指定)
// 1.1使用纯回调函数createAudioFileAsync(audioSettings, successCallback, failureCallback)
// 1.2使用promiseconst promise = createAudioFileAsync(audioSettings);setTimeout(() => {promise.then(successCallback, failureCallback);}, 3000);
② 支持链式调用,可以解决回调地狱的问题
(1)什么是回调地狱?回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件(内层的结果为外层的参数)
(2)回调函数的缺点?不便于阅读/不便于异常处理
(3) 解决方案?promise链式调用
(4)终极解决方案?async/await
//2.1回调地狱doSomething(function(result) {doSomethingElse(result, function(newResult) {doThirdThing(newResult, function(finalResult) {console.log('Got the final result' + finalResult);}, failureCallback)}, failureCallback)}, failureCallback)//2.2 使用promise的链式调用解决回调地狱doSomething().then(function(result) {return doSomethingElse(result)}).then(function(newResult) {return doThirdThing(newResult)}).then(function(finalResult) {lconsole.log('Got the final result' + finalResult)}).catch(failureCallback) //异常传透//2.3 async/await :回调地狱的终极解决方案asnycfunction request() {try {const result = await doSomething();const newResult = await doSomethingElse(result);const finalResult = await doThirdThing(newResult);console.log('Got the final result' + finalResult)} catch (error) {failureCallback(error)}}
2.6 如何使用Promise ?
2.6.1 API
一、Promise构造函数:Promise(excutor){ }
(1)excutor函数:执行器(resolve,reject)=> { }
(2)resolve函数:内部定义成功时我们调用的函数value =>{ }
(3)reject函数:内部定义失败时我们调用的函数 reason =>{ }
说明:excutor会在Promise内部立即同步回调,一步操作在执行器中执行
二、Promise.prototype.then方法:(onResolved,onRejected)=>{ }
onResolved函数:成功回调函数 (value)=> { }
onRejected函数:失败回调函数 (reason)=> { }
说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
三、Promise.prototype.catch方法:(onRejected)=> { }
onRejected函数:失败的回调函数 (reason)=> { }
说明:then()的语法糖,相当于:then(undefined,onRejected)
四、Promise.resolve方法:(value)=> { }
value:成功的数据或promise对象
说明:返回一个成功/失败的promise对象
五、Promise.reject方法:(reason)=> { }
reason:失败的原因
说明:返回一个失败的promise对象
new Promise((resolve, reject) => {setTimeout(() => {resolve('成功的数据')//只能执行一次reject('失败的数据')}, 1000)}).then(value => {console.log('onResolved()1', value);}).catch(reason => {console.log('onRejected()', reason);})
const p1 = new Promise((resolve, reject) => {resolve(1)})const p2 = Promise.resolve(2);const p3 = Promise.reject(3);p1.then(value => {console.log(value)})p2.then(value => {console.log(value)})p3.catch(reason => {console.log(reason)})
2.6.2 Promise的几个关键问题
一、如何改变Promise的状态?
(1)resolve(value):如果当前是pendding就会变为resolved
(2)reject(reason):如果当前是pendding就会变为rejectd
(3)抛出异常:如果当前是pendding就会变为rejectd
const p = new Promise((resolve, reject) => {// resolve(1) //promise变为resolved状态// reject(2) //promise变为rejected状态// throw new Error('出错了') //抛出异常,promise变为rejected失败状态,reason抛出的errorthrow 3})p.then(value => {},reason => {console.log('reason', reason); // 'reason', 3})
二、一个Promise指定多个成功/失败回调函数,都会调用嘛?
当Promise改变为对应状态时都会调用
三、改变Promise状态和指定回调函数谁先谁后?
(1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调
(2)如何先改状态再指定回调?
① 在执行器中直接调用resolve()/ reject()
② 延迟更长时间才能调用then()
(3)什么时候才能得到数据?
① 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
② 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
//1、常规:先执行回调函数,后改变状态new Promise((resolve, reject) => {setTimeout(() => {resolve(1) //后改变状态(同时指定数据),异步执行回调函数}, 1000);}).then( //先指定回调函数,保存当前指定的回调函数value => {},reason => {console.log('reason', reason);})//2、先改状态,后执行回调函数new Promise((resolve, reject) => {resolve(1) //先改变状态(同时指定数据)}).then( //后指定回调函数,异步执行回调函数value => {console.log('value', value);},reason => {console.log('reason', reason);})
四、Promise.then()返回的新的Promise的结果状态由什么决定?
(1)简单表述:由then()指定的回调函数执行的结果决定
(2)详细表述:
① 如果抛出异常,新Promise变为rejected,reason为抛出的异常
② 如果返回的是非Promise的任意值,新Promise变为resolved,value为返回的值
③ 如果返回的是另一个新Promise,此Promise的结果就会成为新Promise的结果
五、Promise如何串连多个操作任务
(1)Promise的then()返回一个新的Promise,可以开成then()的链式调用
(2)通过then的链式调用串连多个同步/异步任务
六、Promise异常传透
(1)当使用Promise的then链式调用时,可以在最后指定失败的回调
(2) 前面任何操作出了异常,都会传到最后失败的回调中处理
七、中断Promise链
(1)当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数
(2)办法:在回调函数中返回一个pendding状态的Promise对象
3、自定义(手写)Promise
3.1 定义整体结构(创建promise.js)
/*
自定义Promise函数模块:IFFE
*/
(function(window) {/*Promise构造函数executor:执行器函数(同步执行)*/function Promise(excutor) {//resolve函数function resolve(data) {}//reject函数function reject (data) {}//同步调用执行器函数executor(resolve,reject);}/*Promise原型对象的then()1.指定成功和失败的回调函数2.函数返回一个新的promise对象*/Promise.prototype.then = function(onResolve, onReject) {}/*Promise原型对象的catch()1.指定失败的回调函数2.函数返回一个新的promise对象*/Promise.prototype.catch = function(onRejectd) {}/*Promise函数对象的resolve方法返回一个指定结果的成功promise*/Promise.resolve = function(value) {}/*Promise函数对象的reject方法返回一个指定结果的失败promise*/Promise.reject = function(reason) {}/*Promise函数对象的all方法返回一个promise,只有当所有promise都成功时,才成功,否则有一个失败,都失败*/Promise.all = function(promises) {}/*Promise函数对象的race方法返回一个promise,其结果由第一个完成的promise来决定*/Promise.race = function(promises) {}//向外暴露promise函数window.Promise = Promise
})(window)
3.2 Promise构造函数的实现
3.3 Promise.then()/ catch()的实现
3.4 Promise.resolve() / reject()的实现
//添加resolve方法Promise.resolve = function(value) {//返回promise对象return new Promise((resolve, reject) => {if (value instanceof Promise) {value.then(v => {resolve(v);}, r => {reject(r);})} else//状态设置成功、resolve(value)});}//添加reject方法Promise.reject = function(reason) {//返回promise对象return new Promise((resolve, reject) => {reject(reason);});}
3.5 Promise.all()的实现
Promise.all = function(promises) {//返回结果为promise对象return new Promise((resolve, reject) => {//遍历for (let i = 0; i < promises.length; i++) {//声明变量let count = 0;let arr = [];//promises[i].then(v => {//得知对象的状态是成功的//每个promise对象都成功,才能执行resolve函数count++;//将当前promise对象成功的结果存入数组arr[i] = v;//判断if (count === promises.length) {resolve(arr);}}, r => {reject(r);})}});}
3.5 Promise.all / race()的实现
Promise.race = function(promises) {return new Promise((resolve,reject)=>{for(let i = 0 ; i < promises.length;i++){promises[i].then(v=>{//修改返回对象值为成功resolve(v);},r=>{//次该范湖对象为失败reject(r);})}});}
4、async与await
4.1 async函数
(1)函数的返回值为promise对象
(2)promise对象的结果由async函数执行的返回值决定
//和then返回规则一样async function main() {//1、如果返回值是一个非promise类型的数据// return 521;//2、如果返回值是一个promise对象return new Promise((resolve, reject) => {// resolve('ok');reject('error');})//3、抛出异常throw "oh no";};let result = main();console.log(result);
4.2 await表达式
(1)await右侧的表达式一般为promise对象,但也可以是其他的值
(2)如果表达式是promise对象,await返回的是promise成功的值
(3)如果表达式是其他值,直接将此值作为await的值
注意:
(1)await必须写在async函数中,但async函数中可以没有await
(2)如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
//await必须写在async函数中,但async函数中可以没有await// await 10; //Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modulesasync function main() {let p = new Promise((resolve, reject) => {// resolve('ok');reject('error');});//1、右侧为promise的情况// await返回值是promise成功的值let res = await p;console.log(res); //ok//2、右侧为其他类型的数据//直接将此值作为await的值let res2 = await 20;console.log(res2); //20//3、如果promise是失败的状态try {let res3 = await p;} catch (e) {console.log(e); //error}}main();
十四、Set
ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和for...of进行遍历,集合的属性和方法:
(1)size 返回集合的元素个数
(2)add 增加一个新元素,返回当前集合
(3)delete 删除元素,返回boolean值
(4)has 检测集合中是否包含某个元素,返回boolean值。
//声明一个setlet s = new Set();let s2 = new Set(['大事', '小事', '没事']);console.log(s, typeof s); //Set(0) {size: 0}[[Entries]]无属性size: 0[[Prototype]]: Set 'object'console.log(s2, typeof s2); //Set(3) {'大事', '小事', '没事'} 'object'//1、元素个数console.log(s2.size); //3//添加新的元素s2.add('喜事');console.log(s2); //Set(4) {'大事', '小事', '没事', '喜事'}//删除元素s2.delete('喜事');console.log(s2);//2、检测console.log(s2.has('大事')); //true//3、清空s2.clear();console.log(s2); //Set(0) {size: 0}//遍历for (let v of s2) { console.log(v);}
案例:
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];//1、数组去重let result = [...new Set(arr)];console.log(result);//2、交集let arr2 = [4, 5, 6, 5, 6];//filter创建一个数组,符合条件的都放进去(过滤器)let result = [...new Set(arr)].filter(item => {let s2 = new Set(arr2); //4.5.6if(s2.has(item)){return true;}else {return false;}}); //简写let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));console.log(result); //[4,5]//3、并集let union = [...new Set([...arr, ...arr2])];console.log(union); //合并arr和arr2数组 [1, 2, 3, 4, 5, 6]//4、差集//用arr和arr2比较let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
十五、Map
ES6提供了Map数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了iterator接口,所以可以使用扩展运算符和for...of进行遍历。Map的属性和方法:
(1)size 返回Map的元素个数
(2)set 增加一个新元素,返回当前Map
(3)get 返回键名对象的键值
(4)has 检测Map中是否包含某个元素,返回Boolean值
(5)clear 清空集合,返回undefined
十六、class类
function Phone() {}// Phone是函数对象,属于类,不属于实例对象Phone.name = '手机';Phone.change = function() {console.log('我可以改变世界');}Phone.prototype.size = '5.5inch';//nokia是实例对象let nokia = new Phone();console.log(nokia.name); //undefinedconsole.log(nokia.size); //5.5inch
class Phone {//静态属性 static标注的属性和方法,属于class类,不属于实例对象vivostatic name = '手机';static change() {console.log('手机真好玩');}}let vivo = new Phone();console.log(vivo.name); //undefinedconsole.log(Phone.name); //手机
十七、数值扩展
1、Number.EPSILON是JavaScript表示的最小精度
EPSILON属性的值接近于2.2204460492503130808472633361816E-16(主要用作在浮点数上)
function equal(a, b) {if (Math.abs(a - b) < Number.EPSILON) {return true;} else {return false;}}console.log(0.1 + 0.2 === 0.3); //falseconsole.log(equal(0.1 + 0.2, 0.3)); //true
2、二进制和八进制
let b = 0b1010; //二进制let o = 0o777; //八进制let d = 100; //十进制let x = 0xff; //十六进制console.log(b); //10console.log(d); //100
3、Number.inFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100)); //true
console.log(Number.isFinite(100 / 0)); //false
console.log(Number.isFinite(Infinity));//false
4、Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(123)); //false
5、Number.parseInt / Number.parseFloat字符串转整数
console.log(Number.parseInt('5201314love')); //5201314console.log(Number.parseFloat('3.1415926神奇'));//3.1415926
6、Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(5)); //true
console.log(Number.isInteger(2.55));//false
7、Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5)); //3
8、Math.sign 判断一个数到底为正数、负数还是零
console.log(Math.sign(100)); //1
console.log(Math.sign(0)); //0
console.log(Math.sign(-250)); //-1
十八、对象扩展
1、Object.is 判断两个值是否完全相等
console.log(Object.is(120, 121)); //作用和===很像console.log(Object.is(NaN, NaN)); //trueconsole.log(NaN === NaN); //false
2、Object.assign对象的合并
const config1 = {hose: 'localhost',port: 3306,name: 'root',pass: 'root',text: 'test',};const config2 = {host: 'http://baidu.com',port: 33060,name: 'baidu',pass: 'iloveyou'};console.log(Object.assign(config1, config2));//{hose: 'localhost', port: 33060, name: 'baidu', pass: 'iloveyou', text: 'test', …}// hose: "localhost"// host: "http://baidu.com"// name: "baidu"// pass: "iloveyou"// port: 33060// text: "test"// [[Prototype]]: Object
3、Object.setPrototypeOf / Object.getPrototypeOf
const school = {name: 'beida'};
const city = {xiaoqu: ['北京', '上海', '深圳']};
Object.setPrototypeOf(school, city);
console.log(Object.getPrototypeOf(school)); //{xiaoqu: Array(3)}
console.log(school); //{name: 'beida'}
十九、模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
1、模块化的好处
(1)防止命名冲突
(2)代码复用
(3)高维护性
2、模块化规模产品
ES6之前的模块化规范有:
(1)CommonJs => NodeJs、Browserify
(2)AMD => requireJS
(3)CMD => seaJS
3、ES6模块化语法
模块功能主要由两个命令构成:export和import
(1)export命令用于规定模块的对外接口
(2)import命令用于输入其他模块提供的功能
ECAMScript6基础知识相关推荐
- 嵌入式Linux的OTA更新,基础知识和实现
嵌入式Linux的OTA更新,基础知识和实现 OTA updates for Embedded Linux, Fundamentals and implementation 更新的需要 一旦嵌入式Li ...
- 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记
计算机文化基础(第十讲)学习笔记 采样和量化PictureElement Pixel(像素)(链接: 采样的实质就是要用多少点(这个点我们叫像素)来描述一张图像,比如,一幅420x570的图像,就表示 ...
- 嵌入式linux编程,嵌入式Linux学习笔记 - 嵌入式Linux基础知识和开发环境的构建_Linux编程_Linux公社-Linux系统门户网站...
注:所有内容基于友善之臂Mini2440开发板 一.嵌入式Linux开发环境的构建 嵌入式开发一般分为三个步骤: 1.编译bootloader,烧到开发板 2.编译嵌入式Linux内核,烧到开发板 3 ...
- 《计算机网络应用基础》模拟试卷(六),《计算机与网络应用基础知识1》模拟试卷...
<计算机与网络应用基础知识1>模拟试卷 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 <计算机与网络应用基础知识1& ...
- python向量计算库教程_NumPy库入门教程:基础知识总结
原标题:NumPy库入门教程:基础知识总结 视学算法 | 作者 知乎专栏 | 来源 numpy可以说是 Python运用于人工智能和科学计算的一个重要基础,近段时间恰好学习了numpy,pandas, ...
- python常用变量名_python基础知识整理
Python Python开发 Python语言 python基础知识整理 序言:本文简单介绍python基础知识的一些重要知识点,用于总结复习,每个知识点的具体用法会在后面的博客中一一补充程序: 一 ...
- 计算机基础知识掌握欠缺,《计算机基础知识》实验教学改革探讨.pdf
<计算机基础知识>实验教学改革探讨.pdf Science& TechnologyVision 科 技 视 界 科技 探·索·争鸣 计<算机基础知识>实验教学改革探讨 ...
- python计算wav的语谱图_Python实现电脑录音(含音频基础知识讲解)
前言 今天开始进入近期系列文章的第一篇,如何用 Python 来实现录音功能. 在开始"造轮子"之前,个人一直强调一个观点,如果有些东西已经有了,不妨直接去 github 上搜,用 ...
- 计算机wrod初级考试题及答案,计算机基础知识+Word基础知识+Excel基础知识试题答案解析.doc...
文档介绍: 计算机基础知识+ Word基础知识+ Excel基础知识 第一部分 一.单项选择题 1.世界上第一台电子数字计算机取名为( ). A.UNIVAC B.EDSAC C.E ...
最新文章
- 最短路径dijkstra
- 记一次Nacos的issue修复之并发导致的NPE异常
- DNS服务器详解--------基础篇
- python笔试题(1)
- 客户关系管理系统-帮管客CRM客户管理系统 v3.0.1
- 数学物理方法pdf_中考状元笔记九科(语文+数学+物理+化学+英语+历史+地理+政治+生物)(高清PDF);...
- Bootstrap:弹出框和提示框效果以及代码展示
- system.data oracleClient 需要Oracle客户端8.1.7或high
- 荒芜的周六-PHP之面向对象(三)
- BZOJ4152 AMPPZ2014 The Captain 【最短路】【贪心】*
- 【路径规划】基于NSGA2实现无人机三维路径规划matlab源码
- vs2013 Matlab 2018 (64)混合编程
- 离散数学_命题逻辑_部分习题
- python单例模式例子_python单例模式实例分析
- python SMTP发送带图片的邮件时,报TypeError: Could not guess image MIME subtype错误的解决办法
- HbuilderX连接Nox(夜神模拟器)
- mybatis-plus过滤不查询某一字段
- ebs查看服务状态_监控您的卷状态 - Amazon Elastic Compute Cloud
- JAVA-国密算法SM3和SM4应用Example
- android+实现微信对话框样式,实现微信对话框的图片样式以及图片边框