《JavaScript 闯关记》之数组

数组是值的有序鸠合。每一个值叫做一个元素,而每一个元素在数组中有一个位置,以数字示意,称为索引。

JavaScript 数组是无范例的,数组元素可所以恣意范例,而且同一个数组中的差别元素也可以有差别的范例。数组的元素以致也多是对象或其他数组。

JavaScript数组是动态的,依据须要它们会增进或缩减,而且在建立数组时没必要声明一个牢固的大小或许在数组大小变化时没必要重新分配空间。

JavaScript 数组多是希罕的,数组元素的索引不一定要一连的,它们之间可以有空缺。每一个JavaScript数组都有一个length属性。针对非希罕数组,该属性就是数组元素的个数。针对希罕数组,length比统统元素的索引要大。

JavaScript 数组是 JavaScript 对象的特别情势,数组索引实际上和碰巧是整数的属性名差不多。一般,数组的完成是经由优化的,用数字索引来接见数组元素一般来讲比接见通例的对象属性要快许多。

数组继续自 Array.prototype 中的属性,它定义了一套雄厚的数组操纵要领。

建立数组

可以运用数组字面量和 new 关键字来建立数组。

运用数组字面量建立数组(引荐)

var empty = [];                 // 没有元素的数组
var primes = [2, 3, 5, 7, 11];  // 有5个数值的数组
var misc = [1.1, true, "a"];    // 3个差别范例的元素

// 数组直接量中的值不一定假如常量,可所以恣意的表达式
var base = 1024;
var table = [base, base+1, base+2, base+3];

// 也可以包含对象直接量或其他数组直接量
var b = [[1, {x:1, y:2}], [2, {x:3, y:4}]];

注重,不要疏忽数组字面量的末了一个元素,仅以逗号末尾。下面几个案例,在差别的浏览器下,可以会被识别成2个元素,也有可以识别成3个元素,而形成递次bug。比方:

var nums = [,,,];               // 不好的写法
var names = ["stone",,];        // 不好的写法
var colors = ["red","green",];  // 不好的写法

运用 new 关键字建立数组

运用 new 关键字挪用组织函数 Array() 是建立数组的另一种要领,可以用三种体式格局挪用组织函数。比方:

// 挪用时没有参数
var a = new Array();

// 挪用时有一个数值参数,它指定长度
var a = new Array(10); 

// 显式指定多个数组元素或许数组的一个非数值元素
var a = new Array(5, 4, 3, 2, 1, "testing");

数组元素的读和写

运用 [] 操纵符来接见数组中的一个元素。数组的援用位于方括号的左侧。方括号中是一个返回非负整数值的恣意表达式。运用该语法既可以读又可以写数组的一个元素。比方:

var a = ["world"];     // 从一个元素的数组最先
var value = a[0];      // 读第0个元素
a[1] = 3.14;           // 写第1个元素
var i = 2; 
a[i] = 3;              // 写第2个元素
a[i + 1] = "hello";    // 写第3个元素
a[a[i]] = a[0];        // 读第0个和第2个元素,写第3个元素

请记着,数组是对象的特别情势,可以为其建立恣意名字的属性。但假如运用的属性是数组的索引,数组的特别行动就是将依据须要更新它们的length属性值。

注重,可以运用负数或非整数来索引数组。这类状况下,数值转换为字符串,字符串作为属性名来用。既然名字不黑白负整数,它就只能当作通例的对象属性,而非数组的索引。一样,假如恰巧运用了黑白负整数的字符串,它就当作数组索引,而非对象属性。当运用的一个浮点数和一个整数相称时状况也是一样的。比方:

a[-1.23] = true;  // 这将建立一个名为"-1.23"的属性
a["1000"] = 0;    // 这是数组的第1001个元素
a[1.000]          // 和 a[1] 相称

事实上数组索引仅仅是对象属性名的一种特别范例,这意味着 JavaScript 数组没有「越界」毛病的观点。当试图查询任何对象中不存在的属性时,不会报错,只会获得 undefined 值。

希罕数组

希罕数组就是包含从0最先的不一连索引的数组。一般,数组的 length 属性值代表数组中元素的个数。假如数组是希罕的,length 属性值大于元素的个数。可以用 Array() 组织函数或简朴地指定数组的索引值大于当前的数组长度来建立希罕数组。

a = new Array(5);   // 数组没有元素,然则 a.length = 5
a = [];             // 建立一个空数组,a.length = 0
a[1000] = 0;        // 增添一个元素,a.length 被自动更新为1001

充足希罕的数组一般在完成上比浓密的数组更慢、内存应用率更高,在如许的数组中查找元素的时候与通例对象属性的查找时候一样长。

须要注重的是,当省略数组直接量中的值时(运用一连的逗号,比方 [1,,3] ),这时候所获得的数组也是希罕数组,省略掉的值是不存在的:

var a1 = [,'1','2'];    // 此数组长度是3 
var a2 = [undefined];   // 此数组包含一个值为 undefined 的元素 
console.log(0 in a1);   // false,a1 在索引0处没有元素
console.log(0 in a2);   // true,a2 在索引0处有一个值为 undefined 的元素 

相识希罕数组是相识 JavaScript 数组的实在实质的一部分。尽管云云,实际上你所遇到的绝大多数 JavaScript 数组不是希罕数组。而且,假如你确切遇到了希罕数组,你的代码极可以像看待非希罕数组一样来看待它们,只不过它们包含一些 undefined 值。

数组长度

每一个数组有一个 length 属性,就是这个属性使其区分于通例的 JavaScript 对象。针对浓密(也就黑白希罕)数组,length 属性值代表数组中元素的个数。其值比数组中最大的索引大1。比方:

[].length             // 0,数组没有元素
['a','b','c'].length  // 3,最大的索引为2,length 为3

当数组是希罕的时,length 属性值大于元素的个数。而且关于此我们可以说的统统也就是数组长度保证大于它每一个元素的索引值。或许,换一种说法,在数组中(不管希罕与否)一定找不到一个元素的索引值大于或即是它的长度。为了保持此划定规矩稳定化,数组有两个特别的行动。

  • 第一个犹如上面的形貌:假如为一个数组元素赋值,它的索引 i 大于或即是现有数组的长度时,length 属性的值将设置为 i+1

  • 第二个特别的行动就是设置 length 属性为一个小于当前长度的非负整数 n 时,当前数组中那些索引值大于或即是 n 的元素将从中删除。比方:

a = [1,2,3,4,5];     // 从5个元素的数组最先
a.length = 3;        // 如今 a 为[1,2,3]
a.length = 0;        // 删除统统的元素。a 为[ ]
a.length = 5;        // 长度为5,然则没有元素,就像 new Array(5)

还可以将数组的 length 属性值设置为大于其当前的长度。实际上这不会向数组中增添新的元素,它只是在数组尾部建立一个空的地区。

在 ECMAScript 5中,可以用 Object.defineProperty() 让数组的 length 属性变成只读的。比方:

a = [1,2,3];                                            // 从3个元素的数组最先
Object.defineProperty(a, "length", {writable: false});  // 让 length 属性只读
a.length = 0;                                           // a 不会转变

数组元素的增添和删除

我们已见过增添数组元素最简朴的要领,为新索引赋值。比方:

a = []           // 最先是一个空数组
a[0] = "zero";   // 然后向个中增添元素
a[1] = "one";

也可以运用 push() 要领在数组末尾增添一个或多个元素。比方:

a = [];                 // 最先是一个空数组
a.push("zero");         // 在末尾增添一个元素。a = ["zero"]
a.push("one", "two");   // 再增添两个元素。a = ["zero", "one", "two"]

可以像删除对象属性一样运用 delete 运算符来删除数组元素。比方:

a = [1,2,3]; 
delete a[1];   // a在索引1的位置不再有元素
1 in a         // => false: 数组索引1并未在数组中定义
a.length       // => 3: delete操纵并不影响数组长度

注重,对一个数组元素运用 delete 不会修正数组的 length 属性,也不会将元素从高索引处移下来添补已删除属性留下的空缺。假如从数组中删除一个元素,它就变成希罕数组。

数组遍历

运用 for 轮回是遍历数组元素最常见的要领。比方:

var keys = Object.keys(o);   // 获得 o 对象属性名构成的数组
var values = []              // 在数组中存储婚配属性的值
for(var i = 0; i < keys.length; i++) {  // 关于数组中每一个索引
    var key = keys[i];                  // 获得索引处的键值
    values[i] = o[key];                 // 在 values 数组中保留属性值
}

在嵌套轮回或其他机能异常重要的高低文中,可以看到这类基本的数组遍历须要优化,数组的长度应当只查询一次而非每次轮回都要查询。比方:

for(var i = 0, len = keys.length; i < len; i++) {
   // 轮回体依然稳定
}

这些例子假定数组是浓密的,而且统统的元素都是正当数据。不然,运用数组元素之前应当先检测它们。比方:

for(var i = 0; i < a.length; i++) {
    if (!a[i]) continue;    // 跳过 null、undefined 和不存在的元素
    if (!(i in a)) continue ;   // 跳过不存在的元素
    if (a[i] === undefined) continue;   // 跳过 undefined 和不存在的元素
    // 轮回体
}

还可以运用 for-in 轮回处置惩罚希罕数组。轮回每次将一个可罗列的属性名(包含数组索引)赋值给轮回变量,不存在的索引将不会遍历到。比方:

for(var index in sparseArray) {
   var value = sparseArray[index];
   // 此处可以运用索引和值做一些事变
}

但因为 for-in 轮回可以罗列继续的属性名,如增添到 Array.prototype 中的要领。基于这个缘由,在数组上不应当运用 for-in 轮回,除非运用分外的检测要领来过滤不想要的属性。比方:

for(var i in a) {
    // 跳过继续的属性
    if (!a.hasOwnProperty(i)) continue;

    // 跳过不黑白负整数的 i
    if (String(Math.floor(Math.abs(Number(i)))) !== i) continue;
}

JavaScript 范例许可 for-in 轮回以差别的递次遍历对象的属性。一般数组元素的遍历完成是升序的,但不能保证一定是如许的。假如数组同时具有对象属性和数组元素,返回的属性名许多是依据建立的递次而非数值的大小递次。怎样处置惩罚这个题目的完成,各个浏览器都不雷同,假如算法依赖于遍历的递次,那末最好不要运用 for-in 而用通例的 for 轮回。

ECMAScript 5定义了一些遍历数组元素的新要领,依据索引的递次按个通报给定义的一个函数。这些要领中最常常使用的就是 forEach() 要领。比方:

var data = [1,2,3,4,5];     // 这是须要遍历的数组
var sumOfSquares = 0;       // 要获得数据的平方和
data.forEach(function(x) {  // 把每一个元素通报给此函数
    sumOfSquares += x*x;    // 平方相加
});
console.log(sumOfSquares);  // 55,1 + 4 + 9 + 16 + 25

数组检测

给定一个未知的对象,剖断它是不是为数组一般异常有效。在 ECMAScript 5中,可以运用 Array.isArray() 函数来做这件事变。比方:

Array.isArray([])   // true
Array.isArray({})   // false

然则,在 ECMAScript 5之前,要区分数组和非数组对象很难题。typeof 运算符对数组返回 "object"(而且关于除了函数之外的统统对象都是云云)。instanceof 操纵符也只能用于简朴的情况。比方:

[] instanceof Array     // true
({}) instanceof Array   // false

运用 instanceof 的题目是在 Web 浏览器中有可以有多个窗体存在。每一个窗体都有自身的 JavaScript 环境,有自身的全局对象。而且,每一个全局对象有自身的一组组织函数。因而一个窗体中的对象将不多是别的窗体中的组织函数的实例。窗体之间的殽杂不常发作,但这个题目足已证实 instanceof 操纵符不能视为一个牢靠的数组检测要领。

解决计划是搜检对象的类属性,对数组而言该属性的值老是 "Array",因而在 ECMAScript 3中 isArray() 函数的代码可以如许誊写。比方:

var isArray = Array.isArray || function(o) {
    return typeof o === "object" && Object.prototype.toString.call(o) === "[object Array]";
};

数组要领

ECMAScript 3和 ECMAScript 5在 Array.prototype 中定义了一些很有效的操纵数组的要领。

转换要领

统统对象都具有 toLocaleString()toString()valueOf() 要领。个中,挪用数组的 toString()valueOf() 要领会返回雷同的值,即由数组中每一个值的字符串情势拼接而成的一个以逗号分开的字符串。实际上,为了建立这个字符串会挪用数组每一项的 toString() 要领。比方:

var colors = ["red", "blue", "green"];  // 建立一个包含3个字符串的数组
alert(colors.toString()); // red,blue,green
alert(colors.valueOf());  // red,blue,green
alert(colors);            // red,blue,green

在这里,我们起首显式地挪用了 toString()valueOf() 要领,以便返回数组的字符串示意,每一个值的字符串示意拼接成了一个字符串,中心以逗号分开。末了一行代码直接将数组通报给了 alert()。因为 alert()要吸收字符串参数,所以它会在背景挪用 toString() 要领,由此会获得与直接挪用 toString() 要领雷同的效果。

别的,toLocaleString() 要领常常也会返回与 toString()valueOf() 要领雷同的值,但也不老是云云。当挪用数组的 toLocaleString() 要领时,它也会建立一个数组值的以逗号分开的字符串。而与前两个要领唯一的差别之处在于,这一次为了获得每一项的值,挪用的是每一项的 toLocaleString() 要领,而不是 toString() 要领。比方:

var person1 = {
    toLocaleString : function () {
        return "Nikolaos";
    },
    toString : function() {
        return "Nicholas";
    }
};

var person2 = {
    toLocaleString : function () {
        return "Grigorios";
    },
    toString : function() {
        return "Greg";
    }
};

var people = [person1, person2];
alert(people);                           // Nicholas,Greg
alert(people.toString());                // Nicholas,Greg
alert(people.toLocaleString());          // Nikolaos,Grigorios

数组继续的 toLocaleString()toString()valueOf()要领,在默许状况下都邑以逗号分开的字符串的情势返回数组项。而假如运用 join() 要领,则可以运用差别的分开符来构建这个字符串。join() 要领只吸收一个参数,即用作分开符的字符串,然后返回包含统统数组项的字符串。比方:

var colors = ["red", "green", "blue"];
console.log(colors.join(","));    // red,green,blue
console.log(colors.join("||"));   // red||green||blue

假如数组中的某一项的值是 null 或许 undefined,那末该值在 join()toLocaleString()toString()valueOf() 要领返回的效果中以空字符串示意。

栈要领

栈是一种 LIFO(Last-In-First-Out,后进先出)的数据结构,也就是最新增添的项最早被移除。push() 要领可以吸收恣意数目的参数,把它们逐一增添到数组末尾,并返回修正后数组的长度。而 pop() 要领则从数组末尾移除末了一项,削减数组的 length 值,然后返回移除的项。连系 push()pop() 要领,就可以像栈一样运用数组。比方:

var colors = [];                            // 建立一个数组
var count = colors.push("red", "green");    // 推入两项
console.log(count);                         // 2,数组的长度

count = colors.push("black");               // 推入另一项
console.log(count);                         // 3,数组的长度

var item = colors.pop();                    // 获得末了一项
console.log(item);                          // "black"
console.log(colors.length);                 // 2,数组的长度

行列要领

行列是一种 FIFO(First-In-First-Out,先进先出)的数据结构,行列在列表的末尾增添项,从列表的前端移除项。shift() 要领则从数组前端移除第一项,削减数组的 length 值,然后返回移除的项。连系 push()shift() 要领,就可以像行列一样运用数组。比方:

var colors = [];                            // 建立一个数组
var count = colors.push("red", "green");    // 推入两项
console.log(count);                         // 2,数组的长度

count = colors.push("black");               // 推入另一项
console.log(count);                         // 3,数组的长度

var item = colors.shift();                  // 获得第一项
console.log(item);                          // "red"
console.log(colors.length);                 // 2,数组的长度

JavaScipt 还为数组供应了一个 unshift() 要领。望文生义,unshift()shift() 的用处相反,它能在数组前端增添恣意个项并返回新数组的长度。因而,同时运用 unshift()pop() 要领,可以从相反的方一直模仿行列,即在数组的前端增添项,从数组末尾移除项。

重排序要领

数组中有两个重排序的要领:reverse()sort()reverse() 要领可以反转数组元素的递次。比方:

var values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values);  // 5,4,3,2,1

sort() 要领可以按升序分列数组元素(即最小的值位于最前面,最大的值排在末了面)。sort() 要领在排序的历程中会挪用每一个数组元素的 toString(),然后比较获得的字符串,以肯定怎样排序。纵然数组中的每一项都是数值,sort() 要领比较的也是字符串,比方:

var values = [0, 1, 5, 10, 15];
values.sort();
console.log(values);     // 0,1,10,15,5

这类排序体式格局在许多状况下都不是最好计划,因而 sort() 要领可以吸收一个比较函数作为参数,以便我们指定哪一个值位于哪一个值的前面,以下就是一个简朴的比较函数。比方:

function compare(value1, value2) {
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
        return 1;
    } else {
        return 0;
    }
}

这个比较函数吸收两个参数,假如第一个参数应当位于第二个之前则返回一个负数,假如两个参数相称则返回0,假如第一个参数应当位于第二个以后则返回一个正数。它可以适用于大多数状况,只需将其作为参数通报给 sort() 要领即可。比方:

var values = [10, 5, 1, 0, 15];
values.sort(compare);
console.log(values);   // 0,1,5,10,15

关于数值范例或许其 valueOf() 要领会返回数值范例的对象范例,可以运用一个更简朴的比较函数。这个函数只需用第二个值减第一个值即可。比方:

function compare(value1, value2){
    return value2 - value1;
}

因为比较函数经由过程返回一个小于零、即是零或大于零的值来影响排序效果,因而减法操纵就可以适当地处置惩罚统统这些状况。

操纵要领

JavaScript 为操纵已包含在数组中的元素供应了许多要领。个中,concat() 要领可以基于当前数组中的统统项建立一个新数组。具体来讲,这个要领会先建立当前数组一个副本,然后将吸收到的参数增添到这个副本的末尾,末了返回新构建的数组。在没有给 concat() 要领通报参数的状况下,它只是复制当前数组并返回副本。假如通报给 concat() 要领的是一或多个数组,则该要领会将这些数组中的每一项都增添到效果数组中。假如通报的值不是数组,这些值就会被简朴地增添到效果数组的末尾。比方:

var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]);

console.log(colors);     // red,green,blue
console.log(colors2);    // red,green,blue,yellow,black,brown

下一个要领是 slice(),它可以基于当前数组中的一或多个项建立一个新数组。slice() 要领可以接收一或两个参数,即要返回项的肇端和完毕位置。在只要一个参数的状况下,slice() 要领返回从该参数指定位置最先到当前数组末尾的统统项。假如有两个参数,该要领返回肇端和完毕位置之间的项,但不包含完毕位置的项。注重,slice() 要领不会影响原始数组。比方:

var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(1,4);

console.log(colors2);   // green,blue,yellow,purple
console.log(colors3);   // green,blue,yellow

假如 slice() 要领的参数中有一个负数,则用数组长度加上该数来肯定响应的位置。比方,在一个包含5项的数组上挪用 slice(-2,-1) 与挪用 slice(3,4) 获得的效果雷同。假如完毕位置小于肇端位置,则返回空数组。

下一个要领是 splice(),它的重要用处是向数组的中部插进去元素,重要有以下3种运用体式格局。

  • 删除:可以删除恣意数目的项,只需指定2个参数:肇端位置和要删除元素的数目。比方,splice(0,2) 会删除数组中的前两项。

  • 插进去:可以向指定位置插进去恣意数目的项,只需供应3个参数:肇端位置、0(要删除元素的数目)和要插进去的元素。假如要插进去多个元素,可以再传入第四、第五,以致恣意多个元素。比方,splice(2,0,"red","green") 会从当前数组的位置2最先插进去字符串 "red""green"

  • 替代:可以向指定位置插进去恣意数目的项,且同时删除恣意数目的项,只需指定3个参数:肇端位置、要删除元素的数目和要插进去的元素。插进去的项数没必要与删除的项数相称。比方,splice (2,1,"red","green")会删除当前数组位置2的项,然后再从位置2最先插进去字符串 "red""green"

splice() 要领一直都邑返回一个数组,该数组中包含从原始数组中删除的项(假如没有删除任何项,则返回一个空数组)。下面的代码展现了上述3种运用 splice() 要领的体式格局。比方:

var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1);       // 删除第一项
console.log(colors);                    // green,blue
console.log(removed);                   // red,返回的数组中只包含一项

removed = colors.splice(1, 0, "yellow", "orange");  // 从位置1最先插进去两项
console.log(colors);                    // green,yellow,orange,blue
console.log(removed);                   // 返回的是一个空数组

removed = colors.splice(1, 1, "red", "purple");     // 插进去两项,删除一项
console.log(colors);                    // green,red,purple,orange,blue
console.log(removed);                   // yellow,返回的数组中只包含一项

位置要领

ECMAScript 5为数组实例增添了两个位置要领:indexOf()lastIndexOf()。这两个要领都吸收两个参数:要查找的项和(可选的)示意查找出发点位置的索引。个中,indexOf() 要领从数组的开首(位置0)最先向后查找,lastIndexOf() 要领则从数组的末尾最先向前查找。

这两个要领都返回要查找的项在数组中的位置,或许在没找到的状况下返回 -1。在比较第一个参数与数组中的每一项时,会运用全等操纵符;也就是说,请求查找的项必需严厉相称(就像运用 === 一样)。比方:

var numbers = [1,2,3,4,5,4,3,2,1];
console.log(numbers.indexOf(4));          // 3
console.log(numbers.lastIndexOf(4));      // 5
console.log(numbers.indexOf(4, 4));       // 5
console.log(numbers.lastIndexOf(4, 4));   // 3

var person = { name: "Nicholas" };
var people = [{ name: "Nicholas" }];
var morePeople = [person];
console.log(people.indexOf(person));      // -1
console.log(morePeople.indexOf(person));  // 0

迭代要领

ECMAScript 5为数组定义了5个迭代要领。每一个要领都吸收两个参数:要在每一项上运转的函数和(可选的)运转该函数的作用域对象。传入这些要领中的函数会吸收三个参数:数组项的值、该项在数组中的位置和数组对象自身。依据运用的要领差别,这个函数实行后的返回值可以会也可以不会影响接见的返回值。以下是这5个迭代要领的作用。

  • every(),对数组中的每一项运转给定函数,假如该函数对每一项都返回 true ,则返回 true

  • filter(),对数组中的每一项运转给定函数,返回该函数会返回 true 的项构成的数组。

  • forEach(),对数组中的每一项运转给定函数。这个要领没有返回值。

  • map(),对数组中的每一项运转给定函数,返回每次函数挪用的效果构成的数组。

  • some(),对数组中的每一项运转给定函数,假如该函数对任一项返回 true ,则返回 true

以上要领都不会修正数组中的包含的值。在这些要领中,最相似的是 every()some(),它们都用于查询数组中的项是不是满足某个前提。对 every() 来讲,传入的函数必需对每一项都返回 true,这个要领才返回 true;不然,它就返回 false。而 some()要领则是只需传入的函数对数组中的某一项返回 true,就会返回 true。比方:

var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array){
    return (item > 2); 
});
console.log(everyResult);   // false

var someResult = numbers.some(function(item, index, array){
    return (item > 2);
});
console.log(someResult);    // true

下面再看一看 filter() 函数,它应用指定的函数肯定是不是在返回的数组中包含的某一项。比方:

var numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item, index, array){
    return (item > 2);
});
console.log(filterResult);  // [3,4,5,4,3]

map() 也返回一个数组,而这个数组的每一项都是在原始数组中的对应项上运转传入函数的效果。比方,可以给数组中的每一项乘以2,然后返回这些乘积构成的数组。比方:

var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item, index, array){
    return item * 2;
});
console.log(mapResult);     // [2,4,6,8,10,8,6,4,2]

末了一个要领是 forEach(),它只是对数组中的每一项运转传入的函数。这个要领没有返回值,实质上与运用 for 轮回迭代数组一样。比方:

var numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){
    //实行某些操纵 
});

 减少要领

ECMAScript 5还新增了两个减少数组的要领:reduce()reduceRight()。这两个要领都邑迭代数组的统统项,然后构建一个终究返回的值。个中,reduce() 要领从数组的第一项最先,逐一遍历到末了。而 reduceRight() 则从数组的末了一项最先,向前遍历到第一项。

这两个要领都吸收两个参数:一个在每一项上挪用的函数和(可选的)作为减少基本的初始值。传给 reduce() reduceRight() 的函数吸收4个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都邑作为第一个参数自动传给下一项。第一次迭代发作在数组的第二项上,因而第一个参数是数组的第一项,第二个参数就是数组的第二项。

运用 reduce() 要领可以实行求数组中统统值之和的操纵。比方:

var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
    return prev + cur; 
});
console.log(sum); // 15

第一次实行回调函数,prev是1,cur是2。第二次,prev是3(1加2的效果),cur是3(数组的第三项)。这个历程会延续到把数组中的每一项都接见一遍,末了返回效果。

reduceRight() 的作用相似,只不过方向相反罢了。比方:

var values = [1,2,3,4,5];
var sum = values.reduceRight(function(prev, cur, index, array){
    return prev + cur;
});
console.log(sum); // 15

运用 reduce() 照样 reduceRight(),重要取决于要从哪头最先遍历数组。除此之外,它们完全雷同。

关卡

完成下面3个数组去重要领。

// 应战一,一维数组
var arr = [2,3,4,2,3,5,6,4,3,2];
var unique = function(arr){
    // 待完成要领体
}
console.log(unique(arr)); // [2,3,4,5,6]
// 应战二,二维数组
var arr = [2,3,4,[2,3,4,5],3,5,[2,3,4,2],4,3,6,2];
var unique = function(arr){
    // 待完成要领体
}
console.log(unique(arr)); // [2,3,4,5,6]
// 应战三,三维数组或 n 维数组
var arr = [2,3,4,[2,3,[2,3,4,2],5],3,5,[2,3,[2,3,4,2],2],4,3,6,2];
var unique = function(arr){
    // 待完成要领体
}
console.log(unique(arr)); // [2,3,4,5,6]

更多

关注微信民众号「劼哥舍」复兴「答案」,猎取关卡详解。
关注 https://github.com/stone0090/javascript-lessons,猎取最新动态。

    原文作者:劼哥stone
    原文地址: https://segmentfault.com/a/1190000007089725
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞