摘要:再將其返回,注意是返回一個(gè)新的數(shù)組,而不是將原數(shù)組直接改變使用方式和類似也是接受一個(gè)回調(diào)函數(shù),一個(gè)改變內(nèi)部指向的對(duì)象。
前言
新增方法預(yù)覽一直以來想寫一篇關(guān)于es5中新增數(shù)組的使用方法與源碼實(shí)現(xiàn)的文章,拖了挺久了,趁著這夜深人靜,大腦清醒,又困意不在的時(shí)刻寫下來。也許有人會(huì)問,現(xiàn)如今es6都大行其道了,還學(xué)es5是不是有些過時(shí)了,?,溫故而知新,可以從中多學(xué)點(diǎn)嘛,而且我們是要自己實(shí)現(xiàn)這些方法,知其然還要知其所以然,不光要會(huì)用,還要知道為什么是這樣用噠。
es5中給js的數(shù)組增添了許多實(shí)用的方法,利用這些方法可以幫助我們更加快速方便的寫js代碼,然后蛋疼的是低版本ie肯定是不支持的,所以..................自己動(dòng)手豐衣足食。讓我們一步步看下如何使用與實(shí)現(xiàn)這些方法。
forEach
map
filter
some
every
indexOf
lastIndexOf
reduce
reduceRight
forEach這個(gè)方法作用是啥咧,就是循環(huán),遍歷。比如一般我們?cè)趂or循環(huán)做這樣的事的時(shí)候如下。
var arr = [1, 2, 3, 4, 5, 6]; for (var i = 0, len = arr.length; i < len; i++) { console.log(arr[i], i, arr); }
如果用forEach我們應(yīng)該如何做呢?
var arr = [1, 2, 3, 4, 5, 6]; arr.forEach(function (e, i, array) { console.log(e, i, array) })
是不是覺得不用寫for循環(huán)了,瞬間逼格都高了
forEach函數(shù)中的回調(diào)函數(shù)支持三個(gè)參數(shù),1、數(shù)組的值,2、值的索引,3、數(shù)組本身。這樣的調(diào)用方式是不是和jQuery中的$.each很像? 其實(shí)不然,jQuery和forEach回調(diào)函數(shù)的第一個(gè)和第二個(gè)參數(shù)正好是反著來的。
看看對(duì)比
var arr = [1, 2, 3, 4, 5]; // forEach arr.forEach(function (e, i, array) { console.log(e, i, array); }) // output 1 0 [1, 2, 3, 4, 5] 2 1 [1, 2, 3, 4, 5] 3 2 [1, 2, 3, 4, 5] 4 3 [1, 2, 3, 4, 5] 5 4 [1, 2, 3, 4, 5] // $.each $.each(arr, function (i, e, array) { // 測(cè)試的時(shí)候發(fā)現(xiàn)array是undefined,查了文檔也發(fā)現(xiàn)沒有第三個(gè)參數(shù) console.log(i, e, array); }) // output 0 1 undefined 1 2 undefined 2 3 undefined 3 4 undefined 4 5 undefined
接著我們來看一下forEach的第二個(gè)參數(shù),這個(gè)參數(shù)決定第一個(gè)回調(diào)函數(shù)的內(nèi)部this指向
var arr = [1, 2, 3, 4, 5]; // 默認(rèn)情況下,第二個(gè)參數(shù)不傳入時(shí) arr.forEach(function (e, i, array) { console.log(e, i, array, this); }) // output 1 0 [1, 2, 3, 4, 5] window 2 1 [1, 2, 3, 4, 5] window 3 2 [1, 2, 3, 4, 5] window 4 3 [1, 2, 3, 4, 5] window 5 4 [1, 2, 3, 4, 5] window // 傳入?yún)?shù) arr.forEach(function (e, i, array) { console.log(e, i, array, this); }, {name: "qianlong"}) // output 1 0 [1, 2, 3, 4, 5] {name: "qianlong"} 2 1 [1, 2, 3, 4, 5] {name: "qianlong"} 3 2 [1, 2, 3, 4, 5] {name: "qianlong"} 4 3 [1, 2, 3, 4, 5] {name: "qianlong"} 5 4 [1, 2, 3, 4, 5] {name: "qianlong"}
最后接下來我們自己實(shí)現(xiàn)一下這個(gè)方法
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeArray = ObjPro.forEach; Array.prototype.forEach = nativeArray || function (callBack, ctx) { if (typeof callBack != "function") return; for (var i =0, len = this.length; i < len; i++) { if (hasOwn.call(this, i)) { callBack.call(ctx, this[i], i, this); } } }map
map是干嘛的! 其最主要的作用就是將原數(shù)組按照一定的規(guī)則映射成一個(gè)新的數(shù)組。再將其返回,注意是返回一個(gè)新的數(shù)組,而不是將原數(shù)組直接改變使用方式和forEach類似,也是接受一個(gè)回調(diào)函數(shù),一個(gè)改變內(nèi)部this指向的對(duì)象。
map
array.map(callback,[ thisObject])
callback
var arr = [1, 2, 3, 4, 5]; arr.map(function(value, index, array) { });
舉個(gè)栗子
var arr = [1, 2, 3, 4, 5]; var newArr = arr.map(function (e, i, array) { return "hello " + e; }) // output ["hello 1", "hello 2", "hello 3", "hello 4", "hello 5"] // newArr [1, 2, 3, 4, 5] // arr
注意上面的return,如果我們不寫return會(huì)怎樣呢?
var arr = [1, 2, 3, 4, 5]; var newArr = arr.map(function (e, i, array) { "hello " + e; }) // output [undefined, undefined, undefined, undefined, undefined] // newArr [1, 2, 3, 4, 5] // arr
這一堆的undefined是啥情況,還記得一個(gè)函數(shù)執(zhí)行完,如果沒有顯示的返回值,會(huì)返回什么嗎? 沒錯(cuò) 就是undefined,這就是原因所在,等會(huì)通過源碼,你就會(huì)更加明白。
最后我們自己實(shí)現(xiàn)一下map這個(gè)方法
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeMap = ObjPro.map; Array.prototype.map = nativeMap || function (callBack, ctx) { if (typeof callBack != "function") return; var returnArr = []; for(var i = 0, len = this.length; i < len; i++) { returnArr.push(callBack.call(ctx, this[i], i, this)); // 這就是為什么回調(diào)函數(shù)沒有返回值的情況下會(huì)得到一堆的undefined值,他將回調(diào)函數(shù)的返回值push到了一個(gè)數(shù)組里面,當(dāng)你沒有顯示的返回值的時(shí)候,自然push進(jìn)去的就是undefined了 } return returnArr; }filter
接下來是filter,篩選,過濾的意思,給你一個(gè)數(shù)組,用一些你制定的條件,對(duì)其中的值進(jìn)行過濾,最后得到你想要的新的數(shù)組?;居梅ê蚼ap差不多
array.filter(callback,[ thisObject]);
但是和map也有差別的地方,filter需要你在callback處返回弱等于true 的值,才會(huì)將原數(shù)組中篩選出的值返回給你。
舉個(gè)栗子
var arr = [0, 1, 2, 3, 4, 5]; var newArr = arr.filter(function (e, i, array) { return e; }) // output [1, 2, 3, 4, 5] // newArr var newArr2 = arr.filter(function (e, i, array) { if (e >= 2) return true; }) // ouput [2, 3, 4, 5] // newArr2
當(dāng)然最后還有第二個(gè)參數(shù)改變內(nèi)部this指向的參數(shù)可選,默認(rèn)是window對(duì)象,你也可以傳一個(gè)對(duì)象進(jìn)去, 最后我們自己來實(shí)現(xiàn)一下這個(gè)api
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeFilter = ObjPro.filter; Array.prototype.filter = nativeFilter || function (callBack, ctx) { if (typeof callBack != "function") return; var returnArr = []; for(var i = 0, len = this.length; i < len; i++) { if (callBack.call(ctx, this[i], i, this)) { returnArr.push(this[i]); } } return returnArr; }some vs every
some與接下里的every正好相對(duì),some是只要數(shù)組中的某個(gè)值,符合你給定的判斷條件就返回true,而every則是數(shù)組中的所有值都符合你給定的判斷條件的時(shí)候才會(huì)返回true,否則就返回false,也就是說兩個(gè)方法最后得到的都是true or false
舉個(gè)栗子
var arr = [0, 1, 2, 3, 4, 5]; var result = arr.some(function (e, i, array) { if (e === 3) {return true}; }); // output true // result; var arr = [0, 1, 2, 3, 4, 5]; var result2 = arr.every(function (e, i, array) { if (e > 3) {return true}; }); // output false // result;
some 和 every使用起來非常簡單,接下來我們自己實(shí)現(xiàn)一把
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeSome = ObjPro.some, nativeEvery = ObjPro.every; // some Array.prototype.some = nativeSome || function (callBack, ctx) { if (typeof callBack != "function") return; var resultValue = false; for(var i = 0, len = this.length; i < len; i++) { if (resultValue) { break; } resultValue = !!callBack.call(ctx, this[i], i, this); } return resultValue; } // every Array.prototype.every = nativeEvery || function (callBack, ctx) { if (typeof callBack != "function") return; var resultValue = true; for (var i = 0, len = this.length; i < len; i++) { if (!resultValue) { break; } resultValue = !!callBack.call(ctx, this[i], i, this); } return resultValue; }indexOf
數(shù)組的indexOf方法和字符串的indexOf用法非常類似,array.indexOf(searchElement[, fromIndex]),針對(duì)給定的要查找的值,和開始查找的位置(可選),返回整數(shù)索引值。
舉個(gè)例子
var arr = [0, 1, 2, 3, 4, 5]; arr.indexOf(1) // 1 arr.indexOf(3, "qianlong") // 3 因?yàn)榻o定的開始索引值不能轉(zhuǎn)化成數(shù)字,所以還是從0位置開始搜索 arr.indexOf(3, 4) // -1 arr.indexOf(3, "4") // -1 arr.indexOf("3") // -1 // 判斷條件是強(qiáng) 3 !== "3" => -1
實(shí)現(xiàn)代碼
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeIndexOf = ObjPro.indexOf; Array.prototype.indexOf = nativeIndexOf || function (searchElement, fromIndex) { var returnIndex = -1, fromIndex = fromIndex * 1 || 0; for (var i = fromIndex, len = this.length; i < len; i++) { if (searchElement === this[i]) { returnIndex = i; break; } } return returnIndex; }lastIndexOf
數(shù)組的lastIndexOf方法和字符串的lastIndexOf用法非常類似,array. lastIndexOf(searchElement[, fromIndex]),針對(duì)給定的要查找的值,和開始查找的位置(可選),返回整數(shù)索引值。與indexOf不同的地方在于,它是從后往前查找。默認(rèn)開始查找的位置是 array.length - 1
舉個(gè)栗子
var arr = [0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0]; arr.lastIndexOf(1) // 9 arr.lastIndexOf(3, "qianlong") // -1 這里和indexOf不一樣,傳入的值不能轉(zhuǎn)化為數(shù)字將得到-1 arr.lastIndexOf(3, 4) // 3 arr.lastIndexOf(3, "4") // 3 arr.lastIndexOf("3") // -1 // 判斷條件是強(qiáng) 3 !== "3" => -1
源碼實(shí)現(xiàn)
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeLastIndexOf = ObjPro.lastIndexOf; Array.prototype.lastIndexOf = nativeLastIndexOf || function (searchElement, fromIndex) { var len = this.length, returnIndex = -1, fromIndex = fromIndex * 1 || len - 1; for (var i = fromIndex; i > -1; i -= 1) { if (this[i] === searchElement){ returnIndex = i; break; } } return returnIndex; }reduce
reduce 相對(duì)es5中數(shù)添加的其他方法都復(fù)雜一些,我們可以通過栗子來看一下這個(gè)api怎么使用。首先基本參數(shù)如下
array.reduce(callback[, initialValue]),接收一個(gè)回調(diào)函數(shù),一個(gè)初始化的值initialValue 。其中callback參數(shù)分別是初始化的值initialValue ,如果沒有傳入initialValue,則默認(rèn)是數(shù)組的第一項(xiàng)。第二個(gè)及其后面的參數(shù)分別是當(dāng)前值,索引,數(shù)組本身
var arr = [0, 1, 2, 3, 4, 5], sum = arr.reduce(function (init, cur, i, array) { return init + cur; }); //output sum // 15
我們來看一下上面的執(zhí)行過程是怎樣的。
第一回合
// 因?yàn)閕nitialValue沒有傳入所以回調(diào)函數(shù)的第一個(gè)參數(shù)為數(shù)組的第一項(xiàng) init = 0; cur = 1; => init + cur = 1;
第二回合
init = 1; cur = 2; => init + cur = 3;
第三回合
init = 3; cur = 3; => init + cur = 6;
第四回合
init = 6; cur = 4; => init + cur = 10;
第五回合
init = 10; cur = 5; => init + cur = 15;
最后得到結(jié)果15
那么我們?nèi)绾巫约簩?shí)現(xiàn)一個(gè)reduce呢?
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeReduce = ObjPro.reduce; Array.prototype.reduce = nativeReduce || function (callBack, initialVal) { if (typeof callBack != "function") return; var init = initialVal, i = 0; if (init === void (0)) { init = this[0]; i = 1; } for (i, len = this.length; i < len; i++) { if (hasOwn.call(this, i)) { init = callBack(init, this[i], i, this); } } return init; }reduceRight
reduceRight基本用法與reduce類似,好比indexOf與lastIndexOf,不同之處在于它是從最右邊的值開始計(jì)算的。我們直接去看源碼怎么實(shí)現(xiàn)吧
var ObjPro = Object.prototype, hasOwn = ObjPro.hasOwnProperty, nativeReduceRight = ObjPro.reduceRight; Array.prototype.reduceRight = nativeReduceRight || function (callBack, initialVal) { if (typeof callBack != "function") return; var init = initialVal, len = this.length, i = len - 1; if (init === void(0)) { init = this[len - 1]; i -= 1; } for (i; i > -1; i -=1) { if (hasOwn.call(this, i)) { init = callBack(init, this[i], i, this); } } return init; }結(jié)尾
終于寫完了,斷斷續(xù)續(xù)快寫了兩天,歡迎大家看了以后提一些意見,函數(shù)實(shí)現(xiàn)的不一定都對(duì),肯定有一些問題的地方,歡迎大家指正。
最后把代碼放到github上面了
github地址
各位大大,請(qǐng)讓我打個(gè)小廣告。???
博客地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/91042.html
摘要:數(shù)組去重是校招面試的必考知識(shí)點(diǎn)。以下就是筆者所實(shí)現(xiàn)的數(shù)組去重的幾種簡單的方式。結(jié)合實(shí)現(xiàn)這種方法的關(guān)鍵點(diǎn)就是判斷是否相同的時(shí)候不要忽略對(duì)元素類型的判斷。以上就是筆者所想到的幾個(gè)數(shù)組去重的方式大家如果有更好的方法歡迎留言。 數(shù)組去重,是校招面試的必考知識(shí)點(diǎn)。簡單的說,數(shù)組去重就是將一個(gè)數(shù)組中的相同的元素刪除,只保留其中的一個(gè)。這里的相同其實(shí)是一個(gè)陷阱,有好多同學(xué)只認(rèn)為值相等即為相同,而忽略...
摘要:問中新增的數(shù)據(jù)類型有哪些使用場(chǎng)景中新增一種原始數(shù)據(jù)類型最大的特點(diǎn)是唯一性,值通過函數(shù)生成在中對(duì)象的屬性都是字符串,我們使用他人定義的對(duì)象,然后去新增自己的屬性,這樣容易起沖突覆蓋原有的屬性也可以看成為一個(gè)字符串,不過這個(gè)字符能保證是獨(dú)一無二 20190125問: Es6中新增的數(shù)據(jù)類型有哪些?使用場(chǎng)景? es6中新增一種原始數(shù)據(jù)類型Symbol,最大的特點(diǎn)是唯一性,Symbol值通過S...
摘要:問中新增的數(shù)據(jù)類型有哪些使用場(chǎng)景中新增一種原始數(shù)據(jù)類型最大的特點(diǎn)是唯一性,值通過函數(shù)生成在中對(duì)象的屬性都是字符串,我們使用他人定義的對(duì)象,然后去新增自己的屬性,這樣容易起沖突覆蓋原有的屬性也可以看成為一個(gè)字符串,不過這個(gè)字符能保證是獨(dú)一無二 20190125問: Es6中新增的數(shù)據(jù)類型有哪些?使用場(chǎng)景? es6中新增一種原始數(shù)據(jù)類型Symbol,最大的特點(diǎn)是唯一性,Symbol值通過S...
摘要:新建數(shù)組新建數(shù)組的方法有三種方法一方法二方法三新增是中新增的將一組值轉(zhuǎn)換為數(shù)組的方法,該方法的出現(xiàn)時(shí)為了彌補(bǔ)構(gòu)造函數(shù)因?yàn)閰?shù)不同導(dǎo)致的不同行為。 原文鏈接:http://mrzhang123.github.io/2016/08/03/js-Array 在ECMAScript中最常用的類型之一就是Array類型,Array類型的方法也有很多,所以在這篇文章中,梳理一下Array類型的方法...
閱讀 2210·2021-11-23 09:51
閱讀 1495·2019-08-30 15:55
閱讀 1752·2019-08-30 15:44
閱讀 893·2019-08-30 14:11
閱讀 1282·2019-08-30 14:10
閱讀 1056·2019-08-30 13:52
閱讀 2781·2019-08-30 12:50
閱讀 759·2019-08-29 15:04