JavaScript 中的遍歷

2021-03-02 程式設計師之家

作者:Barry Zhang(張新強)

原文:www.barryzhang.com/archives/521

(點擊文末閱讀原文即可前往) 

編程這麼多年,要是每次寫遍歷代碼時都用 for 循環,真心感覺對不起 JavaScript 語言~

對象遍歷

為了便於對象遍歷的測試,我在下面定義了一個測試對象 obj 。

測試對象

//   為 Object 設置三個自定義屬性(可枚舉)

Object.prototype.userProp = 'userProp';

Object.prototype.getUserProp = function() {

        return Object.prototype.userProp;

};

//   定義一個對象,隱式地繼承自 Object.prototype

var obj = {

      name: 'percy',

      age: 21,

      [Symbol('symbol 屬性')]: 'symbolProp',

      unEnumerable: '我是一個不可枚舉屬性',

      skills: ['html', 'css', 'js'],

      getSkills: function() {

      return this.skills;

      }

};

//   設置 unEnumerable 屬性為不可枚舉屬性

Object.defineProperty(obj, 'unEnumerable', {

        enumerable: false

});

ES6 之後,共有以下 5 種方法可以遍歷對象的屬性。

for…in: 遍歷對象自身的和繼承的可枚舉屬性(不含 Symbol 類型的屬性

for ( let key in obj ) {

      console.log( key );

      console.log( obj.key );    

      console.log( obj[key] );   

}

不要使用 for…in 來遍歷數組,雖然可以遍歷,但是如果為 Object.prototype 設置了可枚舉屬性後,也會把這些屬性遍歷到,因為數組也是一種對象。

Object.keys(obj):返回一個數組,包括對象自身的(不含繼承的)所有可枚舉屬性(不含 Symbol 類型的屬性)

Object.keys(obj);

//   ["name", "age", "skills", "getSkills"]

Object.getOwnPropertyNames(obj):返回一個數組,包含對象自身的所有屬性(不含 Symbol 類型的屬性,不包含繼承屬性,但是包括不可枚舉屬性)

Object.getOwnPropertyNames(obj);

//   ["name", "age", "unEnumerable", "skills", "getSkills"]

Object.getOwnPropertySymbols(obj):返回一個數組,包含對象自身的所有 Symbol 類型的屬性(不包括繼承的屬性)

Object.getOwnPropertyNames(obj); 

//   [Symbol(symbol 屬性)]

Reflect.ownKeys(obj):返回一個數組,包含對象自身的所有屬性(包含 Symbol 類型的屬性,還有不可枚舉的屬性,但是不包括繼承的屬性)

Reflect.ownKeys(obj);

//  ["name", "age", "unEnumerable", "skills", "getSkills", Symbol(symbol 屬性)]

以上的5種方法遍歷對象的屬性,都遵守同樣的屬性遍歷的次序規則

1)首先遍歷所有屬性名為數值的屬性,按照數字排序

2)其次遍歷所有屬性名為字符串的屬性,按照生成時間排序

3)最後遍歷所有屬性名為Symbol值的屬性,按照生成時間排序

如何判斷某個屬性是不是某個對象自身的屬性呢?

用 in 操作符(不嚴謹,它其實判定的是這個屬性在不在該對象的原型鏈上)

'age' in obj;             

'userProp' in obj;    

'name' in Object;    

// 上面這個也是 true 的原因是,Object 是一個構造函數,而函數恰巧也有一個 name 屬性

Object.name;          // 'Object'

Array.name;           

用 hasOwnProperty(),這個方法只會檢測某個對象上的屬性,而不是原型鏈上的屬性。

obj.hasOwnProperty('age');          

obj.hasOwnProperty('skills');        

obj.hasOwnProperty('userProp'); 

但是它還是有不足之處的。舉例~

// 利用 Object.create() 新建一個對象,並且這個對象沒有任何原型鏈

var obj2 = Object.create(null, {

      name: { value: 'percy' },

      age: { value: 21 },

      skills: { value: ['html', 'css', 'js'] }

});

obj2.hasOwnProperty('name'); // 報錯

obj2.hasOwnProperty('skills');  

針對上面的情況,我們用一個更完善的解決方案來解決。

使用 Object.prototype.hasOwnProperty.call(obj,』prop』…)

Object.prototype.hasOwnProperty.call(obj2,'name');       

Object.prototype.hasOwnProperty.call(obj2,'skills');        

Object.prototype.hasOwnProperty.call(obj2,'userProp'); 

數組遍歷

數組實際上也是一種對象,所以也可以使用上面對象遍歷的任意一個方法(但要注意尺度),另外,數組還擁有其他遍歷的方法。

最基本的 for 循環、while 循環遍歷(缺陷是多添加了一個計數變量)

ES6 引入:for…of ,這下就沒有這個計數變量了,但是也不夠簡潔(這裡不做詳細介紹,以後寫)

for(let value of arr){

     console.log(value);

}

下面說幾種數組內置的一些遍歷方法

Array.prototype.forEach(callback(currentValue, index, array){

       // do something

}[,thisArg]);

// 如果數組在迭代時被修改了,則按照索引繼續遍歷修改後的數組

var words = ["one", "two", "three", "four"];

words.forEach(function(word) {

     console.log(word);

     if (word === "two") {

       words.shift();

}

});

// one

// two

// four

Array.prototype.map(): 返回一個新數組,每個元素都是回調函數返回的值

Array.prototype.map(callback(currentValue, index, array){

         // do something

}[,thisArg]);

```

```js

// map 的一個坑

[1,2,3].map(parseInt); 

// 提示   map(currentValue,index,array)

//        parseInt(value,base)

一些有用的數組內置方法(類似 map,回調函數的參數都是那 3 個)

Array.prototype.reduceRight(callback[, initialValue]): 用法和上面的函數一樣,只不過遍歷方向正好相反

// 一些相關的案例

// 對數組進行累加、累乘等運算

[1,10,5,3,8].reduce(function(accumulator,currentValue){

      return accumulator*currentValue;

});  

// 數組扁平化

[[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {

      return a.concat(b);

});  

[[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {

     return a.concat(b);

});  

總結一下上面這些函數的共性:

1)都是通過每次的回調函數的返回值進行邏輯操作或判斷的

2)回調函數都可以寫成更簡潔的箭頭函數(推薦)

3)都可以通過形如 Array.prototype.map.call(str,callback) 的方式來操作字符串

var str = '123,hello';

// 反轉字符串

Array.prototype.reduceRight.call(str,function(a,b){

      return a+b;

});  

// 過濾字符串,只保留小寫字母

Array.prototype.filter.call('123,hello', function(a) {

      return /[a-z]/.test(a);

}).join('');  

// 利用 map 遍歷字符串(這個例子明顯舉得不太好 *_*)

Array.prototype.map.call(str,function(a){

      return a.toUpperCase();

});  

最下面的文章想說的就是讓我們用更簡潔的語法(比如內置函數)遍歷數組,從而消除循環結構。

微信公眾號內回複數字「1」

小編拉你進粉絲微信群

不是在文章評論裡回復

相關焦點

  • 有關樹遍歷的javascript實現【前端-總結-leetcode算法題】
    在這裡插入圖片描述前言二月的第一天,總結一下近段時間刷的有關樹遍歷的leetcode算法題,希望寫完這篇文章的我和看完文章的你都有些收穫吧。全篇主要講的是有關樹的遍歷,使用前端javascript語言實現。當然有關樹的操作還有很多需要的深入理解和總結的。今天就暫時先把樹遍歷理解全吧。
  • JavaScript 各種遍歷方式詳解,有你不知道的黑科技
    >var i = 0, len = demo1Arr.length;for(; i<len; i++) {};跳出循環的方式有如下幾種return 函數執行被終止break 循環被終止continue 循環被跳過  完整實例  for in  for(var item in arr|obj){} 可以用於遍歷數組和對象
  • JavaScript Loop教程–如何在JavaScript中遍歷數組
    維基百科將For循環定義為:「在計算機科學中,for循環(或簡稱為for循環)是用於指定迭代的控制流 語句,該語句允許重複執行代碼。」for循環是一種重複執行代碼的方法。console.log(「hi」)您可以將其包裝在for循環中,而不必鍵入5次。在第一個示例中,我們將學習如何遍歷上面看到的cars數組,並列印出每個元素。
  • 新特性for-of循環,讓javascript程序語言重獲超強生命力
    在ES6中,新增特性for-of循環,javascript程序語言在for循環方面,功能更加豐富強大,重獲超強生命力!在計算機發展過程中,計算機程式語言一直被視為計算機硬體的靈魂。而每種有超強生命力的程式語言,都是在工業應用中不斷完善發展的。作為前端編程的主流程式語言,javascript語言也不例外。在javascript程序語言,新增特性for-of循環,讓循環更加簡潔直接,功能更加豐富多樣。克服了for-in循環和forEach循環的不足,給javascript語言帶來了新的活力。
  • 使用jQuery的prev()、prevAll()和prevUntil()向上遍歷同胞元素
    對Html DOM的遍歷是全方位的,可以向上級遍歷祖先、也可以向下遍歷子孫,當然還可以平行遍歷同胞。在使用jQuery遍歷同胞時,可以遍歷上一個同胞,也可以遍歷下一個同胞。使用jQuery中的prev()方法可以遍歷當前所選元素的上一個同胞元素,也就是平行級別上面的同胞元素。prev()方法只能獲取同級別的上一個Html元素,並且是不包含當前被選Html元素的。
  • JS幾種數組遍歷方式總結
    這種方法基本上是所有循環遍歷方法中性能最高的一種第三種:弱化版for循環for(j = 0; arr[j]!實際性能要比普通foreach弱第六種:forin循環簡要說明: 這個循環很多人愛用,但實際上,經分析測試,在眾多的循環遍歷方式中它的效率是最低的第七種:map遍歷簡要說明: 這種方式也是用的比較廣泛的,雖然用起來比較優雅,但實際效率還比不上foreach第八種:forof遍歷(需要ES6支持)
  • JavaScript中的簡單排序算法
    英文 | https://medium.com/javascript-in-plain-english/simple-sorting-algorithms-in-javascript
  • javascript常用函數推薦
    繼續上一篇的內容,本文繼續javascript數組相關的常用函數推薦,基於ES6+規範,上一篇請查看這裡countOccurrences計算數組中值的出現次數。每次遇到數組內的特定值時,使用Array.prototype.reduce()遞增計數器。
  • 20個常用的JavaScript簡寫技巧
    箭頭函數 參考:JavaScript Arrow function https://jscurious.com/javascript-arrow-function/ 8. 模板字符串 我們一般使用 + 運算符來連接字符串變量。
  • 什麼是JavaScript對象?如何創建並引用?這就告訴你!
    1.2 什麼是對象對象:就類中的一個具體的實物。人類-具體某一個人(張三丰)。動物類-(一個具體的動物-東北虎),家電類-(具體一個比如說電視。)js 中我們包含哪些對象呢?中一個被我們經常使用的類型,而且JS中的所有對象都是繼承自Object對象的三、對象的鍵名和鍵值(重點)3.1關於鍵名鍵名也被稱為屬性(property),對象的所有屬性都是字符串,所以加不加引號都可以。
  • AST抽象語法樹:最基礎的 Javascript 重點知識
    我們對javascript生態了如指掌,卻常忽視javascript本身。這臺機器,究竟是哪些零部件在支持著它運行?AST在日常業務中也許很難涉及到,但當你不止於想做一個工程師,而想做工程師的工程師,寫出vue、react之類的大型框架,或類似webpack、vue-cli前端自動化的工具,或者有批量修改源碼的工程需求,那你必須懂得AST。
  • numpy中數組的遍歷技巧
    在numpy中,當需要循環處理數組中的元素時,能用內置通函數實現的肯定首選通函數,只有當沒有可用的通函數的情況下,再來手動進行遍歷,遍歷的方法有以下幾種
  • JavaScript算法練習:字符串反轉
    這種方法使用的是一個for循環給原字符串做一個遞減遍歷,然後將遍歷的字符串重新合併成一個新字符串:function reverseString(str) {    // 第一步:創建一個空的字符串用來存儲新創建的字符串    var newString = "";    // 第二步:使用for循環    // 循環從
  • JavaScript中Array方法的正確打開方式
    於是我寫了這篇文章,總結了如何在 JavaScript 中正確使用地使用 Array 的方法! 用 Array.includes 代替 Array.indexOf「如果你要在數組中查找元素,請使用 Array.indexOf」。我記得在學習 JavaScript 的時候,在教材中讀到這樣的一句話。毫無疑問,這句話是真的!
  • JavaScript中的陷阱大集合
    typeoftypeof這會返回一個javascript基本類型的實例的類型。evaleval 可以將字符串以javascript代碼的形式來解析執行,但是一般來說我們不建議這麼做。因為eval非常慢 - 當javascript被加載到瀏覽器中時,它會被編譯成本地代碼;然而執行的過程中每次遇到eval表達式,編譯引擎都將重新啟動執行編譯,這樣做的代 價太大了。
  • 遍歷在政法幹警考試中的新特點
    遍歷在公務員考試中通常是指每行(或每列)中含有完全相同的若干個樣式,在每行(或每列)中對相同的樣式進行不同的排列組合,保證每一種樣式在每行(或每列)中都要出現一次。簡單的來講就是在某個範圍尋找某類事物的全集。比如我們看一個經典的智商測驗的原題。如下圖:
  • 經典模擬:程序設計中的FOR循環,是螳螂捕蟬黃雀在後的經典實現
    經典模擬:程序設計中的FOR循環,是螳螂捕蟬黃雀在後的經典實現!在程序設計中,無論使用的是什麼程式語言,循環語句都是必不可少的,可以說,循環體是程序的靈魂。程序中的循環,就是現實世界循環的抽象。螳螂捕蟬黃雀在後,就是for三層嵌套的經典實現。
  • 你必須要知道的JavaScript數據結構與面試題解答
    JavaScript中的數據結構:面試複習(地址:https://www.educative.io/courses/data-structures-in-javascript-an-interview-refresher)對於許多開發人員和程式設計師而言,數據結構對於破解編程面試至關重要。有關數據結構的問題是現代編程開發面試中的基礎。實際上,對於你的應聘能力和入門級職位,有很多話要說。
  • 每日一課 | JavaScript中的數組
    JavaScript中的數組具有length屬性,該屬性返回該數組的大小。我們僅初始化數組,並且未在數組中添加任何元素。如何檢索數組中的第一個和最後一個元素? 在javascript中,數組不是其他語言(例如c#,java)的定長數組類型,即使它們聲明為定長,它也會動態增長。
  • foreach中遍歷list中string.contains的使用
    現在講有三個string類型list,列表中數據如下;三者的關係如圖所示,這裡需要得到圖中紅色部分;主要B、C中包含A的的字符串即可,不需要完全相同;這裡如果直接按照列表中進行遍歷可以直接通過foreach進行遍歷;代碼1:using System.Collections