中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

織夢(mèng)網(wǎng)站首頁(yè)打開(kāi)慢百度客戶電話

織夢(mèng)網(wǎng)站首頁(yè)打開(kāi)慢,百度客戶電話,無(wú)錫室內(nèi)設(shè)計(jì)學(xué)校,淮安做網(wǎng)站公司一、迭代器與可迭代對(duì)象 1.什么是迭代器 迭代器(iterator),使用戶在容器對(duì)象(container,例如鏈表或數(shù)組)上遍訪的對(duì)象,使用該接口無(wú)需關(guān)心對(duì)象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。 其行為像數(shù)據(jù)庫(kù)中的光標(biāo)&…

一、迭代器與可迭代對(duì)象

1.什么是迭代器

迭代器(iterator),使用戶在容器對(duì)象(container,例如鏈表或數(shù)組)上遍訪的對(duì)象,使用該接口無(wú)需關(guān)心對(duì)象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。

  • 其行為像數(shù)據(jù)庫(kù)中的光標(biāo),迭代器最早出現(xiàn)在1974年設(shè)計(jì)的CLU編程語(yǔ)言中;
  • 在各種編程語(yǔ)言的實(shí)現(xiàn)中,迭代器的實(shí)現(xiàn)方式各不相同,但是基本都有迭代器,比如Java、Python等;

從迭代器的定義我們可以看出來(lái),迭代器是幫助我們對(duì)某個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行遍歷的對(duì)象。

在JavaScript中,迭代器也是一個(gè)具體的對(duì)象,這個(gè)對(duì)象需要符合迭代器協(xié)議(iterator protocol):

  • 迭代器協(xié)議定義了產(chǎn)生一系列值(無(wú)論是有限還是無(wú)限個(gè))的標(biāo)準(zhǔn)方式;
  • 在JavaScript中這個(gè)標(biāo)準(zhǔn)就是一個(gè)特定的next方法

next方法有如下的要求:

  • 一個(gè)無(wú)參數(shù)或者一個(gè)參數(shù)的函數(shù),返回一個(gè)應(yīng)當(dāng)擁有以下兩個(gè)屬性的對(duì)象:
  • done(boolean)
    • 如果迭代器可以產(chǎn)生序列中的下一個(gè)值,則為 false。(這等價(jià)于沒(méi)有指定 done 這個(gè)屬性。)
    • 如果迭代器已將序列迭代完畢,則為 true。這種情況下,value 是可選的,如果它依然存在,即為迭代結(jié)束之后的默認(rèn)返回值。
  • value
    • 迭代器返回的任何 JavaScript 值。done 為 true 時(shí)可省略。
const names = ["abc", "cba", "nba"]// 給數(shù)組names創(chuàng)建一個(gè)迭代器(迭代器: names的跌大氣)
let index = 0
const namesIterator = {next: function() {// done: Boolean// value: 具體值/undefinedif (index < names.length) {return { done: false, value: names[index++] }} else {return { done: true }}}
}console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())// 數(shù)組nums
const nums = [100, 24, 55, 66, 86]let indexNum = 0
const numsIterator = {next: function() {// done: Boolean// value: 具體值/undefinedif (indexNum < nums.length) {return { done: false, value: nums[indexNum++] }} else {return { done: true }}}
}

創(chuàng)建數(shù)組迭代器

const names = ["abc", "cba", "nba"]
const nums = [100, 24, 55, 66, 86]// 封裝一個(gè)函數(shù)
function createArrayIterator(arr) {let index = 0return {next: function() {if (index < arr.length) {return { done: false, value: arr[index++] }} else {return { done: true }}}}
}const namesIterator = createArrayIterator(names)
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())const numsIterator = createArrayIterator(nums)
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())

2.可迭代對(duì)象

但是上面的代碼整體來(lái)說(shuō)看起來(lái)是有點(diǎn)奇怪的:

  • 我們獲取一個(gè)數(shù)組的時(shí)候,需要自己創(chuàng)建一個(gè)index變量,再創(chuàng)建一個(gè)所謂的迭代器對(duì)象;
  • 事實(shí)上我們可以對(duì)上面的代碼進(jìn)行進(jìn)一步的封裝,讓其變成一個(gè)可迭代對(duì)象

什么又是可迭代對(duì)象呢?

  • 它和迭代器是不同的概念;
  • 當(dāng)一個(gè)對(duì)象實(shí)現(xiàn)了iterable protocol協(xié)議時(shí),它就是一個(gè)可迭代對(duì)象;
  • 這個(gè)對(duì)象的要求是必須實(shí)現(xiàn) @@iterator 方法,在代碼中我們使用 Symbol.iterator 訪問(wèn)該屬性;

當(dāng)然我們要問(wèn)一個(gè)問(wèn)題,我們轉(zhuǎn)成這樣的一個(gè)東西有什么好處呢?

  • 當(dāng)一個(gè)對(duì)象變成一個(gè)可迭代對(duì)象的時(shí)候,就可以進(jìn)行某些迭代操作;
  • 比如 for…of 操作時(shí),其實(shí)就會(huì)調(diào)用它的 @@iterator 方法;
const iterableObj = {friends: ["Kobe", "Yaoming", "James"],[Symbol.iterator]: function () {let index = 0return {next: () => {if (index < this.friends.length) {return {done: false, value: this.friends[index++]}} else {return {done: true}}}}}
}
for (const item of iterableObj) {console.log(item)
}
const objIterator = iterableObj[Symbol.iterator]()
console.log(objIterator.next())
console.log(objIterator.next())

優(yōu)化版本

const info = {name: "zhangsan",age: 18,height: 1.88,[Symbol.iterator]: function () {let index = 0const entries = Object.entries(this)const iterator = {next: function () {if (index < entries.length) {return {done: false, value: entries[index++]}} else {return {done: true}}}}return iterator}
}

3.原生迭代器對(duì)象

事實(shí)上我們平時(shí)創(chuàng)建的很多原生對(duì)象已經(jīng)實(shí)現(xiàn)了可迭代協(xié)議,會(huì)生成一個(gè)迭代器對(duì)象的:

  • String、Array、Map、Set、arguments對(duì)象、NodeList集合;
// 1.數(shù)組
// const names = ["abc", "cba", "nba"]
// for (const name of names) {
//   console.log(name)
// }
// console.log(names[Symbol.iterator]())// 2.Set
// const set = new Set(["abc", "cba", "nba"])
// for (const item of set) {
//   console.log(item)
// }
// const setIterator = set[Symbol.iterator]()
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log(setIterator.next())// 3.arguments
function foo() {for (const arg of arguments) {console.log(arg)}
}foo(123, 321, 111, 222)

4.可迭代對(duì)象的應(yīng)用

那么這些東西可以被用在哪里呢?

  • JavaScript中語(yǔ)法:for-of、展開(kāi)語(yǔ)法(spread syntax)、yield*(后面講)、解構(gòu)賦值(Destructuring_assignment);
  • 創(chuàng)建一些對(duì)象時(shí):new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);
  • 一些方法的調(diào)用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);
// 1.數(shù)組
// const names = ["abc", "cba", "nba"]
// for (const name of names) {
//   console.log(name)
// }
// console.log(names[Symbol.iterator]())// 2.Set
// const set = new Set(["abc", "cba", "nba"])
// for (const item of set) {
//   console.log(item)
// }
// const setIterator = set[Symbol.iterator]()
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log(setIterator.next())
// console.log(setIterator.next())// 3.arguments
function foo() {for (const arg of arguments) {console.log(arg)}
}foo(123, 321, 111, 222)

二、自定義類的迭代器

1.自定義類的迭代

在前面我們看到Array、Set、String、Map等類創(chuàng)建出來(lái)的對(duì)象都是可迭代對(duì)象:

  • 在面向?qū)ο箝_(kāi)發(fā)中,我們可以通過(guò)class定義一個(gè)自己的類,這個(gè)類可以創(chuàng)建很多的對(duì)象:
  • 如果我們也希望自己的類創(chuàng)建出來(lái)的對(duì)象默認(rèn)是可迭代的,那么在設(shè)計(jì)類的時(shí)候我們就可以添加上 @@iterator 方法;

案例:創(chuàng)建一個(gè)classroom的類

  • 教室中有自己的位置、名稱、當(dāng)前教室的學(xué)生;
  • 這個(gè)教室可以進(jìn)來(lái)新學(xué)生(push);
  • 創(chuàng)建的教室對(duì)象是可迭代對(duì)象;
class Classroom {constructor(position, name, studentList) {this.position = positionthis.name = namethis.studentList = studentList}push(student) {this.studentList.push(student)}[Symbol.iterator]() {let index = 0const iterator = {next: () => {if (index < this.studentList.length) {return {done: false, value: this.studentList[index++]}} else {return {done: true}}}}return iterator}}const classroom = new Classroom("二樓", "高三二班", ["張三", "李四", "王五"])
classroom[Symbol.iterator]()
for (const stu of classroom) {console.log(stu)
}

三、迭代器的中斷

迭代器在某些情況下會(huì)在沒(méi)有完全迭代的情況下中斷:

  • 比如遍歷的過(guò)程中通過(guò)break、return、throw中斷了循環(huán)操作;
  • 比如在解構(gòu)的時(shí)候,沒(méi)有解構(gòu)所有的值;

那么這個(gè)時(shí)候我們想要監(jiān)聽(tīng)中斷的話,可以添加return方法:

class Classroom {constructor(position, name, studentList) {this.position = positionthis.name = namethis.studentList = studentList}push(student) {this.studentList.push(student)}[Symbol.iterator]() {let index = 0const iterator = {next: () => {if (index < this.studentList.length) {return {done: false, value: this.studentList[index++]}} else {return {done: true}}},return() {console.log("我被中斷啦")return {done: true}}}return iterator}}const classroom = new Classroom("二樓", "高三二班", ["張三", "李四", "王五"])
classroom[Symbol.iterator]()
for (const stu of classroom) {console.log(stu)if (stu === "李四") {break}
}

四、生成器的理解和作用

1.什么是生成器?

生成器是ES6中新增的一種函數(shù)控制、使用的方案,它可以讓我們更加靈活的控制函數(shù)什么時(shí)候繼續(xù)執(zhí)行、暫停執(zhí)行等。

  • 平時(shí)我們會(huì)編寫很多的函數(shù),這些函數(shù)終止的條件通常是返回值或者發(fā)生了異常。

生成器函數(shù)也是一個(gè)函數(shù),但是和普通的函數(shù)有一些區(qū)別:

  • 首先,生成器函數(shù)需要在function的后面加一個(gè)符號(hào):*

  • 其次,生成器函數(shù)可以通過(guò)yield關(guān)鍵字來(lái)控制函數(shù)的執(zhí)行流程:

  • 最后,生成器函數(shù)的返回值是一個(gè)Generator(生成器):

    • 生成器事實(shí)上是一種特殊的迭代器;
    • MDN:Instead, they return a special type of iterator, called a Generator.
/*生成器函數(shù): 1.function后面會(huì)跟上符號(hào): *2.代碼的執(zhí)行可以被yield控制3.生成器函數(shù)默認(rèn)在執(zhí)行時(shí), 返回一個(gè)生成器對(duì)象* 要想執(zhí)行函數(shù)內(nèi)部的代碼, 需要生成器對(duì)象, 調(diào)用它的next操作* 當(dāng)遇到y(tǒng)ield時(shí), 就會(huì)中斷執(zhí)行*/// 1.定義了一個(gè)生成器函數(shù)
function* foo() {console.log("1111")console.log("2222")yieldconsole.log("3333")console.log("4444")yieldconsole.log("5555")console.log("6666")
}// 2.調(diào)用生成器函數(shù), 返回一個(gè) 生成器對(duì)象
const generator = foo()
// 調(diào)用next方法
generator.next()
generator.next()
generator.next()

2.生成器傳遞參數(shù) – next函數(shù)

函數(shù)既然可以暫停來(lái)分段執(zhí)行,那么函數(shù)應(yīng)該是可以傳遞參數(shù)的,我們是否可以給每個(gè)分段來(lái)傳遞參數(shù)呢?

  • 答案是可以的;
  • 我們?cè)谡{(diào)用next函數(shù)的時(shí)候,可以給它傳遞參數(shù),那么這個(gè)參數(shù)會(huì)作為上一個(gè)yield語(yǔ)句的返回值;
  • 注意:也就是說(shuō)我們是為本次的函數(shù)代碼塊執(zhí)行提供了一個(gè)值;
function* foo (param) {const value1 = yield param + "111"const value2 = yield value1 + "222"const value3 = yield value2 + "333"}const f1 = foo("abc")
const result1 = f1.next()
console.log(result1.value)// abc111
const result2 = f1.next(result1.value)
console.log(result2.value)// abc111222
const result3 = f1.next(result2.value)
console.log(result3.value)// abc111222333
console.log(f1.next())

3.生成器提前結(jié)束 – return函數(shù)

還有一個(gè)可以給生成器函數(shù)傳遞參數(shù)的方法是通過(guò)return函數(shù):

  • return傳值后這個(gè)生成器函數(shù)就會(huì)結(jié)束,之后調(diào)用next不會(huì)繼續(xù)生成值了;
function* foo2 () {const value1 = yield 111console.log("value1" + value1)const value2 = yield value1const value3 = yield value2
}
const f2 = foo2()
console.log(f2.next())
console.log(f2.return(123))
console.log(f2.next())

4.生成器拋出異常 – throw函數(shù)

除了給生成器函數(shù)內(nèi)部傳遞參數(shù)之外,也可以給生成器函數(shù)內(nèi)部拋出異常

  • 拋出異常后我們可以在生成器函數(shù)中捕獲異常;
  • 但是在catch語(yǔ)句中不能繼續(xù)yield新的值了,但是可以在catch語(yǔ)句外使用yield繼續(xù)中斷函數(shù)的執(zhí)行;
function* foo3 () {const value1 = yield 111console.log("value1" + value1)const value2 = yield value1const value3 = yield value2
}
const f2 = foo2()
console.log(f2.next())
console.log(f2.throw(new Error("next2 throw error")))
console.log(f2.next())

5.生成器替代迭代器

我們發(fā)現(xiàn)生成器是一種特殊的迭代器,那么在某些情況下我們可以使用生成器來(lái)替代迭代器:

// 1.對(duì)之前的代碼進(jìn)行重構(gòu)(用生成器函數(shù))
const names = ["abc", "cba", "nba"]
const nums = [100, 22, 66, 88, 55]function* createArrayIterator(arr) {for (let i = 0; i < arr.length; i++) {yield arr[i]}// yield arr[0]// yield arr[1]// yield arr[2]// return undefined
}// const namesIterator = createArrayIterator(names)
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())// const numsIterator = createArrayIterator(nums)
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())// 2.生成器函數(shù), 可以生成某個(gè)范圍的值
// [3, 9)
function* createRangeGenerator(start, end) {for (let i = start; i < end; i++) {yield i}
}const rangeGen = createRangeGenerator(3, 9)
console.log(rangeGen.next())
console.log(rangeGen.next())
console.log(rangeGen.next())
console.log(rangeGen.next())
console.log(rangeGen.next())
console.log(rangeGen.next())
console.log(rangeGen.next())
console.log(rangeGen.next())

事實(shí)上我們還可以使用yield*來(lái)生產(chǎn)一個(gè)可迭代對(duì)象:

  • 這個(gè)時(shí)候相當(dāng)于是一種yield的語(yǔ)法糖,只不過(guò)會(huì)依次迭代這個(gè)可迭代對(duì)象,每次迭代其中的一個(gè)值;
// 1.yield*替換之前的方案
const names = ["abc", "cba", "nba"]
const nums = [100, 22, 66, 88, 55]function* createArrayIterator(arr) {yield* arr
}const namesIterator = createArrayIterator(names)
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())

yield替換類中的實(shí)現(xiàn)

class Classroom {constructor(position, name, studentList) {this.position = positionthis.name = namethis.studentList = studentList}push(student) {this.studentList.push(student)}*[Symbol.iterator]() {yield* this.studentList}}const classroom = new Classroom("二樓", "高三二班", ["張三", "李四", "王五"])
classroom[Symbol.iterator]()
for (const stu of classroom) {console.log(stu)
}

五、異步處理方案

1.異步處理方案

學(xué)完了我們前面的Promise、生成器等,我們目前來(lái)看一下異步代碼的最終處理方案。

案例需求:

  • 我們需要向服務(wù)器發(fā)送網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù),一共需要發(fā)送三次請(qǐng)求;
  • 第二次的請(qǐng)求url依賴于第一次的結(jié)果;
  • 第三次的請(qǐng)求url依賴于第二次的結(jié)果;
  • 依次類推;
// 封裝請(qǐng)求的方法: url -> promise(result)
function requestData(url) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(url)}, 2000)})
}
// 方式一: 層層嵌套(回調(diào)地獄 callback hell)
function getData() {// 1.第一次請(qǐng)求requestData("why").then(res1 => {console.log("第一次結(jié)果:", res1)// 2.第二次請(qǐng)求requestData(res1 + "kobe").then(res2 => {console.log("第二次結(jié)果:", res2)// 3.第三次請(qǐng)求requestData(res2 + "james").then(res3 => {console.log("第三次結(jié)果:", res3)})})})
}
// 方式二: 使用Promise進(jìn)行重構(gòu)(解決回調(diào)地獄)
// 鏈?zhǔn)秸{(diào)用
function getData() {requestData("why").then(res1 => {console.log("第一次結(jié)果:", res1)return requestData(res1 + "kobe")}).then(res2 => {console.log("第二次結(jié)果:", res2)return requestData(res2 + "james")}).then(res3 => {console.log("第三次結(jié)果:", res3)})
}

2.Generator方案

但是上面的代碼其實(shí)看起來(lái)也是閱讀性比較差的,有沒(méi)有辦法可以繼續(xù)來(lái)對(duì)上面的代碼進(jìn)行優(yōu)化呢?

使用生成器

function requestUrl(url) {return new Promise((resolve, reject) => {setTimeout(() => {console.log("發(fā)送請(qǐng)求到:" + url)resolve(url+"/abc")}, 3000);})
}function* getList(url) {const result1 = yield requestUrl(url)const result2 = yield requestUrl(result1)const result3 = yield requestUrl(result2)}const listGenerator = getList("baidu")
listGenerator.next().value.then(res => {listGenerator.next(res).value.then(res => {listGenerator.next(res).value.then(res => {console.log("最終的響應(yīng)結(jié)果:" + res)})})
})

3.自動(dòng)執(zhí)行g(shù)enerator函數(shù)

目前我們的寫法有兩個(gè)問(wèn)題:

  • 第一,我們不能確定到底需要調(diào)用幾層的Promise關(guān)系;
  • 第二,如果還有其他需要這樣執(zhí)行的函數(shù),我們應(yīng)該如何操作呢?

所以,我們可以封裝一個(gè)工具函數(shù)execGenerator自動(dòng)執(zhí)行生成器函數(shù):

// 自動(dòng)化執(zhí)行生成器函數(shù)(了解)
function execGenFn(genFn) {// 1.獲取對(duì)應(yīng)函數(shù)的generatorconst generator = genFn()// 2.定義一個(gè)遞歸函數(shù)function exec(res) {// result -> { done: true/false, value: 值/undefined }const result = generator.next(res)if (result.done) returnresult.value.then(res => {exec(res)})}// 3.執(zhí)行遞歸函數(shù)exec()
}
http://www.risenshineclean.com/news/27783.html

相關(guān)文章:

  • 電商網(wǎng)站建設(shè)課件蘇州seo網(wǎng)站優(yōu)化軟件
  • 泉州 網(wǎng)站制作成都百度快照優(yōu)化排名
  • 深圳專業(yè)做網(wǎng)站技術(shù)公司網(wǎng)絡(luò)推廣方案
  • 法人變更在哪個(gè)網(wǎng)站做公示建網(wǎng)站需要多少錢
  • 電子商務(wù)網(wǎng)站建設(shè)的階段化分析b2b電子商務(wù)平臺(tái)有哪些
  • 網(wǎng)站編程外貿(mào)業(yè)務(wù)推廣
  • 廣東裝飾公司網(wǎng)站建設(shè)網(wǎng)絡(luò)營(yíng)銷師證書含金量
  • 中山企業(yè)門戶網(wǎng)站建設(shè)成都網(wǎng)站關(guān)鍵詞推廣
  • 長(zhǎng)沙需要做網(wǎng)站的企業(yè)吳忠seo
  • 動(dòng)態(tài)網(wǎng)站開(kāi)發(fā)第一步藥品銷售推廣方案
  • 中國(guó)幼兒在線幼兒園網(wǎng)站建設(shè)天津網(wǎng)站建設(shè)
  • sae 網(wǎng)站模板線上營(yíng)銷平臺(tái)有哪些
  • 政府網(wǎng)站建設(shè)什么網(wǎng)站可以免費(fèi)推廣
  • wordpress 首頁(yè)模板河南靠譜seo地址
  • 北京中關(guān)村在線官網(wǎng)站群seo
  • 長(zhǎng)沙簡(jiǎn)單的網(wǎng)站建設(shè)公司威海百度seo
  • 翡翠原石網(wǎng)站首頁(yè)怎么做怎樣做app推廣
  • 網(wǎng)站手機(jī)端 怎么做阿里指數(shù)官方網(wǎng)站
  • 在局網(wǎng)站 作風(fēng)建設(shè)百度電話怎么轉(zhuǎn)人工
  • 網(wǎng)站備案當(dāng)面核驗(yàn)中國(guó)搜索引擎市場(chǎng)份額
  • 汕頭網(wǎng)站推廣教程2345瀏覽器網(wǎng)址導(dǎo)航
  • 怎么做淘寶客網(wǎng)站賺錢整站優(yōu)化加盟
  • 做英文網(wǎng)站哪家好關(guān)鍵詞首頁(yè)排名優(yōu)化價(jià)格
  • 大寺網(wǎng)站建設(shè)公司不限次數(shù)觀看視頻的app
  • 網(wǎng)站備案填寫昆山網(wǎng)站制作公司
  • 可以做早安圖片的網(wǎng)站一鍵優(yōu)化大師下載
  • domain:網(wǎng)站建設(shè)網(wǎng)站建設(shè)的系統(tǒng)流程圖
  • 有了網(wǎng)站 怎么做排名優(yōu)化新聞?lì)^條最新消息今日頭條
  • 企業(yè)網(wǎng)盤怎么申請(qǐng)seo搜索優(yōu)化 指數(shù)
  • 兼職做設(shè)計(jì)什么網(wǎng)站好360競(jìng)價(jià)推廣