1. 程式人生 > 實用技巧 >JavaScript的array方法

JavaScript的array方法

JavaScript高階函式

1.map/reduce

map()

map()是array的一個方法

作用: 對array中每一個元素呼叫自定義函式

'use strict';
function pow(x){
return x*x;
}
var arr=[1,2,3,4,5]
var newarray=arr.map(pow)

map的回撥函式有三個引數:

callback(currentValue, index, array)通常只要第一個引數

PS: map()傳入的引數是pow,即函式物件本身

通常map呼叫的自定義方法只包含一個引數

reduce()

reduce()也是array的一個方法

作用: 從陣列的前兩個元素開始,作為函式引數,傳入函式得到結果,

結果再和下一個陣列元素再一次呼叫函式,直到陣列盡頭

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)

PS: 通常reduce()呼叫的自定義方法只包含兩個個引數

2.filter(篩選)

作用:把Array的某些元素過濾掉,然後返回剩下的元素.

map()類似,Arrayfilter()也接收一個函式。和map()不同的是,filter()把傳入的函式依次作用於每個元素,然後根據返回值是true還是false決定保留還是丟棄該元素。

//去掉空字串

var arr = ['A', '', 'B', null, undefined, 'C', '  '];
var r = arr.filter(function (s) {
    return s && s.trim(); // 注意:IE9以下的版本沒有trim()方法
});
r; // ['A', 'B', 'C']

回撥函式

通常我們僅使用第一個引數,表示Array的某個元素。回撥函式還可以接收另外兩個引數,表示元素的位置和陣列本身:

var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); // 依次列印'A', 'B', 'C'
    console.log(index); // 依次列印0, 1, 2
    console.log(self); // self就是變數arr
    return true;
});

篩選素數:

function get_primes(arr){
if(elem===1){
return false;
}
for(var i=2;i<=elem/2;i++){
if(elem%i==0)
{
return false;
}
}
return true;
});
return x;
}

PS: 關鍵在於正確實現一個“篩選”函式

3.sort(排序)

預設排序會把所有元素轉成String在排序,根據一個元素的ASCII值進行排序(非遞減)(TimSort演算法)

兩兩比較,當回撥函式返回值大於0時,交換元素值

自定義數字排序

'use strict' 
var arr=[10,20,1,2];

arr.sort(function(x,y){
	if (x < y) {
        return -1;
    }
    if (x > y) {
        return 1;
    }
    return 0;
});
console.log(arr); // [1, 2, 10, 20]

數字倒序排列

var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return 1;
    }
    if (x > y) {
        return -1;
    }
    return 0;
}); // [20, 10, 2, 1]

4.其他的Array方法

every()和some()

作用: 可以判斷陣列的所有元素是否滿足測試條件(通過函式提供)

  • every()是全部滿足的時候返回true,一個不滿足返回false,並終止檢測

  • some()是全部不滿足的時候返回false,有一個滿足就返回true

find()

作用: 查詢第一個符合條件的元素

查詢符合條件的第一個元素,如果找到了就返回這個元素,否則,返回undefined

findindex()

作用: 查詢第一個符合條件的元素的索引

查詢符合條件的第一個元素,找到這個元素就返回他的索引,如果沒有找到就返回-1

forEach()

作用: 常用於遍歷陣列

(和map類似)把陣列每個元素依次傳入函式,但不會返回新的陣列.

函式作為返回值

函式裡再定義一個函式,返回值為裡面定義的函式

呼叫函式作為返回值的函式式,每次呼叫都會返回一個新的函式,即使傳入相同引數

function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    }
    return sum;
}
//此時返回的是求和函式
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); // 15 此時呼叫,才進行計算

在函式lazy_sum中又定義了函式sum,並且,內部函式sum可以引用外部函式lazy_sum的引數和區域性變數,當lazy_sum返回函式sum時,相關引數和變數都儲存在返回的函式中,這種稱為“閉包(Closure)”的程式結構擁有極大的威力.

閉包(懵逼了)(吐彩虹)

有權訪問另一個函式作用域內變數的函式都是閉包。

函式裡面的函式會隨著外部定義函式而改變

PS: 因為返回值就是一個函式,呼叫的時候要加小括號

返回閉包時牢記的一點就是:返回函式不要引用任何迴圈變數,或者後續會發生變化的變數。

如果一定要引用迴圈變數怎麼辦?方法是再建立一個函式,用該函式的引數繫結迴圈變數當前的值,無論該迴圈變數後續如何更改,已繫結到函式引數的值不變:

箭頭函式(=>)(強噠)

(引數...)=>{函式體}等價於function(引數...){函式體}

當返回的是一個物件時函式體大括號外邊加小括號

x=>({foo:x})

this

箭頭函式內部的this是詞法作用域,由上下文確定

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj物件
        return fn();
    }
};
obj.getAge(); // 25

箭頭函式完全修復了this指向,this總是指向詞法作用域,也就是外層呼叫 obj

generator(生成器)

ES6引入借鑑Python同名函式

寫法和函式類似,只是在function後加*,通過yield多次返回值,也可通過return返回值

函式在執行過程中,如果沒有遇到return語句(函式末尾如果沒有return,就是隱含的return undefined;),控制權無法交回被呼叫的程式碼。

function* (x){

yield x

}

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}

直接呼叫一個generator和呼叫函式不一樣,fib(5)僅僅是建立了一個generator物件,還沒有去執行它。

呼叫generator物件有兩個方法,

  1. 一是不斷地呼叫generator物件的next()方法:next()方法會執行generator的程式碼,然後,每次遇到yield x;就返回一個物件{value: x, done: true/false},然後“暫停”。返回的value就是yield的返回值,done表示這個generator是否已經執行結束了。如果donetrue,則value就是return的返回值。當執行到donetrue時,這個generator物件就已經全部執行完畢,不要再繼續呼叫next()`了。

    var f = fib(5);
    f.next(); // {value: 0, done: false}
    f.next(); // {value: 1, done: false}
    f.next(); // {value: 1, done: false}
    f.next(); // {value: 2, done: false}
    f.next(); // {value: 3, done: false}
    f.next(); // {value: undefined, done: true}
    
  2. 第二個方法是直接用for ... of迴圈迭代generator物件,這種方式不需要我們自己判斷done

for (var x of fib(10)) {
    console.log(x); // 依次輸出0, 1, 1, 2, 3, ...
}

generator還有另一個巨大的好處,就是把非同步回撥程式碼變成“同步”程式碼。這個好處要等到後面學了AJAX以後才能體會到。

try {
    r1 = yield ajax('http://url-1', data1);
    r2 = yield ajax('http://url-2', data2);
    r3 = yield ajax('http://url-3', data3);
    success(r3);
}
catch (err) {
    handle(err);
}

看上去是同步的程式碼,實際執行是非同步的。