最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

ES6 迭代器(Iterator)和 for.of循環(huán)使用方法學習(總結)

 更新時間:2018年02月08日 13:46:49   作者:貴在隨心  
這篇文章主要介紹了ES6 迭代器(Iterator)和 for.of循環(huán)使用方法學習總結,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

一、什么是迭代器?

生成器概念在Java,Python等語言中都是具備的,ES6也添加到了JavaScript中。Iterator可以使我們不需要初始化集合,以及索引的變量,而是使用迭代器對象的 next 方法,返回集合的下一項的值,偏向程序化。

迭代器是帶有特殊接口的對象。含有一個next()方法,調用返回一個包含兩個屬性的對象,分別是value和done,value表示當前位置的值,done表示是否迭代完,當為true的時候,調用next就無效了。

ES5中遍歷集合通常都是 for循環(huán),數(shù)組還有 forEach 方法,對象就是 for-in,ES6 中又添加了 Map 和 Set,而迭代器可以統(tǒng)一處理所有集合數(shù)據(jù)的方法。迭代器是一個接口,只要你這個數(shù)據(jù)結構暴露了一個iterator的接口,那就可以完成迭代。ES6創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator接口主要供for...of消費。

二、如何使用迭代器?

1、默認 Iterator 接口

數(shù)據(jù)結構只要部署了 Iterator 接口,我們就成這種數(shù)據(jù)結構為“可遍歷”(Iterable)。ES6 規(guī)定,默認的 Iterator 接口部署在數(shù)據(jù)結構的 Symbol.iterator 屬性,或者說,一個數(shù)據(jù)結構只要具有 Symbol.iterator 數(shù)據(jù),就可以認為是“可遍歷的”(iterable)。

可以供 for...of 消費的原生數(shù)據(jù)結構

  1. Array
  2. Map
  3. Set
  4. String
  5. TypedArray(一種通用的固定長度緩沖區(qū)類型,允許讀取緩沖區(qū)中的二進制數(shù)據(jù))
  6. 函數(shù)中的 arguments 對象
  7. NodeList 對象

可以看上面的原生數(shù)據(jù)結構中并沒有對象(Object),為什么呢?

那是因為對象屬性的遍歷先后順序是不確定的,需要開發(fā)者手動指定。本質上,遍歷器是一種線性處理,對于任何非線性的數(shù)據(jù)結構,部署遍歷器接口就等于部署一種線性變換。

做如下處理,可以使對象供 for...of 消費:

// code1
function Obj(value) {
  this.value = value;
  this.next = null;
}
Obj.prototype[Symbol.iterator] = function() {
  var iterator = {
    next: next
  };
  var current = this;
  function next() {
    if (current) {
      var value = current.value;
      current = current.next;
      return {
        done: false,
        value: value
      };
    } else {
      return {
        done: true
      };
    }
  }
  return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two;
two.next = three;
for (var i of one) {
  console.log(i);
}
// 1
// 2
// 3

2、調用 Iterator 接口的場合

(1) 解構賦值

// code2
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];

(2) 擴展運算符

// code3
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']

(3)Generator 函數(shù)中的 yield* 表達式(下一章介紹)

// code4
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }

(4)其它場合

  1. for..of
  2. Array.from
  3. Map()、Set()、WeakMap()、WeakSet()
  4. Promise.all()
  5. Promise.race()

3、for...of 循環(huán)的優(yōu)勢

先看看,數(shù)組 forEach 方法的缺點:

// code5
myArray.forEach(function (value) {
 console.log(value);
});

這個寫法的問題在于,無法中途跳出 forEach 循環(huán),break 命令或 return 命令都不能生效。

再看看,對象 for...in 的循環(huán)的缺點:

for (var index in myArray) {
 console.log(myArray[index]);
};
  1. 數(shù)組的鍵名是數(shù)字,但是 for...in 循環(huán)是以字符串作為鍵名,“0”、“1”、“2”等。
  2. for...in 循環(huán)不僅可以遍歷數(shù)字鍵名,還會遍歷手動添加的期推薦,甚至包括原型鏈上的鍵。
  3. 某些情況下,for...in 循環(huán)會議任意順序遍歷鍵名
  4. for...in 遍歷主要是為遍歷對象而設計的,不適用于遍歷數(shù)組

那么,for...of 有哪些顯著的優(yōu)點呢?

  1. 有著同 for...in 一樣的簡潔語法,但是沒有 for...in 那些缺點
  2. 不同于 forEach 方法,它可以與 break、continue 和 return 配合使用
  3. 提供了遍歷所有數(shù)據(jù)結構的統(tǒng)一操作接口
for (var n of fibonacci) {
 if (n > 1000) {
  break;
  console.log(n);
 }
}

4、各數(shù)據(jù)類型如何使用 for...of 循環(huán)?

(1)數(shù)組

for...of 循環(huán)允許遍歷數(shù)組獲得鍵值

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 循環(huán)調用遍歷器接口,數(shù)組的遍歷器接口只返回具有數(shù)字索引的值

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"
}

(2)Map 和 Set 結構

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
  console.log(e);
}
// Gecko
// Trident
// Webkit
var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for (var [name, value] of es6) {
  console.log(name + ": " + value);
}
// edition: 6
// committee: TC39
// standard: ECMA-262

由上述的代碼可以看出,for...of 循環(huán)遍歷Map 和 Set 結構時,遍歷的順序是按照各個成員被添加進數(shù)據(jù)結構的順序,Set 結構遍歷時返回的是一個值,而 Map 結構遍歷時返回的是一個數(shù)組,該數(shù)組的兩個成員分別為當前 Map 成員的鍵名和鍵值。

(3)類數(shù)組對象

字符串

// 普通的字符串遍歷
let str = "yuan";
for (let s of str) {
 console.log(s); // y u a n
}

// 遍歷含有 32位 utf-16字符的字符串
for (let x of 'a\uD83D\uDC0A') {
 console.log(x);
}
// 'a'
// '\uD83D\uDC0A'

DOM NodeList 對象

let paras = document.querySelectorAll("p");
for (let p of paras) {
 p.classList.add("test");
}

arguments 對象

function printArgs() {
 for (let x of arguments) {
  console.log(x);
 }
}
printArgs("a", "n");
// "a"
// "n"

沒有 Iterator 接口類數(shù)組對象的遍歷處理

借用 Array.from 方法處理

let arrayLike = {
  length: 2,
  0 : 'a',
  1 : 'b'
};
// 報錯
for (let x of arrayLike) {
  console.log(x);
}
// 正確
for (let x of Array.from(arrayLike)) {
  console.log(x);
}

(4)對象

對于普通對象,不能直接使用 for...of 遍歷,否則會報錯,必須部署了 Iterator 接口才能使用。如下兩種方法部署:

// 方法一:使用 Object.keys 方法講對象的鍵名生成一個數(shù)組
for (var key of Object.keys(someObject)) {
 console.log(key + ": " + someObject[key]);
}

// 方法二:使用Generator 函數(shù)將對象重新包裝一下
function * entries(obj) {
  for (let key of Object.keys(obj)) {
    yield[key, obj[key]];
  }
}
for (let[key, value] of entries(obj)) {
  console.log(key, "->", value);
}
// a -> 1
// b -> 2
// c -> 3

三、迭代器應用實例

1、斐波那契數(shù)列

下面我們就使用迭代器來自定義自己的一個斐波那契數(shù)列組,我們直到斐波那契數(shù)列有兩個運行前提,第一個前提是初始化的前兩個數(shù)字為0,1,第二個前提是將來的每一個值都是前兩個值的和。這樣我們的目標就是每次都迭代輸出一個新的值。

var it = { [Symbol.iterator]() {
    return this
  },
  n1: 0,
  n2: 1,
  next() {
    let temp1 = this.n1,
    temp2 = this.n2;
    [this.n1, this.n2] = [temp2, temp1 + temp2]
    return {
      value: temp1,
      done: false
    }
  }
}

for (var i = 0; i < 20; i++) {
  console.log(it.next())
}

// 
  "value": 0,
  "done": false
} {
  "value": 1,
  "done": false
} {
  "value": 1,
  "done": false
} {
  "value": 2,
  "done": false
} {
  "value": 3,
  "done": false
} {
  "value": 5,
  "done": false
}... {
  "value": 2584,
  "done": false
} {
  "value": 4181,
  "done": false
}

2、任務隊列迭代器

我們可以定義一個任務隊列,該隊列初始化時為空,我們將待處理的任務傳遞后,傳入數(shù)據(jù)進行處理。這樣第一次傳遞的數(shù)據(jù)只會被任務1處理,第二次傳遞的只會被任務2處理… 代碼如下:

var Task = {
  actions: [],
  [Symbol.iterator]() {
    var steps = this.actions.slice();
    return { [Symbol.iterator]() {
        return this;
      },
      next(...args) {
        if (steps.length > 0) {
          let res = steps.shift()(...args);
          return {
            value: res,
            done: false
          }
        } else {
          return {
            done: true
          }
        }
      }
    }
  }
}

Task.actions.push(function task1(...args) {
  console.log("任務一:相乘") return args.reduce(function(x, y) {
    return x * y
  })
},
function task2(...args) {
  console.log("任務二:相加") return args.reduce(function(x, y) {
    return x + y
  }) * 2
},
function task3(...args) {
  console.log("任務三:相減") return args.reduce(function(x, y) {
    return x - y
  })
});

var it = Task[Symbol.iterator]();
console.log(it.next(10, 100, 2));
console.log(it.next(20, 50, 100)) console.log(it.next(10, 2, 1))
 // 
任務一:相乘 {
  "value": 2000,
  "done": false
}任務二:相加 {
  "value": 340,
  "done": false
}任務三:相減 {
  "value": 7,
  "done": false
}

3、延遲執(zhí)行

假設我們有一個數(shù)據(jù)表,我們想按大小順序依次的獲取數(shù)據(jù),但是我們又不想提前給他排序,有可能我們根本就不去使用它,所以我們可以在第一次使用的時候再排序,做到延遲執(zhí)行代碼:

var table = {
  "d": 1,
  "b": 4,
  "c": 12,
  "a": 12
}
table[Symbol.iterator] = function() {
  var _this = this;
  var keys = null;
  var index = 0;

  return {
    next: function() {
      if (keys === null) {
        keys = Object.keys(_this).sort();
      }

      return {
        value: keys[index],
        done: index++>keys.length
      };
    }
  }
}

for (var a of table) {
  console.log(a)
} 
// a b c d

四、結語

本章內容,重點是明白 Iterator 接口的機制,以及 for...of 循環(huán)的使用方法。下一章介紹生成器函數(shù) Generator 函數(shù)。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • JavaScript的parseInt 進制問題

    JavaScript的parseInt 進制問題

    今天在整理以前寫過的一段根據(jù)周期值自動計算下次執(zhí)行日期的js代碼,發(fā)現(xiàn)一bug,我使用parseInt對源數(shù)據(jù)串進行轉換,當輸入類似:2009-05-05時,parseInt將把串的05做8進制轉換,這樣結果自然就不對了。
    2009-05-05
  • JavaScript中this詳解

    JavaScript中this詳解

    this是javascript的一個關鍵字,隨著函數(shù)使用場合不同,this的值會發(fā)生變化。但是總有一個原則,那就是this指的是調用函數(shù)的那個對象。
    2015-09-09
  • JS基于面向對象實現(xiàn)的放煙花效果

    JS基于面向對象實現(xiàn)的放煙花效果

    這篇文章主要介紹了JS基于面向對象實現(xiàn)的放煙花效果,涉及javascript面向對象技術的使用技巧,需要的朋友可以參考下
    2015-05-05
  • JS高仿拋物線加入購物車特效實現(xiàn)代碼

    JS高仿拋物線加入購物車特效實現(xiàn)代碼

    本篇文章主要介紹了JS高仿拋物線加入購物車特效實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • js 動態(tài)修改css文件用到了cssRule

    js 動態(tài)修改css文件用到了cssRule

    js 動態(tài)修改css文件,循環(huán)用的underscore,在使用cssRule只能使用cssRule.style.padding=0px,詳細示例如下
    2014-08-08
  • webpack4.x CommonJS模塊化淺析

    webpack4.x CommonJS模塊化淺析

    這篇文章主要介紹了webpack4.x CommonJS模塊化淺析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • JavaScript無操作后屏保功能的實現(xiàn)方法

    JavaScript無操作后屏保功能的實現(xiàn)方法

    今天組里的同事要寫一個屏保的效果,要求鼠標無操作N秒后進入屏幕保護,滑動鼠標的時候取消屏幕保護。我真是難倒了,糾結了半天,搞定了,下面給大家分享實現(xiàn)代碼
    2017-07-07
  • 自己封裝的常用javascript函數(shù)分享

    自己封裝的常用javascript函數(shù)分享

    這里給大家推薦一個自己封裝的常用的javascript函數(shù),基本上常見的操作都包含在內了,有需要的小伙伴直接拿走使用吧。
    2015-01-01
  • 小程序分享鏈接onShareAppMessage的具體用法

    小程序分享鏈接onShareAppMessage的具體用法

    這篇文章主要介紹了小程序分享鏈接onShareAppMessage的具體用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05
  • uniapp項目實踐之全局公共組件樣式及方法使用示例詳解

    uniapp項目實踐之全局公共組件樣式及方法使用示例詳解

    這篇文章主要為大家介紹了uniapp項目實踐之全局公共組件樣式及方法使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09

最新評論

汾阳市| 平果县| 定日县| 文水县| 乌恰县| 呼图壁县| 罗源县| 汝城县| 镇安县| 翁牛特旗| 徐州市| 镇原县| 曲阜市| 宁乡县| 都昌县| 南投县| 观塘区| 博罗县| 周至县| 康马县| 温州市| 行唐县| 咸宁市| 涞水县| 博爱县| 体育| 图片| 黎城县| 九台市| 玉山县| 上杭县| 荔波县| 乌拉特后旗| 香港| 邯郸市| 古田县| 法库县| 拉萨市| 托里县| 宽甸| 宜宾市|