资讯专栏INFORMATION COLUMN

JavaScript之数组

coolpail / 1728人阅读

摘要:数组的特别之处在于,当使用小于的非负整数作为属性名时数组会自动维护其属性值。返回的数组包含第一个参数指定的位置和所有到但不含第二个参数指定的位置之间的所有数组元素。数组中只需有一项满足给定条件则返回。

概念

JavaScript数组是JavaScript对象的特殊形式。数组索引实际上和碰巧是整数的属性名差不多,使用方括号访问数组元素就像用方括号访问对象的属性一样。JavaScript将指定的数字索引值转换成字符串——索引值1变成 “1”——然后将其作为属性名来使用。

数组的特别之处在于,当使用小于2^32的非负整数作为属性名时数组会自动维护其length属性值。通常,数组的实现是经过优化的,用数字索引来访问数组元素一般来说比访问常规的对象属性要快很多。

注意,可以使用负数或非整数来索引数组。这种情况下,数值转换为字符串,字符串作为属性名来用。

数组相关函数 数组遍历方法

for循环

Array.prototype.forEach()
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。没有返回值

array.forEach(callback(currentValue[, index, array]]), [thisArg])

实例:遍历并输出所有数组元素

function logArrayElements(element, index, array) {
  console.log("a[" + index + "] = " + element);
}

// 注意索引 2 被跳过了,因为在数组的这个位置没有项
[2, 5, , 9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[1] = 5
// a[3] = 9

Array.prototype.map()
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值,不改变原数组

var newArray = arr.map(callback(currentValue[, index[, array]]) {
    // Return element for new_array 
}[, thisArg]);

实例1: 求数组中每个元素的平方根

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]

实例2:在一个String上使用 map 方法获取字符串中每个字符所对应的 ASCII 码组成的数组:

var map = Array.prototype.map
var a = map.call("Hello World", function(x) { 
  return x.charCodeAt(0); 
})
// a的值为[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

Array.prototype.filter()
filter()方法创建一个新数组,返回一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

var newArray = array.filter(callback(element[, index[, array]])[, thisArg])

实例:使用filter()创建具有非零id的元素的 json。

var arr = [
  { id: 15 },
  { id: -1 },
  { id: 0 },
  { id: 3 },
  { id: 12.2 },
  { },
  { id: null },
  { id: NaN },
  { id: "undefined" }
];

// 判断当前元素是否为数字
function isNumber(obj) {
  return obj !== undefined && typeof(obj) === "number" && !isNaN(obj);
}
//callback过滤函数
function filterByID(item) {
  if (isNumber(item.id) && item.id !== 0) {
    return true;
  } 
  invalidEntries++;
  return false; 
}

var arrByID = arr.filter(filterByID);
// Filtered Array:
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]

Array.prototype.reduce()
方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
语法:

var result = array.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

reduce为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:

accumulator 累计器
currentValue 当前值
currentIndex 当前索引
array 数组

回调函数第一次执行时,accumulator和currentValue的取值有几种情况:
如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;
如果没有提供initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
如果数组为空且没有提供initialValue,会抛出TypeError。
如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。

reduce()如何运行:
假如运行下段reduce()代码:

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array){
  return accumulator + currentValue;
});

Callback 被调用四次,每次调用的参数和返回值如下表:

您还可以提供Arrow Function来代替完整的函数。 下面的代码将产生与上面的代码中相同的输出:

[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr );

如果你打算提供一个初始值作为reduce()方法的第二个参数,以下是运行过程及结果:

[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { returnaccumulator+ currentValue; }, 10);    // =>20

实例1:计算数组中每个元素出现的次数

var names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
var names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
var countedNames = names.reduce(function (allNames, name) { 
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { "Alice": 2, "Bob": 1, "Tiff": 1, "Bruce": 1 }

实例2: 数组去重

let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
let result = arr.sort().reduce(function(init, currentValue){
    if(init.length === 0 || init[init.length - 1] !== currentValue){
    init.push(current);
  }
    return init;
}, []);    // => [1, 2, 3, 4, 5]
此处额外附上其他数组去重方法以作对比参考
// 方法一
var norepeat = funtion(arr){
    return arr.filter(function(val, index, array){
        return array.indexOf(val) === index;
    });
}
norepeat()

// 方法二
var set = new Set(arr);

实例3:按顺序运行Promise

 // Runs promises from array of functions that can return promises
 // in chained manner
 // @param {array} arr - promise arr
 // @return {Object} promise object
 
function runPromiseInSequence(arr, input) {
  return arr.reduce(
    (promiseChain, currentFunction) => promiseChain.then(currentFunction),
    Promise.resolve(input)
  );
}

// promise function 1
function p1(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 5);
  });
}

// promise function 2
function p2(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 2);
  });
}

// function 3  - will be wrapped in a resolved promise by .then()
function f3(a) {
 return a * 3;
}

// promise function 4
function p4(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 4);
  });
}

const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10)
  .then(console.log);   // 1200

Array.prototype.some()Array.prototype.every()

some()方法测试是否至少有一个元素可以通过被提供的函数方法。该方法返回一个Boolean类型的值。some()被调用时不会改变数组

array.some(callback(element[, index[, array]])[, thisArg])

实例:检测在数组中是否有元素大于 10。

function isBiggerThan10(element, index, array) {
  return element > 10;
}

[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

every()方法就像数学中的“针对所有”的量词,当且仅当针对数组中的所有元素调用判定函数都返回true,它才返回true。和some有相似之处。
实例:

a = [1,2,3,4,5];
a.every(function(x) { return X < 10; }) // => true:所有的值<10
a.every(function(x) { return x % 2 === 0; }) // => false: 不是所有的值都是偶数

js数组方法

Array.prototype.push()Array.prototype.pop()

push()方法向数组的末尾添加一个或更多元素,并返回新的长度。
pop()方法删除并返回数组的最后一个元素。

Array.prototype.unshift()Array.prototype.shift()

shift()方法删除并返回数组的第一个元素。
unshift()方法向数组的头部添加一个或更多元素,并返回新的长度。

注意,当使用多个参数调用unshift()时它的行为令人惊讶。参数是一次性插入的(就像splice()方法)而非一次一个地插入。这意味着最终的数组中插入的元素的顺序和它们在参数列表中的顺序-致。而假如元素是一次一个地插入,它们的顺序应该是反过来的。

Array.prototype.reverse()

方法将数组中元素的位置颠倒,并返回该数组。reverse()方法会改变原数组

Array.prototype.sort()
方法用原地算法对数组的元素进行排序,并返回数组。排序算法现在是稳定的。默认排序顺序是根据字符串Unicode码点。由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。sort()原数组上原地排序,会导致原数组改变

var a = [33, 4, 1111, 222];
a.sort();
//字母表顺序: 1111,222,33,4
a.sort(function(a, b) {    // =>a: [4, 33, 222, 1111]
return a - b;    // 根据顺序,返回负数、0、正数
});
a.sort( function(a, b) {return b - a});    // =>a: [1111, 222, 33, 4]

Array.prototype.concat(array2)
方法用于合并两个或多个数组。concat()方法不会更改原数组,而是返回一个新数组

Array.prototype.join()
方法将数组中所有元素都转化为字符串并连接在一起,返回最后生成的字符串。可以指定一个可选的字符串在生成的字符串中来分隔数组的各个元素。如果不指定分隔符,默认使用逗号。join()方法不该变原数组。
实例:字符串数组连接成字符串

var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
arr.join()
// output: George,John,Thomas

Array.prototype.slice(start, end)

slice()方法返回指定数组的一个片段或子数组。它的两个参数分别指定了片段的开始和结束的位置。返回的数组包含第一个参数指定的位置和所有到但不含第二个参数指定的位置之间的所有数组元素。如果只指定一个参数,返回的数组将包含从开始位置到数组结尾的所有元素。如参数中出现负数,它表示相对于数组中最后一个元素的位置。slice()方法不会改变原数组

// 语法:
str.slice(beginSlice[, endSlice])

beginSlice:
必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。

endSlice:
可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

//实例: 
var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
arr.slice(1) // output: John,Thomas

Array.prototype.splice() :方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组
语法:

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

实例:

// 示例1: 添加元素
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2,1,"Lemon","Kiwi");    // output: Banana,Orange,Lemon,Kiwi,Mango

// 示例2: 删除元素
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2,2);    // output: Banana,Orange

Array.prototype.indexOf()Array.prototype.lastIndexOf()
index0f()和lastIndex0f()搜索整个数组中具有给定值的元素,返回找到的第一个元素的索引或者如果没有找到就返回-1。index0f( )从头至尾搜索,而lastIndexOf()则反向搜索。

Array.prototype.reduce(reducer)
方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值

Array.prototype.map():对数组的每一项应用回调函数,返回新数组

Array.prototype.some():数组中只需有一项满足给定条件则返回true。

Array.prototype.every():数组的每一项都满足给定条件则返回true。

Array.prototype.filter():方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

Array.prototype.forEach():数组遍历,与for循环一样,没有返回值

数组类型

给定一个未知的对象,判定它是否为数组通常非常有用。在ECMAScript 5中,可以使用Array.isArray()函数来做这件事情:

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

在ECMAScript 3中isArray( )函数的代码可以这样书写:

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

我们已经看到,JavaScript数组的有- - 些特性是其他对象所没有的:

* 当有新的元素添加到列表中时,自动更新length属性。
* 设置length为一个较小值将截断数组。
* 从Array.prototype中继承一些有用的方法。
* 其类属性为“Array" 。

这些特性让JavaScript数组和常规的对象有明显的区别。但是它们不是定义数组的本质特性。一种常常完全合理的看法把拥有-个数值length属性和对应非负整数属性的对象看做一种类型的数组。

实例:为一个常规对象增加了一些属性使其变成类数组对象,然后遍历生成的伪数组的“元素”:

var a = {};    // 从一个常规空对象开始
// 添加一些属性,称为"类数组"
var i = 0;
while(i < 10) {
    a[i] = i * i;
    i++;
}
a.length = i;
// 现在,当做真正的数组遍历它
var total = 0;
for(var j = 0; j < a.length; j++)
total += a[j] ;    // => 287

JavaScript中的Arguments对象就是一个类数组对象。一些DOM方法(如document.getElementsByTagName()也返回类数组对象。
下面有一个函数可以用来检测类数组对象:

//判定o是否是一个类数组对象
//字符串和函数有length属性,但是它们
//可以用typeof检测将其排除。在客户端JavaScript中,DOM文 本节点
//也有length属性,需要用额外判断o. nodeType != 3将其排除
function isArrayLike(o) {
  return o && typeof o === "object" && isFinite(o.length) && o.length >= 0 && o.length === Math.floor(o.length) && o.length < 4294967296;             
}

参考:

* 《JavaScript权威指南》第六版
* [MDN Web 文档](https://developer.mozilla.org/zh-CN/)

推荐阅读:
【专题:JavaScript进阶之路】
JavaScript之“use strict”
JavaScript之new运算符
JavaScript之call()理解
JavaScript之对象属性

我是Cloudy,年轻的前端攻城狮一枚,爱专研,爱技术,爱分享。 
个人笔记,整理不易,感谢阅读、点赞和收藏。
文章有任何问题欢迎大家指出,也欢迎大家一起交流前端各种问题!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105431.html

相关文章

  • JavaScript专题系列文章

    摘要:专题系列共计篇,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究专题之函数组合专题系列第十六篇,讲解函数组合,并且使用柯里化和函数组合实现模式需求我们需要写一个函数,输入,返回。 JavaScript 专题之从零实现 jQuery 的 extend JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 ext...

    Maxiye 评论0 收藏0
  • JS专题数组去重

    摘要:将元素作为对象的键,默认键对应的值为如果对象中没有这个键,则将这个元素放入结果数组中去。 前言 数组去重在日常开发中的使用频率还是较高的,也是网上随便一抓一大把的话题,所以,我写这篇文章目的在于归纳和总结,既然很多人都在提的数组去重,自己到底了解多少呢。又或者是如果自己在开发中遇到了去重的需求,自己能想到更好的解决方案吗。 这次我们来理一理怎么做数组去重才能做得最合适,既要考虑兼容性,...

    only_do 评论0 收藏0
  • JavaScript 闯关记

    摘要:对象数组初始化表达式,闯关记之上文档对象模型是针对和文档的一个。闯关记之数组数组是值的有序集合。数组是动态的,根闯关记之语法的语法大量借鉴了及其他类语言如和的语法。 《JavaScript 闯关记》之 DOM(下) Element 类型 除了 Document 类型之外,Element 类型就要算是 Web 编程中最常用的类型了。Element 类型用于表现 XML 或 HTML 元素...

    mj 评论0 收藏0
  • JavaScript专题系列20篇正式完结!

    摘要:写在前面专题系列是我写的第二个系列,第一个系列是深入系列。专题系列自月日发布第一篇文章,到月日发布最后一篇,感谢各位朋友的收藏点赞,鼓励指正。 写在前面 JavaScript 专题系列是我写的第二个系列,第一个系列是 JavaScript 深入系列。 JavaScript 专题系列共计 20 篇,主要研究日常开发中一些功能点的实现,比如防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里...

    sixleaves 评论0 收藏0
  • JavaScript】核心语法数组

    摘要:数组一数组是什么是值得有序集合,每个元素都在数组里有唯一的位置,用数字表示,叫做索引数据用字符串表示,叫关联数组。 JS(JavaScript) 数组; 一.数组是什么; 是值得有序集合,每个元素都在数组里有唯一的位置,用数字表示,叫做索引数据;用字符串表示,叫关联数组。数组无类型;数组元素可以是类型,字符串,数字值,布尔值等数组动态的;向插入新元素,从数组中删除指定元素 二.一维数组...

    ghnor 评论0 收藏0

发表评论

0条评论

coolpail

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<