91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

什么是for of和Iterator

發布時間:2021-10-19 15:20:35 來源:億速云 閱讀:106 作者:iii 欄目:編程語言

這篇文章主要講解了“什么是for of和Iterator”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“什么是for of和Iterator”吧!

從一個變量說起

var arr = ['紅','綠','藍']; 

上面是一個普通的數組,如果我要獲取他的每一項數據,應該怎么做?

這個還不簡單,直接來個 for循環,如果你覺得循環 low,那就來個 forEach 唄。

ok,立刻擼串代碼

//for 循環
for(var i=0;i<arr.length;i++){
    console.log(arr[i]);
}

//forEacth
arr.forEach(item=>{
    console.log(item);
});

// 結果 略
 

ok,沒毛病。

那咱們繼續,請看下面代碼。給定一個字符串,如果我想輸出每一個字符怎么做?

var str='1234567890';
 

有么有搞錯,這簡單的讓人發笑。

可以用 for in,也可以用 for 循環,按照類數組方式來處理。

立刻擼串代碼

//for in
for(var s in str){
    console.log(str[s]);//s 是 屬性名稱【key】
}

//轉為數組
for(var i =0;i<str.length;i++){
console.log(str[i]);
}

//或者轉換為數組
Array.prototype.slice.call(str);
 

不過 for in 不是用來獲取數據的,他會遍歷對象上所有可枚舉的屬性,包括自身的和原型鏈上的,所以這個不保險。

emmm....沒啥問題,那咱們繼續。

請看下面代碼,給定一個map對象,然后輸出它每一項數據。

var map = new Map();
map.set('zhang','1000w');
map.set('liu','200w');
map.set('sun','100w');

forEach 就妥妥的了。

map.forEach((val,key)=>{
    console.log(val,key);
})
 

到這里看了這么多如此簡單到令人發指的提問,估計都有些坐不住了,要掀桌子走人了。請稍后,慢慢往下看。

發現問題

好了,在上一步幾個簡單的問題中,我們的操作都是獲得他們的每一項數據。

當然方法有很多種,實現方式也有很多,for 循環forEachfor in 啦。

但是有沒有發現一個問題,或者我們站在一個更高的維度去看待,其實這些方法都不能通用,也就是說上面的這幾種集合數據不能使用統一的遍歷方法來進行數據獲取。

誰說的,能統一呀,都可以用 forEach來遍歷,數組和map 本身就支持,字符串我直接轉為數組后可以了。

ok,這沒什么毛病。

但是每次都要轉換,還要封裝,還有可能要侵入原型。

那有沒有一種更好的,通用方法,讓開發者用的更舒服,更爽呢?

答案是肯定的,es5的時候還沒出現,升級到 es6就有了。

NB的 for of,扒一扒

這個可以對不同數據結構進行統一遍歷的方式就是 es6for of 循環。

for of 循環 和 古老的for 循環很像呀。不就是個新增語法么。

引用阮大佬書中一句話,相信一看便知。

ES6 借鑒 C++、Java、C# 和 Python 語言,引入了for...of循環。作為遍歷所有數據結構的統一的方法。

關鍵在于統一,另一個就是直接取值,簡化操作,不需要在聲明和維護什么變量、對數據做轉換。

原來for of 這么牛,for 循環搞不定的你可以搞定。

為什么 for of 能具備這個能力,可以為不同的數據結構提供一種統一的數據獲取方式。

for of 真的這么強大嗎,他背后的機制是什么?

其實for of 并不是真的強大,他只是一種ES6新的語法而已。

并不是所有的對象都能使用 for of,只有實現了Iterator接口的對象才能夠使用 for of 來進行遍歷取值。

所以說 for of 只是語法糖,真正的主角是Iterator

What ? Iterator..... 

主角登場- Iterator 迭代器

Iterator 是一種接口,目的是為不同的數據結構提供統一的數據訪問機制。也可以理解為 Iterator 接口主要為 for of 服務的,供for...of進行消費。

其實在很多后端語言多年前早已存在 Iterator 這個特性,如 java、C++、C#等。

既然他是一種接口,那我們應該怎樣實現這個接口呢?實現規則是什么樣的呢?

因為 javascript 語言里沒有接口的概念,這里我們可以理解成它是一種特殊的對象 - 迭代器對象,返回此對象的方法叫做迭代器方法。

首先他作為一個對象,此對象具有一個next方法,每次調用 next 方法都會返回一個結果值。

這個結果值是一個 object,包含兩個屬性,valuedone

value表示具體的返回值,done 是布爾類型的,表示集合是否遍歷完成或者是否后續還有可用數據,沒有可用數據則返回 true,否則返回 false

另外內部會維護一個指針,用來指向當前集合的位置,每調用一次 next 方法,指針都會向后移動一個位置(可以想象成數組的索引)。

看下代碼實現

function getIterator(list) {
    var i = 0;
    return {
        next: function() {
            var done = (i >= list.length);
            var value = !done ? list[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
    };
}
var it = getIterator(['a', 'b', 'c']);
console.log(it.next()); // {value: "a", done: false}
console.log(it.next()); // {value: "b", done: false}
console.log(it.next()); // {value: "c", done: false}
console.log(it.next()); // "{ value: undefined, done: true }"
console.log(it.next()); // "{ value: undefined, done: true }"
console.log(it.next()); // "{ value: undefined, done: true }"
 

上面代碼便是根據迭代器的基本概念衍生出來的一個模擬實現。

  • getIterator方法返回一個對象 - 可迭代對象
  • 對象具有一個     next 方法,     next 方法內部通過閉包來保存指針     i 的值,每次調用     next 方法     i 的值都會     +1.
  • 然后根據     i 的值從數組內取出數據作為     value,然后通過索引判斷得到     done的值。
  • 當     i=3的時候,超過數組的最大索引,無可用數據返回,此時done 為     true,遍歷完成。 

可迭代對象

到這里我們已經大概了解了 Iterator, 以及如何創建一個迭代器對象。但是他和 for of 有什么關系呢? 

for of 運行機制

for of執行的時候,循環過程中引擎就會自動調用這個對象上的迭代器方法, 依次執行迭代器對象的 next 方法,將 next 返回值賦值給 for of 內的變量,從而得到具體的值。

我覺得上面一句話包含了一個重要的信息- “對象上的迭代器方法”。 

實現可迭代對象

對象上怎么會有迭代器方法呢?

ES6里規定,只要在對象的屬性上部署了Iterator接口,具體形式為給對象添加Symbol.iterator屬性,此屬性指向一個迭代器方法,這個迭代器會返回一個特殊的對象 - 迭代器對象。

而部署這個屬性并且實現了迭代器方法后的對象叫做可迭代對象

此時,這個對象就是可迭代的,也就是可以被 for of 遍歷。

Symbol.iterator,它是一個表達式,返回Symbol對象的iterator屬性,這是一個預定義好的、類型為 Symbol 的特殊值。

舉個例子

普通的對象是不能被 for of 遍歷的,直接食用會報錯。

var obj = {};

for(var k of obj){
    
}
 

obj 不是可迭代的對象。

什么是for of和Iterator  

那么我們來,讓一個對象變成可迭代對象,按照協議也就是規定來實現即可。

iterableObj 對象上部署 Symbol.iterator屬性,然后為其創建一個迭代器方法,迭代器的規則上面我們已經說過啦。

var iterableObj = {
    items:[100,200,300],
    [Symbol.iterator]:function(){
    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.items.length);
            var value = !done ? self.items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
    };
    }
}

//遍歷它
for(var item of iterableObj){
    console.log(item); //100,200,300
}
 

就這么簡單,上面這個對象就是可迭代對象了,可以被 for of 消費了。 

Iterator 原生應用場景

我們再回到最開始使用 for of 來進行遍歷字符串、數組、map,我們并沒有為他們部署Iterator接口,仍然可以使用 for of 遍歷。

這是因為在 ES6中有些對象已經默認部署了此接口,不需要做任何處理,就可以使用 for of 來進行遍歷取值。

不信?咿,你好難搞,我不要你說 - 信,我要我說 - 信。

看看能不能拿到它們的迭代器。

數組

//數組
var arr=[100,200,300];

var iteratorObj=  arr[Symbol.iterator]();//得到迭代器方法,返回迭代器對象

console.log(iteratorObj.next());
console.log(iteratorObj.next());
console.log(iteratorObj.next());
console.log(iteratorObj.next());


 
什么是for of和Iterator  

字符串

因為字符串本身的值是有序的,并且具有類數組的特性,支持通過索引訪問,所以也默認部署了iterator接口。

var str='abc';

var strIteratorObj = str[Symbol.iterator]();//得到迭代器

console.log(strIteratorObj.next());
console.log(strIteratorObj.next());
console.log(strIteratorObj.next());
console.log(strIteratorObj.next());
 
什么是for of和Iterator 

或者直接看原型上是否部署了這個屬性即可。

什么是for of和Iterator  

arguments 類數組

函數內的arguments 是一個類數組,他也支持 for of,因為他內部也部署了Iterator 接口。

我們都知道對象是默認沒有部署這個接口的,所以arguments這個屬性沒有在原型上,而在在對象自身的屬性上。

function test(){
    var obj = arguments[Symbol.iterator]();
   console.log( arguments.hasOwnProperty(Symbol.iterator));
   console.log( arguments);
   console.log(obj.next());
}

test(1,2,3);
什么是for of和Iterator  

總結來說,已默認部署 Iterator 接口的對象主要包括數組、字符串、Set、Map 、類似數組的對象(比如arguments對象、DOM NodeList 對象)。

代碼驗證略,都是一個套路,不多說。

Iterator 另外一個作用

Iterator除了可以為不同的數據結構提供一種統一的數據訪問方式,還有沒有發現其他的作用?

那就是數據可定制性,因為我們可以隨意的控制迭代器的 value 值。

比如:數組本身就是一個可迭代的,我們可以覆蓋他的默認迭代器。

var arr=[100,200,300];

for(var o of arr){
    console.log(o);
}
 

for of 數組默認輸出如下

什么是for of和Iterator  

經過我們的改造

什么是for of和Iterator  
var arr=[100,200,300];
arr[Symbol.iterator]=function(){

    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.length);
            var value = !done ? self[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
    };
}

for(var o of arr){
    console.log(o);
}
  

對象為什么沒有默認部署

對象可能有各種屬性,不像數組的值是有序的。

所以遍歷的時候根本不知道如何確定他們的先后順序,所以需要我們根據情況手動實現。

擴展

for of 中斷

我們都知道普通的 for 循環是可以隨時中斷的,那 for of 是否可以呢?

答案是肯定的,for of機制兼顧了forforEach

迭代器除了必須next 方法外,還有兩個可選的方法 returnthrow方法。

如果 for of 循環提前退出,則會自動調用 return 方法,需要注意的是 return 方法必須有返回值,且返回值必須是 一個object

ps:以拋出異常的方式退出,會先執行 return 方法再拋出異常。

var iterableObj = {
    items:[100,200,300],
    [Symbol.iterator]:function(){
    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.items.length);
            var value = !done ? self.items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        },
        return(){
            console.log('提前退出');
            return {//必須返回一個對象
                done:true
            }
        }
    };
    }

}

for(var item of iterableObj){
    console.log(item);
    if(item===200){
        break;
    }
}

for(var item of iterableObj){
    console.log(item);
    throw new Error();
}
 
什么是for of和Iterator 

ps:throw 方法這里先不說,這里不是他的用武之地,后續文章見。 

不止 for of

除了 for of 執行的時候會自動調用對象的Iterator方法,那么ES6里還有沒有其他的語法形式? 

解構賦值

對可迭代對象進行解構賦值的時候,會默認調用Symbol.iterator方法。

//字符串
var str='12345';
var [a,b]=str;
console.log(a,b); // 1 2

//map
var map = new Map();
map.set('我','前端');
map.set('是','技術');
map.set('誰','江湖');
map.set('作者','zz_jesse');

var [d,e]=map;
console.log(d,e);
//["我", "前端"] ["是", "技術"]
....
 

同樣如果對一個普通對象進行解構,則會報錯。

因為普通對象不是可迭代對象。

var [d,e]={name:'zhang'};
 
什么是for of和Iterator 

從一個自定義的可迭代對象進行解構賦值。

var iterableObj = {
    items:['紅','綠','藍'],
    [Symbol.iterator]:function(){
    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.items.length);
            var value = !done ? self.items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
     };
   }
}

var [d,e]=iterableObj;
console.log(d,e);//紅 綠 
 

解構賦值的變量的值就是迭代器對象的 next 方法的返回值,且是按順序返回。 

擴展運算符

擴展運算符的執行(...)也會默認調用它的Symbol.iterator方法,可以將當前迭代對象轉換為數組。

//字符串
var str='1234';
console.log([...str]);//[1,2,3,4]  轉換為數組


//map 對象
var map=new Map([[1,2],[3,4]]);
[...map] //[[1,2],[3,4]

//set 對象
var set=new Set([1,2,3]);
[...set] //[1,2,3]
 

通用普通對象是不可以轉為數組的。

var obj={name:'zhang'};
[..obj]//報錯
 
什么是for of和Iterator    

作為數據源

作為一些數據的數據源,比如某些api 方法的參數是接收一個數組,都會默認的調用自身迭代器。

例如:Set、Map、Array.from 等

//為了證明,先把一個數組的默認迭代器給覆蓋掉

var arr=[100,200,300];

arr[Symbol.iterator]=function(){

    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.length);
            var value = !done ? self[i++] : undefined;
            return {
                done: done,
                value: value+'前端技術江湖' //注意這里
            };
        }
    };

}

for(var o of arr){
    console.log(o);
}

// 100前端技術江湖
// 200前端技術江湖
// 300前端技術江湖
 

已覆蓋完成

//生成 set  對象
var set  = new Set(arr);
 
什么是for of和Iterator  
//調用 Array.from方法
Array.from(arr);
 
什么是for of和Iterator  

yield*  關鍵字

yield*后面跟的是一個可遍歷的結構,執行時也會調用迭代器函數。

let foo = function* () {
  yield 1;
  yield* [2,3,4];
  yield 5;
};
 

yield 需要著重說明, 下一節再詳細介紹。 

判斷對象是否可迭代

既然可迭代對象的規則必須在對象上部署Symbol.iterator屬性,那么我們基本上就可以通過此屬來判斷對象是否為可迭代對象,然后就可以知道是否能使用 for of 取值了。

function isIterable(object) {
    return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable('abcdefg')); // true
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable("Hello")); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new WeakMap())); // false
console.log(isIterable(new WeakSet())); // false
   

總結

ES6的出現帶來了很多新的數據結構,比如 Map ,Set ,所以為了數據獲取的方便,增加了一種統一獲取數據的方式 for of 。而 for of 執行的時候引擎會自動調用對象的迭代器來取值。

不是所有的對象都支持這種方式,必須是實現了Iterator接口的才可以,這樣的對象我們稱他們為可迭代對象。

迭代器實現方式根據可迭代協議,迭代器協議實現即可。

除了統一數據訪問方式,還可以自定義得到的數據內容,隨便怎樣,只要是你需要的。

迭代器是一個方法, 用來返回迭代器對象。

可迭代對象是部署了 Iterator 接口的對象,同時擁有正確的迭代器方法。

ES6內很多地方都應用了Iterator,平時可以多留意觀察,多想一步。 

是結束也是開始

到這里我們已經可以根據迭代器的規則自定義迭代器了,但實現的過程有些復雜,畢竟需要自己來維護內部指針,有不少的邏輯處理,難免會出錯。

那有沒有更優雅的實現方式呢?

有,那就是-Generator -生成器 。

let obj = {
  * [Symbol.iterator]() {
    yield 'hello';
    yield 'world';
  }
};

for (let x of obj) {
  console.log(x);
}
// "hello"
// "world"

可以看出它非常簡潔,無需過多代碼就可以生成一個迭代器。

它除了可以作為生成迭代器的語法糖,他還有更多神奇的能力。

這次就先搞定Iterator,下次搞 Generator

感謝各位的閱讀,以上就是“什么是for of和Iterator”的內容了,經過本文的學習后,相信大家對什么是for of和Iterator這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

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

AI

三原县| 敦化市| 昭平县| 大冶市| 乌拉特后旗| 藁城市| 长宁区| 鄂托克前旗| 寿光市| 彭泽县| 岱山县| 天津市| 麻江县| 巩义市| 玉门市| 鄱阳县| 岚皋县| 乌兰察布市| 堆龙德庆县| 金门县| 商洛市| 东光县| 苏州市| 新津县| 甘德县| 军事| 南皮县| 栾川县| 陆河县| 盐源县| 临城县| 阿图什市| 克东县| 太仆寺旗| 兰溪市| 玉环县| 泊头市| 高台县| 沙坪坝区| 济源市| 通州市|