国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript專(zhuān)題之?dāng)?shù)組去重

fsmStudy / 2067人閱讀

摘要:專(zhuān)題系列第三篇,講解各種數(shù)組去重方法,并且跟著寫(xiě)一個(gè)前言數(shù)組去重方法老生常談,既然是常談,我也來(lái)談?wù)劇K?lèi)似于數(shù)組,但是成員的值都是唯一的,沒(méi)有重復(fù)的值。

JavaScript 專(zhuān)題系列第三篇,講解各種數(shù)組去重方法,并且跟著 underscore 寫(xiě)一個(gè) unique API

前言

數(shù)組去重方法老生常談,既然是常談,我也來(lái)談?wù)劇?/p> 雙層循環(huán)

也許我們首先想到的是使用 indexOf 來(lái)循環(huán)判斷一遍,但在這個(gè)方法之前,讓我們先看看最原始的方法:

var array = [1, 1, "1", "1"];

function unique(array) {
    // res用來(lái)存儲(chǔ)結(jié)果
    var res = [];
    for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
        for (var j = 0, resLen = res.length; j < resLen; j++ ) {
            if (array[i] === res[j]) {
                break;
            }
        }
        // 如果array[i]是唯一的,那么執(zhí)行完循環(huán),j等于resLen
        if (j === resLen) {
            res.push(array[i])
        }
    }
    return res;
}

console.log(unique(array)); // [1, "1"]

在這個(gè)方法中,我們使用循環(huán)嵌套,最外層循環(huán) array,里面循環(huán) res,如果 array[i] 的值跟 res[j] 的值相等,就跳出循環(huán),如果都不等于,說(shuō)明元素是唯一的,這時(shí)候 j 的值就會(huì)等于 res 的長(zhǎng)度,根據(jù)這個(gè)特點(diǎn)進(jìn)行判斷,將值添加進(jìn) res。

看起來(lái)很簡(jiǎn)單吧,之所以要講一講這個(gè)方法,是因?yàn)椤嫒菪院茫?/p> indexOf

我們可以用 indexOf 簡(jiǎn)化內(nèi)層的循環(huán):

var array = [1, 1, "1"];

function unique(array) {
    var res = [];
    for (var i = 0, len = array.length; i < len; i++) {
        var current = array[i];
        if (res.indexOf(current) === -1) {
            res.push(current)
        }
    }
    return res;
}

console.log(unique(array));
排序后去重

試想我們先將要去重的數(shù)組使用 sort 方法排序后,相同的值就會(huì)被排在一起,然后我們就可以只判斷當(dāng)前元素與上一個(gè)元素是否相同,相同就說(shuō)明重復(fù),不相同就添加進(jìn) res,讓我們寫(xiě)個(gè) demo:

var array = [1, 1, "1"];

function unique(array) {
    var res = [];
    var sortedArray = array.concat().sort();
    var seen;
    for (var i = 0, len = sortedArray.length; i < len; i++) {
        // 如果是第一個(gè)元素或者相鄰的元素不相同
        if (!i || seen !== sortedArray[i]) {
            res.push(sortedArray[i])
        }
        seen = sortedArray[i];
    }
    return res;
}

console.log(unique(array));

如果我們對(duì)一個(gè)已經(jīng)排好序的數(shù)組去重,這種方法效率肯定高于使用 indexOf。

unique API

知道了這兩種方法后,我們可以去嘗試寫(xiě)一個(gè)名為 unique 的工具函數(shù),我們根據(jù)一個(gè)參數(shù) isSorted 判斷傳入的數(shù)組是否是已排序的,如果為 true,我們就判斷相鄰元素是否相同,如果為 false,我們就使用 indexOf 進(jìn)行判斷

var array1 = [1, 2, "1", 2, 1];
var array2 = [1, 1, "1", 2, 2];

// 第一版
function unique(array, isSorted) {
    var res = [];
    var seen = [];

    for (var i = 0, len = array.length; i < len; i++) {
        var value = array[i];
        if (isSorted) {
            if (!i || seen !== value) {
                res.push(value)
            }
            seen = value;
        }
        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }
    return res;
}

console.log(unique(array1)); // [1, 2, "1"]
console.log(unique(array2, true)); // [1, "1", 2]
優(yōu)化

盡管 unqique 已經(jīng)可以試下去重功能,但是為了讓這個(gè) API 更加強(qiáng)大,我們來(lái)考慮一個(gè)需求:

新需求:字母的大小寫(xiě)視為一致,比如"a"和"A",保留一個(gè)就可以了!

雖然我們可以先處理數(shù)組中的所有數(shù)據(jù),比如將所有的字母轉(zhuǎn)成小寫(xiě),然后再傳入unique函數(shù),但是有沒(méi)有方法可以省掉處理數(shù)組的這一遍循環(huán),直接就在去重的循環(huán)中做呢?讓我們?nèi)ネ瓿蛇@個(gè)需求:

var array3 = [1, 1, "a", "A", 2, 2];

// 第二版
// iteratee 英文釋義:迭代 重復(fù)
function unique(array, isSorted, iteratee) {
    var res = [];
    var seen = [];

    for (var i = 0, len = array.length; i < len; i++) {
        var value = array[i];
        var computed = iteratee ? iteratee(value, i, array) : value;
        if (isSorted) {
            if (!i || seen !== value) {
                res.push(value)
            }
            seen = value;
        }
        else if (iteratee) {
            if (seen.indexOf(computed) === -1) {
                seen.push(computed);
                res.push(value);
            }
        }
        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }
    return res;
}

console.log(unique(array3, false, function(item){
    return typeof item == "string" ? item.toLowerCase() : item
})); // [1, "a", 2]

在這一版也是最后一版的實(shí)現(xiàn)中,函數(shù)傳遞三個(gè)參數(shù):

array:表示要去重的數(shù)組,必填

isSorted:表示函數(shù)傳入的數(shù)組是否已排過(guò)序,如果為 true,將會(huì)采用更快的方法進(jìn)行去重

iteratee:傳入一個(gè)函數(shù),可以對(duì)每個(gè)元素進(jìn)行重新的計(jì)算,然后根據(jù)處理的結(jié)果進(jìn)行去重

至此,我們已經(jīng)仿照著 underscore 的思路寫(xiě)了一個(gè) unique 函數(shù),具體可以查看 Github。

filter

ES5 提供了 filter 方法,我們可以用來(lái)簡(jiǎn)化外層循環(huán):

比如使用 indexOf 的方法:

var array = [1, 2, 1, 1, "1"];

function unique(array) {
    var res = array.filter(function(item, index, array){
        return array.indexOf(item) === index;
    })
    return res;
}

console.log(unique(array));

排序去重的方法:

var array = [1, 2, 1, 1, "1"];

function unique(array) {
    return array.concat().sort().filter(function(item, index, array){
        return !index || item !== array[index - 1]
    })
}

console.log(unique(array));
Object 鍵值對(duì)

去重的方法眾多,盡管我們已經(jīng)跟著 underscore 寫(xiě)了一個(gè) unqiue API,但是讓我們看看其他的方法拓展下視野:

這種方法是利用一個(gè)空的 Object 對(duì)象,我們把數(shù)組的值存成 Object 的 key 值,比如 Object[value1] = true,在判斷另一個(gè)值的時(shí)候,如果 Object[value2]存在的話,就說(shuō)明該值是重復(fù)的。示例代碼如下:

var array = [1, 2, 1, 1, "1"];

function unique(array) {
    var obj = {};
    return array.filter(function(item, index, array){
        return obj.hasOwnProperty(item) ? false : (obj[item] = true)
    })
}

console.log(unique(array)); // [1, 2]

我們可以發(fā)現(xiàn),是有問(wèn)題的,因?yàn)?1 和 "1" 是不同的,但是這種方法會(huì)判斷為同一個(gè)值,這是因?yàn)閷?duì)象的鍵值只能是字符串,所以我們可以使用 typeof item + item 拼成字符串作為 key 值來(lái)避免這個(gè)問(wèn)題:

var array = [1, 2, 1, 1, "1"];

function unique(array) {
    var obj = {};
    return array.filter(function(item, index, array){
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
}

console.log(unique(array)); // [1, 2, "1"]
ES6

隨著 ES6 的到來(lái),去重的方法又有了進(jìn)展,比如我們可以使用 Set 和 Map 數(shù)據(jù)結(jié)構(gòu),以 Set 為例,ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set。它類(lèi)似于數(shù)組,但是成員的值都是唯一的,沒(méi)有重復(fù)的值。

是不是感覺(jué)就像是為去重而準(zhǔn)備的?讓我們來(lái)寫(xiě)一版:

var array = [1, 2, 1, 1, "1"];

function unique(array) {
   return Array.from(new Set(array));
}

console.log(unique(array)); // [1, 2, "1"]

甚至可以再簡(jiǎn)化下:

function unique(array) {
    return [...new Set(array)];
}

還可以再簡(jiǎn)化下:

var unique = (a) => [...new Set(a)]

此外,如果用 Map 的話:

function unique (arr) {
    const seen = new Map()
    return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}
JavaScript 的進(jìn)化

我們可以看到,去重方法從原始的 14 行代碼到 ES6 的 1 行代碼,其實(shí)也說(shuō)明了 JavaScript 這門(mén)語(yǔ)言在不停的進(jìn)步,相信以后的開(kāi)發(fā)也會(huì)越來(lái)越高效。

特殊類(lèi)型比較

去重的方法就到此結(jié)束了,然而要去重的元素類(lèi)型可能是多種多樣,除了例子中簡(jiǎn)單的 1 和 "1" 之外,其實(shí)還有 null、undefined、NaN、對(duì)象等,那么對(duì)于這些元素,之前的這些方法的去重結(jié)果又是怎樣呢?

在此之前,先讓我們先看幾個(gè)例子:

var str1 = "1";
var str2 = new String("1");

console.log(str1 == str2); // true
console.log(str1 === str2); // false

console.log(null == null); // true
console.log(null === null); // true

console.log(undefined == undefined); // true
console.log(undefined === undefined); // true

console.log(NaN == NaN); // false
console.log(NaN === NaN); // false

console.log(/a/ == /a/); // false
console.log(/a/ === /a/); // false

console.log({} == {}); // false
console.log({} === {}); // false

那么,對(duì)于這樣一個(gè)數(shù)組

var array = [1, 1, "1", "1", null, null, undefined, undefined, new String("1"), new String("1"), /a/, /a/, NaN, NaN];

以上各種方法去重的結(jié)果到底是什么樣的呢?

我特地整理了一個(gè)列表,我們重點(diǎn)關(guān)注下對(duì)象和 NaN 的去重情況:

方法 結(jié)果 說(shuō)明
for循環(huán) [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN] 對(duì)象和 NaN 不去重
indexOf [1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN] 對(duì)象和 NaN 不去重
sort [/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined] 對(duì)象和 NaN 不去重 數(shù)字 1 也不去重
filter + indexOf [1, "1", null, undefined, String, String, /a/, /a/] 對(duì)象不去重 NaN 會(huì)被忽略掉
filter + sort [/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined] 對(duì)象和 NaN 不去重 數(shù)字 1 不去重
優(yōu)化后的鍵值對(duì)方法 [1, "1", null, undefined, String, /a/, NaN] 全部去重
Set [1, "1", null, undefined, String, String, /a/, /a/, NaN] 對(duì)象不去重 NaN 去重

想了解為什么會(huì)出現(xiàn)以上的結(jié)果,看兩個(gè) demo 便能明白:

// demo1
var arr = [1, 2, NaN];
arr.indexOf(NaN); // -1

indexOf 底層還是使用 === 進(jìn)行判斷,因?yàn)?NaN ==== NaN的結(jié)果為 false,所以使用 indexOf 查找不到 NaN 元素

// demo2
function unique(array) {
   return Array.from(new Set(array));
}
console.log(unique([NaN, NaN])) // [NaN]

Set 認(rèn)為盡管 NaN === NaN 為 false,但是這兩個(gè)元素是重復(fù)的。

寫(xiě)在最后

雖然去重的結(jié)果有所不同,但更重要的是讓我們知道在合適的場(chǎng)景要選擇合適的方法。

專(zhuān)題系列

JavaScript專(zhuān)題系列目錄地址:https://github.com/mqyqingfeng/Blog。

JavaScript專(zhuān)題系列預(yù)計(jì)寫(xiě)二十篇左右,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類(lèi)型判斷、拷貝、最值、扁平、柯里、遞歸、亂序、排序等,特點(diǎn)是研(chao)究(xi) underscore 和 jQuery 的實(shí)現(xiàn)方式。

如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑?qǐng)務(wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對(duì)作者也是一種鼓勵(lì)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/88313.html

相關(guān)文章

  • JS專(zhuān)題數(shù)組去重

    摘要:將元素作為對(duì)象的鍵,默認(rèn)鍵對(duì)應(yīng)的值為如果對(duì)象中沒(méi)有這個(gè)鍵,則將這個(gè)元素放入結(jié)果數(shù)組中去。 前言 數(shù)組去重在日常開(kāi)發(fā)中的使用頻率還是較高的,也是網(wǎng)上隨便一抓一大把的話題,所以,我寫(xiě)這篇文章目的在于歸納和總結(jié),既然很多人都在提的數(shù)組去重,自己到底了解多少呢。又或者是如果自己在開(kāi)發(fā)中遇到了去重的需求,自己能想到更好的解決方案嗎。 這次我們來(lái)理一理怎么做數(shù)組去重才能做得最合適,既要考慮兼容性,...

    only_do 評(píng)論0 收藏0
  • JavaScript專(zhuān)題系列文章

    摘要:專(zhuān)題系列共計(jì)篇,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類(lèi)型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究專(zhuān)題之函數(shù)組合專(zhuān)題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn)模式需求我們需要寫(xiě)一個(gè)函數(shù),輸入,返回。 JavaScript 專(zhuān)題之從零實(shí)現(xiàn) jQuery 的 extend JavaScritp 專(zhuān)題系列第七篇,講解如何從零實(shí)現(xiàn)一個(gè) jQuery 的 ext...

    Maxiye 評(píng)論0 收藏0
  • JavaScript專(zhuān)題系列20篇正式完結(jié)!

    摘要:寫(xiě)在前面專(zhuān)題系列是我寫(xiě)的第二個(gè)系列,第一個(gè)系列是深入系列。專(zhuān)題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫(xiě)在前面 JavaScript 專(zhuān)題系列是我寫(xiě)的第二個(gè)系列,第一個(gè)系列是 JavaScript 深入系列。 JavaScript 專(zhuān)題系列共計(jì) 20 篇,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類(lèi)型判斷、拷貝、最值、扁平、柯里...

    sixleaves 評(píng)論0 收藏0
  • JavaScript專(zhuān)題數(shù)組扁平化

    摘要:專(zhuān)題系列第九篇,講解如何實(shí)現(xiàn)數(shù)組的扁平化,并解析的源碼扁平化數(shù)組的扁平化,就是將一個(gè)嵌套多層的數(shù)組嵌套可以是任何層數(shù)轉(zhuǎn)換為只有一層的數(shù)組。 JavaScript 專(zhuān)題系列第九篇,講解如何實(shí)現(xiàn)數(shù)組的扁平化,并解析 underscore 的 _.flatten 源碼 扁平化 數(shù)組的扁平化,就是將一個(gè)嵌套多層的數(shù)組 array (嵌套可以是任何層數(shù))轉(zhuǎn)換為只有一層的數(shù)組。 舉個(gè)例子,假設(shè)有個(gè)...

    tuantuan 評(píng)論0 收藏0
  • JavaScript專(zhuān)題如何求數(shù)組的最大值和最小值

    摘要:專(zhuān)題系列第八篇,講解多種方式求數(shù)組的最大值和最小值前言取出數(shù)組中的最大值或者最小值是開(kāi)發(fā)中常見(jiàn)的需求,但你能想出幾種方法來(lái)實(shí)現(xiàn)這個(gè)需求呢提供了函數(shù)返回一組數(shù)中的最大值,用法是值得注意的是如果有任一參數(shù)不能被轉(zhuǎn)換為數(shù)值,則結(jié)果為。 JavaScritpt 專(zhuān)題系列第八篇,講解多種方式求數(shù)組的最大值和最小值 前言 取出數(shù)組中的最大值或者最小值是開(kāi)發(fā)中常見(jiàn)的需求,但你能想出幾種方法來(lái)實(shí)現(xiàn)這個(gè)...

    zhaochunqi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<