迭代器
迭代器(iterator)是一种可以为各种不同的数据结构提供统一遍历操作的接口,JAVA、C++、Python、PHP等很多语言都有迭代器的概念,对象只要部署了iterator接口,就可以进行遍历操作(如用for语句进行遍历)。
迭代器的遍历
迭代器遍历的原理是这样的:
- 创建一个指针对象,指向当前数据结构的起始位置;
- 调用指针对象的next方法,指针指向数据结构的第一个成员;
- 重复调用next方法,指针后移动,直至指向最后一个成员;
以最常见的遍历数组为例:我们可以用for…of等语句对其进行遍历,是因为数组中原生内置了iterator接口。
const songs=['夜曲','手写的从前','反方向的钟','晴天','最长的电影'];
console.log(songs);

按照其原理,先定义一个对象来获取该Symbol.iterator属性,找到该对象中包含的next方法。调用这个next()方法,它会返回一个包含done和value属性的对象。
const songs=['夜曲','手写的从前','最长的电影','晴天','明明就'];
// console.log(songs);
let iterator=songs[Symbol.iterator]();
console.log(iterator);
console.log(iterator.next());

重复调用next()方法,该方法会依次遍历数组成员并返回多个包含done和value属性的对象,遍历完数组后,再返回一个done属性值为true,value属性值为undefined的对象,表示数组遍历结束。

在JavaScript中,原生自带iterator接口的数据结构有:
Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象
自定义遍历对象
对于没有内置iterator接口的数据结构,可以仿照其原理,手写一个iterator接口,并且自定义需要遍历或者允许被遍历的内容。
按照其原理,添加iterator接口的步骤分为:
- 添加Symbol.iterator属性,它是以一个函数的形式包含;
- 在其中添加next()方法;
- next()方法会依次返回一个包含done和value属性的对象;
- 如果遍历结束,则返回一个done属性值为true,value属性值为undefined的对象;
//遍历输出对象的songs属性
const Rapper={
name:'王以太',
shows:['Chengdu','Hangzhou','Shenzhen'],
songs:['三思而后行','阿司匹林','童言无忌','目不转睛','人间天堂'],
[Symbol.iterator](){
let index=0;//索引号
return{
next: ()=>{
if(index< this.songs.length){
const result={
value:this.songs[index],
done:false};
index++;
return result;
}
else{
return{
value:undefined,
done:true
}
}
}
}
}
};
//遍历输出
for(let m of Rapper){
console.log(m);
}
生成器函数
生成器函数允许我们定义一个包含自有迭代算法的函数,返回一种称为 Generator 的迭代器,生成器函数需要使用function *语法声明
yield关键字
yield 关键字用于生成器函数的暂停和恢复,当执行Generator迭代器的next()方法时,开始执行生成器中的代码,一旦遇到 yield 表达式,生成器的代码将被暂停运行,直到生成器的 next() 方法再次被调用,暂停时yield 关键字后面的表达式的值返回给生成器的调用者,类似于一个基于生成器的版本的 return 关键字
[rv] = yield [expression];
- rv 返回传递给生成器的 next() 方法的可选值,以恢复其执行
- expression:定义通过迭代器协议从生成器函数返回的值。如果省略,则返回 undefined
next()方法传参
next() 方法接受一个参数用于修改生成器内部状态,传递给 next() 的参数值会被 yield 接收。传递给第一个 next() 的值会被忽略,而传递给第二个 next() 的值会被第一个 yield 接收,依此类推
异步调用
由于生成器函数每次执行到yield语句就会暂停,利用这个特性我们可以进行对资源的异步顺序加载,
Promise
Promise是ES6新增的异步编程解决方案,用于封装异步任务,并且可以根据异步任务的成功/失败,对结果和数据进行灵活处理,此外,Promise支持链式调用,能很好地解决回调地狱问题
Promise对象
Promise本质上是一个函数返回的对象,代表了一个异步操作的成功或者失败,该对象中有两个关键属性:PromiseState和PromiseResult
PromiseState 即Promise的状态,Promise有三种状态:
- pending 未决定的
- resolved/fulfilled 决定的,符合的(成功)
- rejected 拒绝的(失败)
该属性只能被修改一次,并且修改完毕后也只有一个结果(resolved或rejected)和结果数据
PromiseResult即Promise封装的异步任务成功/失败的结果数据,只能通过resolve()或reject()函数修改,并且可以传递给then()方法,Promise成功时结果数据一般使用value为实参名,失败则使用reason作为实参名
实例化
使用new关键字进行实例化,实例化时接收一个函数类型的参数,该函数又接收两个函数类型的形参,resolve()用于异步任务执行成功时调用,reject()用于异步任务执行失败时调用
当resolve被调用后,Promise状态会被修改为成功,随后执行then()方法的第一个回调函数。reject则会将Promise状态会被修改为失败,随后执行then()方法的第二个回调函数
API
执行流程
通过new创建Promise对象,对象初始状态为pending状态,然后执行内部的异步操作,执行成功则调用resolve()函数,将Promise对象状态修改为resolved状态,此时如果调用了then()方法,则将执行then()方法中的第一个回调函数,执行完该回调函数后返回一个新的promise()对象。如果异步任务执行失败,则调用reject()函数,将Promise对象状态修改为rejected状态,此时如果调用了then()方法,则将执行then()方法中的第二个回调函数,执行完该回调函数后返回一个新的promise()对象
构造函数
Promise((excutor){})
该构造函数接收一个执行器函数,内部定义了resolve()和reject()函数,这两个函数不属于Promise对象内部,执行器函数会在对象创建后立即执行(同步调用)
快速获取Promise对象
以下方法属于Promise函数对象,可以直接调用
- Promise.resolve(value)
value可以为任意类型的数据,或者一个Promise对象
返回一个成功的Promise对象,但如果传入了一个Promise对象,则其状态取决于传入对象的状态,如果传入的Promise对象为成功,则返回的对象也为成功状态,反之亦然。该方法用于快速将一个数据转换为一个状态为成功的Promise对象const p1=Promise.resolve(100);// const p2=Promise.resolve(new Promise((resolve,reject)=>{ reject();//由于传入的Promise对象状态为rejected,依次p2也为rejected状态 }))
Promise.reject(value)
永远返回一个rejected状态的Promise对象,即便传入的值是成功状态的PromisePromise.all(promise[])
参数为一个Promise数组,只有当该数组中的所有Promise对象状态都为resolved时,该方法才返回一个resolve状态的Promise对象,且该对象的PromiseResult为数组中的Promise对象成功结果组成的数组。如果该数组中有任意一个Promise对象状态为rejected,则该方法返回的Promise对象状态将修改为rejected,且该对象的PromiseResult为数组中第一个失败成员的返回的PromiseResultlet p1=Promise.resolve(123) let p2=Promise.reject("aaa") let p3=Promise.reject({test:0}) let p=Promise.all([p1,p2,p3]); console.log(p);//p对象的PromiseResult为"aaa"p2.catch(reason=>{}); p3.catch(reason=>{}); p.catch(reason=>{});</div>
否则返回一个rejected状态的Promise
- Promise.race(promise[])
参数为一个Promise数组,该方法返回的Promise对象的状态取决中传入数组中第一个执行完异步任务的Promise对象状态,且值也为其PromiseResult
修改Promise状态的方法
- resolve函数
- reject函数
- throw 函数
执行多个回调
Promise允许指定多个回调,即可以指定多个then()方法
let p=new Promise((resolve,reject)=>{ resolve("go"); }); p.then(value=>{ console.log("第一个回调"+value); }); p.then(value=>{ console.log("第二个回调"+value); });then()方法返回值
then()方法会返回一个新的Promise对象,该对象的状态和值取决于then()方法所执行的回调函数
- 如果该回调函数返回一个Promise对象,则then()方法返回的Promise对象状态与其相同
- 如果该回调函数无return语句(默认返回undefined),或者返回一个非Promise对象的值(如:返回字符串等),则总是返回一个fulfilled状态的Promise
- 如果该回调函数throw异常,则返回rejected状态的Promise对象
let p=new Promise((resolve,reject)=>{ resolve(); }) let result1=p.then(value=>{throw '异常'});//状态为rejected let result2=p.then(value=>{return 'aaa'});//状态为fulfilled let result3=p.then(value=>{ return new Promise((resolve,reject)=>{ reject('error'); }) });//状态为rejected链式调用
由于then()方法返回了一个新的Promise对象,因此该对象也可以调用then()方法,而该then()方法又返回一个新的Promise对象,又能调用then()方法,因此then()方法可以链式调用
let p=new Promise((resolve,reject)=>{ resolve('success'); }) p.then(value=>{ console.log(value);//success }).then(value=>{ console.log(value);//由于上一个then()无返回值,因此其返回的Promise对象的PromiseResult为undefined,因此输出undefined })异常穿透
当then()方法进行链式调用时,只需要在最后进行异常处理,前面的链式调用出现的任何异常,都会被传到最后处理异常的回调函数中进行处理(异常穿透特性)
let p=new Promise((resolve,reject)=>{ resolve('success'); }) p.then(value=>{ console.log(value); throw '异常' //抛出异常 }).then(value=>{ console.log(value);//由于上一个Promise状态为rejected,then()方法第一个回调不执行 }).then(value=>{ console.log(value);//同上,不执行 }).then(value=>{ console.log(value);//同上,不执行 }).catch(reason=>{ console.warn(reason);//在链式最后进行异常处理 })中断Promise链
当then()方法进行链式调用时,如果想在某个节点中断Promise链,只需要在该节点返回一个pending状态的Promise对象,因为处于pending状态的Promise对象不会触发then()方法的执行,而其他任何返回值、异常抛出等操作都会使链式继续进行。注意:中断以后的Promise链,最后的异常捕获会依旧执行
let p=new Promise((resolve,reject)=>{ resolve('success'); }) p.then(value=>{ console.log(111);//输出111 throw 'error' }).then(value=>{ return new Promise(()=>{});//返回pending状态的Promise对象 }).then(value=>{ console.log(222);//上一个Promise对象为pending状态,不执行then()方法 }).catch(reason=>{ console.warn(reason);//但由于异常穿透,该语句会继续执行 })async与await
async函数
async函数可以帮助我们用更简洁的方式写出基于 Promise 的异步行为,用于包裹await表达式,该函数会返回一个Promise对象,对象的状态取决于async函数的返回值:
- 如果该函数无return语句(默认返回undefined),或者返回一个非Promise对象的值(如:返回字符串等),则返回一个fulfilled状态的Promise对象
- 如果该函数返回一个Promise对象,则async函数返回的Promise对象状态与其相同
- 如果该函数throw异常,则返回rejected状态的Promise对象
await表达式
await表达式必须用async函数包裹,其右侧一般为Promise对象,也可以为其他值
- 如果为其他值,则await返回值与其相同
- 如果为Promise对象,则返回值为该对象fulfilled状态下的PromiseResult属性值
- 如果为Promise对象,且状态为rejected,则必须用try…catch进行异常捕获处理
async function main(){ try{ let result=await new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('success') },1000) }) console.log(result); } catch(e){ console.warn(e) } } main();AJAX
简介
AJAX为Asynchronous JavaScript And XML的缩写,即异步 JavaScript 和 XML,用于更新数据,而不需要重载(刷新)整个页面
XMLHttpRequest对象
Ajax 需要依赖于 XMLHttpRequest 对象,主流浏览器都支持 XMLHttpRequest 对象,只需要new即可
let xmlhttp=new XMLHttpRequest();E5和IE6等低版本IE浏览器不支持XMLHttpRequest 对象,而需要使用ActiveX 对象,因此如果需要兼顾低版本IE浏览器,则需要做兼容性检查
var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest();//主流浏览器 } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");//低版本IE浏览器 }XMLHttpRequest对象方法
- open(请求类型,url,async,user,psw) 书写一个请求
- 请求类型:GET 或POST
- url为文件位置
- async:是否异步,值为true(异步)或 false(同步)
- user:用户名称(可选)
- psw: 用户密码(可选)
- send() 发送请求,用于GET请求
- send(string)发送请求,用于POST请求
- abort()取消当前请求
- setRequestHeader() 向要发送的报头添加标签/值对
- getResponseHeader() 返回特定的头部信息
- getAllResponseHeaders() 返回头部信息
XMLHttpRequest对象属性
- onreadystatechange 定义当 readyState 属性发生变化时被调用的函数
- readyState 表示当前 XMLHttpRequest 的状态
- 0:UNSET,尚未调用open方法,请求未初始化,
- 1:OPEND,open方法被调用,服务器连接已建立
- 2:HEADERS_RECEIVED,send()方法被调用,请求已收到
- 3:LOADING,正在处理请求,response属性已经包含部分数据
- 4:DONW,请求已完成且响应已就绪
- responseText 以字符串返回响应数据
- responseXML 以 XML 数据返回响应数据
- statusText 返回状态文本(比如 “OK” 或 “Not Found”)
- status 返回请求的状态号
发起请求
发起get请求
如果get请求需要携带参数,可以直接在URL地址后以键值对的形式拼接查询字符串,多个参数使用&拼接
xhr.open('GET','http://shiwivi.com')xhr.open('GET','http://shiwivi.com?id=1&author=shiwivi')let xhr=new XMLHttpRequest(); xhr.open('GET','http://shiwivi.com') xhr.send(); xhr.onreadystatechange=function(){ if(xhr.readyState===4&&xhr.status===200){ console.log(xhr.responseText) } }发起post请求
AJAX发起post请求主要需要如下流程:
- 创建xhr对象
- 调用open()方法初始化请求
- 设置content-type属性,指定请求头所含数据MIME类型为application/x-www-form-urlencoded,即进行了URL编码的二进制数据
- 调用send()方法,并指定请求所需要包含的数据
- 监听onreadystatechange事件
var xhr=new XMLHttpRequest(); xhr.open('POST','http://shiwivi.com'); xhr.setRequestHeader('content-Type','application/x-www-form-urlencoded') xhr.send('id=1&author=shiwivi'); xhr.onreadystatechange=function(){ if(xhr.readyState===4&&xhr.status===200){ console.log(xhr.responseText) } }URL中只允许出现英文字母、数字、标点符号,在拼接查询字符串时,如果我们在URL中拼接了中文字符,或者其他被预定义的字符,则浏览器会对其进行URL编码,其中中文字符会被编码为%xx%xx%xx形式(x为16进制数),JavaScript中可以使用encodeURI('字符串')对该字符串进行编码,使用decodeURI('%xx%xx')对该字符串进行解码JQuery中的Ajax
JQuery对XMLHttpRequest进行了封装
发起get请求
$.get(url,[data],[function(){…}]) 发起get请求
- url为请求地址,必须
- data为请求所携带的参数,非必须,参数也可以以查询字符串的形式拼接到URL后
- function可以指定请求成功执行的回调,非必须
$(function(){ $.get('http://shiwivi.com',function(res){ console.log(res)//res用于接收返回的数据 }) })$.get('http://shiwivi.com',{id:1,author:''shiwivi},function(res){...}) //等价于 $.get('http://shiwivi.com?id=1&author=shiwivi',function(res){...})发起post请求
$.post(url,[data],[function(){…}]) 发起post请求
- url为提交数据地址,必须
- data为所要提交的数据,非必须
- function可以指定请求成功执行的回调,非必须
$(function(){ $.post('http://xxxx.com',{name:'shiwivi',type:'blog'},function(res){ console.log(res) }) })get与post通用
$.ajax({
type:’get/post/put/delete’,
url:’’,
data:{ },
dataType:’html/text/json/xml/script/jsonp’,
success:function(res,textStatus,jqXHR){ },
error:function(jqXHR,textStatus,error){ }
})- type为请求方式,可选get/post/put/delete,默认get
- url为请求地址
- data为请求携带的数据
- dataType为请求数据类型
- success为请求成功执行的回调函数,参数依次为响应内容(根据dataType作了处理)、文本形式的响应状态、jqXHR对象(里面包含状态码等信息)
- error为请求失败执行的回调函数,参数依次为jqXHR对象、文本形式的错误信息(eg:error、timeout、abort)、捕获的异常对象(对于http请求为http状态的文本部分eg:Not Found)
$.ajax({ type:'GET', url:'http://shiwivi.com', data:{id:1}, success:function(res,textStatus,jqXHR){ console.log(res);//服务器返回的数据 console.log(textStatus);//success console.log(jqXHR.status);//200 }, error:function(jqXHR,textStatus,error){ console.error(jqXHR.status);//404 console.log(textStatus);//error console.log(error);//Not Found } })- Promise.race(promise[])