亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2020-09-26 22:43:02 來源:腳本之家 閱讀:188 作者:貴在隨心 欄目:web開發

一、什么是迭代器?

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

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

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

二、如何使用迭代器?

1、默認 Iterator 接口

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

可以供 for...of 消費的原生數據結構

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

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

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

做如下處理,可以使對象供 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 函數中的 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 循環的優勢

先看看,數組 forEach 方法的缺點:

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

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

再看看,對象 for...in 的循環的缺點:

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

那么,for...of 有哪些顯著的優點呢?

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

4、各數據類型如何使用 for...of 循環?

(1)數組

for...of 循環允許遍歷數組獲得鍵值

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

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 循環遍歷Map 和 Set 結構時,遍歷的順序是按照各個成員被添加進數據結構的順序,Set 結構遍歷時返回的是一個值,而 Map 結構遍歷時返回的是一個數組,該數組的兩個成員分別為當前 Map 成員的鍵名和鍵值。

(3)類數組對象

字符串

// 普通的字符串遍歷
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 接口類數組對象的遍歷處理

借用 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 方法講對象的鍵名生成一個數組
for (var key of Object.keys(someObject)) {
 console.log(key + ": " + someObject[key]);
}

// 方法二:使用Generator 函數將對象重新包裝一下
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、斐波那契數列

下面我們就使用迭代器來自定義自己的一個斐波那契數列組,我們直到斐波那契數列有兩個運行前提,第一個前提是初始化的前兩個數字為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、任務隊列迭代器

我們可以定義一個任務隊列,該隊列初始化時為空,我們將待處理的任務傳遞后,傳入數據進行處理。這樣第一次傳遞的數據只會被任務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、延遲執行

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

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 循環的使用方法。下一章介紹生成器函數 Generator 函數。

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

分宜县| 满洲里市| 瑞昌市| 镇江市| 濮阳市| 南昌县| 荃湾区| 枣强县| 大冶市| 嘉义县| 万全县| 随州市| 洪雅县| 辽中县| 佳木斯市| 雷山县| 宿州市| 沂南县| 彝良县| 佛坪县| 特克斯县| 汉中市| 革吉县| 元阳县| 烟台市| 葫芦岛市| 阿拉尔市| 习水县| 南平市| 吴忠市| 成都市| 肃北| 昌乐县| 横峰县| 新民市| 凤庆县| 湘西| 鹤岗市| 聊城市| 古蔺县| 禄丰县|