迭代器模式 順序訪問一個集合 使用者無需知道集合內部結構(封裝) jQuery 示例 傳統 UML 類圖 javascript 中的 UML 類圖 使用場景 jQuery each 上面的 jQuery 代碼就是 ES6 Iterator ES6 Iterator 為何存在? es6 語法中,有序集 ...
迭代器模式
順序訪問一個集合
使用者無需知道集合內部結構(封裝)
jQuery 示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<p>jquery each</p>
<p>jquery each</p>
<p>jquery each</p>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var arr = [1, 2, 3];
var nodeList = document.getElementsByTagName("p");
var $p = $("p");
// 要對這三個變數進行遍歷,需要寫三個遍歷方法
// 第一
arr.forEach(function(item) {
console.log(item);
});
// 第二
var i,
length = nodeList.length;
for (i = 0; i < length; i++) {
console.log(nodeList[i]);
}
// 第三
$p.each(function(key, p) {
console.log(key, p);
});
// 如何能寫出一個方法來遍歷這三個對象呢
function each(data) {
var $data = $(data);
$data.each(function(key, p) {
console.log(key, p);
});
}
each(arr);
each(nodeList);
each($p);
</script>
</body>
</html>
傳統 UML 類圖
javascript 中的 UML 類圖
class Iterator {
constructor(conatiner) {
this.list = conatiner.list;
this.index = 0;
}
next() {
if (this.hasNext()) {
return this.list[this.index++];
}
return null;
}
hasNext() {
if (this.index >= this.list.length) {
return false;
}
return true;
}
}
class Container {
constructor(list) {
this.list = list;
}
getIterator() {
return new Iterator(this);
}
}
// 測試代碼
let container = new Container([1, 2, 3, 4, 5]);
let iterator = container.getIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
使用場景
jQuery each
上面的 jQuery 代碼就是
ES6 Iterator
ES6 Iterator 為何存在?
- es6 語法中,有序集合的數據類型已經有很多了
- Array Map Set String TypedArray argument Nodelist
- 需要有一個統一的遍歷介面來遍歷所有的數據類型
- (註意,object 不是有序集合,可以用 Map 代替)
es6 Interator 是什麼?
- 以上數據類型,都有[Symbol.iterator]屬性
- 屬性值是函數,執行函數返回一個迭代器
- 這個迭代器就有 next 方法可以順序迭代子元素
- 可運行 Array.prototype[Symbol.iterator]來測試
示例
let arr = [1, 2, 3, 4]
let nodeList = document.getElementsByTagName('p')
let m = new Map()
m.set('a', 100)
m.set('b', 200)
function each(data) {
// 生成遍歷器
let iterator = data[Symbol.iterator]()
console.log(iterator.next()) // 有數據時返回 {value: 1, done: false}
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next()) // 沒有數據時返回 {value: undefined, done: true}
each(arr)
each(nodeList)
each(m)
上面代碼改進
let arr = [1, 2, 3, 4];
let nodeList = document.getElementsByTagName("p");
let m = new Map();
m.set("a", 100);
m.set("b", 200);
function each(data) {
// 生成遍歷器
let iterator = data[Symbol.iterator]();
let item = { done: false };
while (!item.done) {
item = iterator.next();
if (!item.done) {
console.log(item.value);
}
}
}
each(arr);
each(nodeList);
each(m);
es6 很聰明提供了for of
let arr = [1, 2, 3, 4];
let nodeList = document.getElementsByTagName("p");
let m = new Map();
m.set("a", 100);
m.set("b", 200);
function each(data) {
for (let item of data) {
console.log(item);
}
}
each(arr);
each(nodeList);
each(m);
ES6 Interator 與 Generator
- Interator 的價值不限於上述幾個類型的遍歷
- 還有 Generator 函數的使用
- 即只要返回的數據符合 Interator 介面的要求
function* helloWorldGenerator() {
yield "hello";
yield "world";
return "ending";
}
var hw = helloWorldGenerator();
console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
//輸出
// { value: 'hello', done: false }
// { value: 'world', done: false }
// { value: 'ending', done: true }
// { value: undefined, done: true }
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
設計原則驗證
- 迭代器對象和目標對象分離
- 迭代器將使用者與目標者對象隔離開
- 符合開放封閉原則