js梳理笔记(三) - 数组之数组方法

红宝书学习笔记

第一章: 字符串操作方法
第二章: 数组之创建数组
第三章: 数组之数组方法



前言

前一篇介绍了创建数组的各种方式,本篇主要介绍数组方法。


一、检测数组 Array.isArray()

判断一个对象是不是数组,我们通常使用的是 value instanceof Array 去判断,但是这有一个大前提是,只有一个网页(因而只有一个全局作用域)。如果网页里有多个框架,可能设计两个不同的全局执行上下文,因此就会有两个不同版本的 Array 构造函数。如果要把数组从一个框架传给另一个框架,则这个数组的构造函数将有别于在第二个框架内本地创建的数组。
为解决这个问题,ECMAScript提供了Array.isArray() 方法。
这个方法的目的就是确定一个值是否为数组,而不用管它是在哪个全局执行上下文中创建的。

二、迭代器方法 keys()、 values()、entries()

在ES6中,Array原型上暴露了3个用于检索数组内容的方法: keys()、 values()、entries()
keys() 返回数组索引的迭代器,
values() 返回数组元素的迭代器,
entries() 返回索引/值对的迭代器。

const a = ["foo","bar","baz","qux"];
// 因为这些方法都返回迭代器,所以可以将他们的内容通过Array.from() 直接转换为数组实例
const aKeys = Array.from(a.keys()); 
const aValues = Array.from(a.values());
const aEntries = Array.from(a.entries());

console.log(aKeys); // [0, 1, 2, 3]
console.log(aValues); // ["foo", "bar", "baz", "qux"]
console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]

三、复制 copyWithin() 和 填充 fill()

这两种方法都需要指定既有数组实例上的一个范围,包含 开始索引,不包含 结束索引。使用这个方法不回改变数组的大小。

fill()

使用fill() 方法可以向一个已有的数组中插入全部或部分相同的值。

  • 开始索引用于指定开始填充的位置。
  • 如果不提供结束索引,将一直填充到数组末尾
  • 负值索引从数组末尾开始计算,也可以换算为 arr.length + 负值
    例:
const zeroes = [0, 0, 0, 0, 0];
// 用5填充整个数组
zeroes.fill(5);
console.log(zeroes); // [5, 5, 5, 5, 5]
zeroes.fill(0); // 重置

// 用6 填充索引值大于等于3的元素
zeroes.fill(6, 3);
console.log(zeroes); // [0, 0, 0, 6, 6]
zeroes.fill(0); // 重置

// 用7 填充索引值大于等于1且小于3的元素
zeroes.fill(7, 1, 3);
console.log(zeroes); // [0, 7, 7, 0, 0]
zeroes.fill(0); // 重置

// 用8 填充索引值大于等于1且小于4的元素
// -4 + 5(zeroes.length) = 1
// -1 + 5(zeroes.length) = 4
zeroes.fill(8, -4, -1);
console.log(zeroes); // [0, 8, 8, 8, 0]
zeroes.fill(0); // 重置

fill() 静默忽略超出数组边界、零长度及方向相反的索引范围

zeroes.fill(1, -10, -6);  // 索引过低,忽略
zeroes.fill(1, 6, 10);  // 索引过高,忽略
zeroes.fill(1, 5, 3);  // 索引反向,忽略
zeroes.fill(2, 4, 10);  // 索引部分有效,执行有效部分,忽略无效部分 输出 : [0, 0, 0, 2, 2]

copyWithin()

copyWithin()按照指定范围浅复制数组中的部分内容,然后将他们插入到指定索引开始的位置。开始索引和结束索引与 fill() 计算方法相同。

let ints, 
	rest = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
rest();

// 从ints中复制索引 0 开始的内容,插入到索引 5 开始的位置。
ints.copyWithin(5);
console.log(ints); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
rest();

// 从ints 中复制索引 5 开始的内容,插入到索引 0 开始的位置
ints.copyWithin(0, 5);
console.log(ints); // [5,6,7,8,9,5,6,7,8,9]
rest();

// 从ints中复制索引 0 开始到索引 3 结束的内容,插入到索引4 开始的位置
ints.copyWithin(4, 0, 3);
console.log(ints); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
reset();

// 支持负值索引
ints.copyWithin(-4, -7, -3);
console.log(ints); //[0, 1, 2, 3, 4, 5, 3, 4, 5, 6]
reset();

copyWithin() 静默忽略超出数组边界、零长度及方向相反的索引范围

ints.copyWithin(1, -15, -12);  // 索引过低,忽略
ints.copyWithin(1, 12, 15);  // 索引过高,忽略
ints.copyWithin(1, 4, 2);  // 索引反向,忽略
ints.copyWithin(2, 7, 10);  // 索引部分有效,执行有效部分,忽略无效部分 输出 : [0, 1, 7, 8, 9, 5, 6, 7, 8, 9]

四、转换方法 toLocalString() 、toString() 、valueOf() 、join()

valueOf() 返回数组本身。
toString() 返回由数组中每个值的等效字符串拼接而成的以逗号分隔的字符串。

let colors = ["red", "pink", "blue", "green" ];
console.log(colors.toString()); // red,pink,blue,green // 显式调用
console.log(colors.valueOf()); // red,pink,blue,green  // 显式调用
alert(colors); // red,pink,blue,green  // 由于alert 期待返回字符串,在后台调用数组的toString() 方法

toLocalString() 也可能返回相同的结果。但是也不一定。因为调用它时,调用的时数组的 toLocalString() 方法,而不是 toString() 方法。
方法定义不同时,返回结果不一定相同。

join() 方法可以定义不同的分隔符

let colors = ["red", "pink", "blue", "green" ];
alert(colors.join(",")); // red,pink,blue,green
alert(colors.join("||")); // red||pink||blue||green
alert(colors.join()); // red,pink,blue,green

五、栈方法 队列方法 push() pop() shift() unshift()

栈方法 push() + pop()

ECMAScript给数组提供几个方法,让它看起来像是另外一种数据结构,数组对象可以像栈一样,也就是一种限制插入和删除项的数据结构。
栈是一种后进先出的结构,也就是最近添加的项先被删除。
push() 方法接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。
pop() 方法用于删除数组的最后一项,同时减少数组的length值,返回被删除的项。

let colors = new Array(); // 创建一个数组
let count = colors.push("red", "green"); // 推入两项
alert(count); // 2

count = colors.push("blue"); // 再推入一项
alert(count); // 3

let item = colors.pop(); // 取得最后一项
alert(item); // blue
alert(colors.length); // 2

队列方法 push() + shift()

队列以先进先出的形式限制访问。 队列在列表末尾添加数据,但从列表开头获取数据。
shift() 方法删除数组的第一项并返回它,同时数组长度减 1 。

let colors = new Array(); // 创建一个数组
let count = colors.push("red", "green"); // 推入两项
alert(count); // 2

count = colors.push("blue"); // 再推入一项
alert(count); // 3

let item = colors.shift(); // 取得第一项
alert(item); // red
alert(colors.length); // 2

unshift() 方法接收任意数量的参数,并将它们添加到数组头部,返回数组的最新长度。
使用unshift()pop() ,可以在相反方向上模拟队列。

六、排序方法 reverse() 、sort()

reverse()方法用于将数组元素反向排列

let values = [1, 2, 3, 4, 5];
alert(values.reverse()); // 5,4,3,2,1

sort() 用于重新排序,默认情况下按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。
但是,sort() 会在每一项上调用String() 转型函数,然后比较字符串来决定顺序,即使元素都是数值,也会转换为字符串进行比较排序,因此会出现以下情况:

let values = [1, 2, 10, 15];
values.sort();
alert(values); // 1,10,15,2

因为字符串“10”“15”会排在字符串“2”前面。很明显,这在很多情况下都不是最合适的。因此,sort() 方法可以接收一个比较函数,用于判断哪个值应该排在前面。

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

  let values = [1, 10, 2, 15];
  values.sort(compare);
  alert(values); // 1,2,10,15

如果希望产生降序效果,只需要把返回值交换一下即可

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

  let values = [1, 10, 2, 15];
  values.sort(compare);
  alert(values); // 15,10,2,1

可以简写为箭头函数

  let values = [1, 10, 2, 15];
  values.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
  alert(values); // 15,10,2,1

如果数组的元素是数值,或者他valueOf() 返回数值的对象,这个比较函数可以写得更简单,因为这时可以用第二个值减去第一个值:

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

七、操作方法 concat() 、 slice() 、splice()

concat()

concat() 方法可以在现有数组全部元素基础上创建一个新数组。他会先创建一个当前数组的副本,再把它的参数添加到副本末尾,最后返回这个新构建的数组。

  • 原始数组保持不变,返回一个新数组。
  • 如果参数是一个或多个数组,每一项都添加到末尾。
  • 如果不是数组,直接添加到数组末尾。
let colors = ["red", "green", "blue"];
let colors2 = colors.concat("yellow", ["pink", "black"]);
console.log(colors); // ['red', 'green', 'blue']
console.log(colors2); // ['red', 'green', 'blue', 'yellow', 'pink', 'black']

slice()

slice() 方法用于创建一个包含原有数组中一个或多个元素的新数组。

  • 接收一个或两个参数:返回元素的开始索引和结束索引。
  • 如果只有一个参数,返回开始索引到末尾的所有元素。
  • 不影响原始数组。
let colors = ["red", "green", "blue", "pink", "black"];
let colors2 = colors.slice(1);
let colors3 = colors.slice(1, 4);
console.log(colors2); // ['green', 'blue', 'pink', 'black']
console.log(colors3); //  ['green', 'blue', 'pink']

splice()

splice() 主要目的是在数组中间插入元素,但有3种不同的方式使用这个方法。

删除。

需要给splice() 传入两个参数:要删除的第一个元素的位置、要删除的元素的数量。

插入

需要给splice() 传入至少三个参数:开始位置、要删除的元素数量为0、要插入的元素。

替换

需要给splice() 传入至少三个参数: 开始位置、要删除元素的数量、任意的多个元素。

  • 始终返回一个新数组,这个数组包含被删除的元素,如果没有删除元素,则返回空数组。

放在一起对比:

let colors = ["red", "green", "blue"];
let removed = colors.splice(0, 1); // 删除第一项
alert(colors); // green,blue
alert(removed); // red

removed = colors.splice(1, 0, "yellow", "orange");  // 在位置1 插入两个元素
alert(colors); // green,yellow,orange,blue
alert(removed); // 空数组

removed = colors.splice(1, 1, "red", "pink"); // 在位置1 删除一个元素,然后插入两个元素
alert(colors); // green,red,pink,orange,blue
alert(removed); // yellow

八、搜索和位置方法 indexOf() 、lastIndexOf() 、includes()、find() 、findIndex()

严格相等 indexOf() 、lastIndexOf() 、includes()

相同点

  • 都接收两个参数,第一个参数表示要查找的元素,第二个参数为可选的起始搜索位置。
  • 判断相等时,会使用 === 进行比较,即 两者必须严格相等。

不同点

  • indexOf 从数组第一项开始向后搜索,返回结果为 位置下标或 -1(没搜到);
  • lastIndexOf 从数组最后一项开始向前搜索,返回结果为 位置下标 或 -1(没搜到);
  • includes 从数组第一项开始向后搜索,返回结果为布尔值,表示是否找到至少一个与指定元素匹配的项
let numbers = [1,2,3,4,5,4,3,2,1]
alert(numbers.indexOf(4)); // 3
alert(numbers.lastIndxOf(4)); // 5
alert(numbers.includes(4)); // true

alert(numbers.indexOf(4, 4)); // 5
alert(numbers.lastIndxOf(4, 4)); // 3
alert(numbers.includes(4, 7)); // false
let person = { name: "Bob" };
let people = [{ name: "Bob" } ];
let people1 = [person];

alert(people.indexOf(person));  // -1
alert(people1.indexOf(person));  // 0
alert(people.includes(person));  // false
alert(people1.includes(person));  // true

断言函数 find() 、findIndex()

ECMAScript 也允许按照定义的断言函数搜索数组,每个索引都会调用这个函数。

断言函数接收三个参数:元素、索引、数组本身。 断言函数返回真值,表示是否匹配。

find() 和 findIndex() 使用了断言函数。
这两个方法都是从数组的最小索引开始
两个方法接收的第一个参数表示需要匹配的元素;第二个可选参数用于指定断言函数内部this的值
找到匹配项后,两个方法都不再继续搜索

find 返回第一个匹配的元素
findIndex返回第一个匹配元素的索引

const people = [
  {
    name: "Bob",
    age: 18,
  },
  {
    name: "Jack",
    age: 20,
  },
];
console.log(people.find((element, index, array) => element.age < 19));
// {name: 'Bob', age: 18}
console.log(people.findIndex((element, index, array) => element.age < 19));
// 0

九、迭代方法 every() 、filter() 、forEach() 、map() 、some()

every() :对数组每一项都运行传入的函数,如果对每一项函数都返回true,则这个方法返回 true;
filter() :对数组每一项都运行传入的函数,函数返回true的项会组成数组之后返回;
forEach() :对数组每一项都运行传入的函数,没有返回值;
map() :对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组;
some() :对数组每一项都运行传入的函数,如果有一项函数返回true,则这个方法返回 true;

共同点:
这些方法都不改变原数组。

let numbers = [1,2,3,4,5,4,3,2,1];
// every 用于确定是否所有元素都符合指定条件
let everyResult = numbers.every((item,index,array) => item > 2);
console.log(everyResult); // false

// some用于确定是否至少含有一个符合条件的元素
let someResult = numbers.some((item,index,array) => item > 2);
console.log(someResult); //true

// filter用于筛选符合某些条件的元素
let filterResult = numbers.filter((item,index,array) => item > 2) ;
alert(filterResult); // 3,4,5,4,3

// map方法非常适合生成一个与原数组元素一一对应的新数组
let mapResult = numbers.map((item,index,array) => item*2); 
alert(mapResult); // 2,4,6,8,10,8,6,4,2

// forEach 不返回内容,执行一些操作
numbers.forEach((item,index,array) => {
  // 执行某些操作
})

十、归并方法 reduce() 、reduceRight()

这两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值。

reduce方法从第一项开始遍历到最后一项
reduceRight方法从最后一项开始遍历到第一项
这两个方法都接收两个参数:归并函数、可选的初始值;

  • 归并函数接收四个参数:上一个归并值、当前项、当前项的索引、数组本身
// 可以使用reduce 方法执行累加数组中所有数值的操作
let values = [1, 2, 3, 4, 5];
let sum = values.reduce((prev, cur, idnex, array) => prev + cur);
alert(sum); // 15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值