(十四) js中的数组相关方法

类数组对象

类数组定义

  • 拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理)
  • 不具有数组所具有的方法;

常见的类数组有:

  • arguments对象
  • DOM方法的返回结果。比如 document.getElementsByTagName()
  • 字符串

  1. arguments对象

          function fn() {
            console.log(arguments);
            [...arguments].forEach(element => {
              console.log(element);
            });
          }
          fn(1, 2, 3, 4, 5)
    
  2. 字符串

    var str = '1234'
    console.log(str.length);      // 4
    
    // 对于字符串长度的改变是不允许的, 但是可以利用字符串拼接的方式
    str.push('5')       // str.push is not a function
    Array.prototype.push.call(str, '5')     //Cannot assign to read only property 'length' of object
    console.log(str);
    
    Array.prototype.forEach.call(str, item => console.log(item))      // 1 2 3 4
    

1. 字符串和数组转换

类数组 -> 数组

toString() 、 join()和split()

toString() 是一个所有对象都有的方法, 它把一个变量隐式转换成字符串

console.log(Array.prototype.toString.call([[[1, [[2], 3]], [4, 5], 6, 7]]));    //1,2,3,4,5,6,7
console.log([[[1, [[2], 3]], [4, 5], 6, 7]].join());    // 1,2,3,4,5,6,7
console.log([[1, [[2], 3]], [4, 5], 6, 7].join('-'));    // 1,2,3-4,5-6-7

toString全部转换, 而join只能分割一层

split用于把字符串转换成数组

var str = "123"
str.slpit()				// ['123']
str.split('')			// ['1','2','3']

[slice()方法的特殊操作](#5. 删改)

... (Array.from的语法糖)

var str = "12345"
console.log([...str]);      			// ["1", "2", "3", "4", "5"]
console.log(Array.from(str));			// ["1", "2", "3", "4", "5"]

2. 堆栈方法

push pop unshift shift

方法名 push pop unshift shift
操作 追加 尾删 头加 头删
返回值 数组长度 删除的值 数组长度 删除的值

3. 排序

reverse sort 随机排序

方法名 reverse sort
操作 数组元素反序 排序
返回值 改变后的原数组 改变后的原数组
// arr.reverse()
var arr = ['hello', 'world', 123]   //   [123, "world", "hello"]
console.log(arr, arr.reverse());    //   [123, "world", "hello"]

sort() 方法用于对数组的元素进行排序,并返回数组。默认排序顺序是根据ASCII码升序。

sort语法:arrayObject.sort(sortby);参数sortby可选。规定排序顺序。必须是函数(函数名)。

注:如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:

  • 若 a 小于 b,则返回一个小于 0 的值。即: 升序
  • 若 a 等于 b,则返回 0。相等位置不变1
  • 若 a 大于 b,则返回一个大于 0 的值。即: 降序
var arr = [1, 2, 3, 4]
console.log(arr, arr.sort((a, b) => {
  return b - a
}));					// [4,3,2,1]   [4,3,2,1]

利用sort实现一个随机排序

function ramSort() {
  return Math.random() - 0.5
}
console.log(arr.sort(ramSort));

4. 拼接

concat ES6的扩展运算符 ...

方法名 concat ...
返回值 新数组 新数组
对原数组修改 没有 没有
可拼接几层 一层 一层
var arr = [1, 2, 3]
// concat
console.log(arr, arr.concat(4, 5));           //  [1,2,3,4,5]	[1,2,3,4,5]
console.log(arr, arr.concat([4, 5]));         //  [1,2,3,4,5]	[1,2,3,4,5]
console.log(arr, arr.concat([4, [5]]));       //  [1,2,3,4,5]	[1,2,3,4,[5]]

// ...
console.log(arr, [...arr, 4, 5]);	//[1,2,3,4,5]	[1,2,3,4,5]
console.log(arr, [...arr, [4, 5]]);	//[1,2,3,4,5]	[1,2,3,[4,5]]
console.log(arr, [...arr, [4, [5]]]);	//[1,2,3,4,5]	[1,2,3,[4,[5]]

5. 删改

slice splice

方法 slice splice
返回值 删除后的数组 删除后的数组
原数组是否被修改

对于slice和splice的删除操作, 都是左闭右开区间

slice():image-20210711081530606

需要两个参数: start 删除的起始下标, end 删除的结束下标 => start必须小于end

var arr = [1, 2, 3, 4, 5]
console.log(arr, arr.slice());		//  [1, 2, 3, 4, 5]  [1, 2, 3, 4, 5]
console.log(arr, arr.slice(3));		//  [1, 2, 3, 4, 5]  [4, 5]
console.log(arr, arr.slice(2, 4));	//  [1, 2, 3, 4, 5]  [3, 4]
console.log(arr, arr.slice(-2));	//  [1, 2, 3, 4, 5]  [4, 5]
console.log(arr, arr.slice(-3, -1));	//  [1, 2, 3, 4, 5]  [3, 4]

// slice()的特殊操作
var str = "12345"
console.log(str, Array.prototype.slice.call(str));          // "12345" ["1", "2", "3", "4", "5"]

function fn() {
  console.log(Array.prototype.slice.call(arguments));       // [1, 2, 3, 4, 5]
}
fn(1, 2, 3, 4, 5)

splice():image-20210711083747883

需要两个参数: start: 删除的起始下标, count: 需要删除的个数

  • 当count < 0 时, 不进行操作
  • 当count = 0时, 进行添加操作, 此时需要指定添加的元素
  • 当count > 0时, 表示要删除的个数
var arr = [1, 2, 3, 4, 5]
console.log(arr, arr.splice());		// [1, 2, 3, 4, 5] []
console.log(arr, arr.splice(4));	// [1, 2, 3, 4]  [5]
console.log(arr, arr.splice(-2));	// [1, 2, 3]  [4, 5]
console.log(arr, arr.splice(0, 3));	// [4, 5]  [1, 2, 3]
console.log(arr, arr.splice(0));	// [] []

// 添加元素
console.log(arr, arr.splice(0, 0, 'a', 12));        //  ["a", 12, 1, 2, 3, 4, 5]  []

6. 元素下标

indexOf lastIndexOf

方法名 indexOf lastIndexOf
返回值 找到: 元素下标 / 找不到: -1 找到: 元素下标 / 找不到: -1
var arr = [1, 2, 3, 4, 5, 3]

console.log(arr.indexOf(3));        //   2
console.log(arr.indexOf(6));        //  -1

console.log(arr.lastIndexOf(3));    //   5
console.log(arr.indexOf(6));        //  -1

7. 数组迭代

map forEach filter some every

1. forEach

作用像for一样

image-20210711103540495

forEach没有返回值

forEach的第一个参数是一个回调函数, 可以接收三个参数: item index arr

    var arr = [1, 2, 3, 4, 5]
    // 基本使用
    arr.forEach(function (item, index, arr) {
      console.log(item, index, arr);
    }) 
		// 类数组(对象)的调用
    function fn() {
      [...arguments].forEach(item => console.log(item))
    }
    fn(1, 2, 3, 4, 5)

    // 返回值     =>  没有返回值
    console.log(arr.forEach(function (item) {
      return 1          // undefined
    }));


    // 与for的对比    对于稀疏数组的遍历
    var arr = [1, , 3]
    arr.forEach(function (item) {
      console.log(item);    // 1  3
    })

    for (let i = 0, l = arr.length; i < l; i++) {
      console.log(arr[i]);        // 1  undefined   3
    }

    // break  continue 无法使用
    var arr = [1, 2, 3, 4]
    arr.forEach(function (item) {
      if (item === 2) {
        //break         // SyntaxError: Illegal break statement
        continue        // SyntaxError: Illegal continue statement: no surrounding iteration statement
      }
    })

foreach还可以接收第二个参数, this指向

    var arr = [1, 2, 3, 4, 5]
    var newArr = []
    arr.forEach(function (item) {
      this.push(item)
    }, newArr)

    console.log(newArr);        // [1, 2, 3, 4, 5]

    var obj = {
      items: [1, 2, 3],
      print: function () {
        console.log(this);        // obj

        this.items.forEach(function (item) {
          console.log(this);      // window
        })
      }
    }
    obj.print()
		// 指定this指向
    var obj = {
      items: [1, 2, 3],
      print: function () {
        console.log(this);        // obj

        this.items.forEach(function (item) {
          console.log(this);      // obj
        },this)
      }
    }
    obj.print()

2. map

image-20210711113010717

返回一个和原数组有映射关系的新数组 => 有返回值

返回一个新数组

  • map()不会对空数组进行检测
  • map()不会改变原始数组
    var arr = [1, 2, 3, 4, 5]    var newArr = arr.map(function (item) {      return item * 2    })    console.log(arr, newArr);       // [1, 2, 3, 4, 5]  [2, 4, 6, 8, 10]

练习:

    // 需求: 返回一个新数组: 数组中的元素为每个数组中的最大值    function fn(arr) {      return arr.map(function (item) {        // apply和call的参数区别        return Math.max.apply(Math, item)      })    }    fn([      [4, 5, 6, 7],      [12, 33, 45, 63],      [123, 432, 423, 234],      [1234, 5435, 4564, 7567]    ]);

// apply和call的参数区别

call(thisObj, arg1, arg2, arg3, arg4);

apply(thisObj, [args]);

  • thisObj:call和apply第一个参数是一样的,该参数将替代Function类里面的this对象。
  • arg1,arg2....:是一个个的参数,
  • args:一个数组或类数组,是一个参数列表。

3. filter

根据每一次返回值的真假来过滤数组 => 返回值必须是一个布尔值

返回一个新数组

简单理解: 只有满足 return 后面表达式的数组元素会被保留

    var arr = [1, 2, 3, 4, 5]
    console.log(arr.filter(item => {
      return item > 2
    }));        //  3, 4, 5

练习:

    // 需求: 过滤掉数组中的 undefined 和 null
    var arr = [1, 2, 3, undefined, 4, null, 5]

    var newArr = arr.filter(item => { return item != undefined })
    console.log(newArr);        // [1, 2, 3, 4, 5]

// undefined == null    

4. some和every

两个方法都返回一个布尔值

    var arr = [1, 2, 3, 4, 5]
    var res1 = arr.some((item, index, arr) => {
      // 只要有一个元素满足return后的表达式, 就返回true
      return item % 2 === 0
    })

    var res2 = arr.every((item, index, arr) => {
      // 只有数组中的每个元素都满足return后的表达式, 才返回true
      return item % 2 === 0
    })

    console.log(res1, res2);      // true   false

8. reduce()

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

返回一个值 (不像上面局限于数组)

image-20210711143757005

callback中第一个参数是一个累加器 (accumulator)

几种使用场景

  1. 数组求和 基本使用

        // 1. 数组求和    var arr = [0, 1, 2, 3, 4]    var sum = arr.reduce((acc, item) => {      return acc + item    })    console.log(sum);
    

    计算过程: 赋予累加器acc为数组第一个元素的值, 然后从数组第二个元素1开始进行累加, 最后将最终的计算结果返回

事实上, 还可以为reduce指定第二个参数, 指定的第二个参数将作为callbackaccumulator的初始值

  1. 数组元素是对象, 对元素对象的value求和

        // 2. 数组元素是对象, 对元素对象的value求和 
        var arr = [
          { a: 1 },
          { b: 2 },
          { c: 3 }
        ]
        var sum = arr.reduce((acc, item) => {
          var k = Object.keys(item)[0]
          return acc + item[k]
        }, 0)				// 第二个参数
    
        console.log(sum);       // 6
    
  2. 二维数组转换成一维数组

        var arr = [[1, 2], [3, 4], [5, 6]]
        var newArr = arr.reduce((acc, item) => {
          return acc.concat(item)
        }, [])
        console.log(newArr);      // [1,2,3,4,5,6]
    
  3. 计算数组中每个元素出现的次数, 结果返回一个对象

        var arr = ['a', 'b', 'a', 'c', 'd', 'c']
        var res = arr.reduce(function (acc, item) {
          if (item in acc) {
            acc[item]++
          } else {
            acc[item] = 1
          }
          return acc
        }, {})
    
        console.log(res);         // {a: 2, b: 1, c: 2, d: 1}
    
  4. 按照某个属性对object进行分类

    // 比如说: 按照年龄这个属性进行分类
    // 结果为一个对象: key: 年龄的value值, value: 以数组存储, 数组元素是原始数据中的数据
    // {
    //   20: [
    //     { name: 'Max', age: 20 },
    //     { name: 'Jane', age: 20 }
    //   ],
    //   21: [{ name: 'Alice', age: 21 }]
    // }
        var people = [
          { name: 'Alice', age: 21 },
          { name: 'Max', age: 20 },
          { name: 'Jane', age: 20 }
        ];
    		// 第一次答案	
        function groupBy(objectArr, basis) {
          return objectArr.reduce((newArr, item) => {
            var k = Object.keys(newArr);
            var indexK = k.indexOf(item[basis])
    
            if (!(item[basis] in newArr)) {
              newArr[item[basis]] = []
            }
    
            if (indexK) {
              newArr[item[basis]].push(item)
            }
            return newArr
          }, {})
        }
    
        var newArr = groupBy(people, 'age')
        console.log(newArr);
    
    		// MDN给的解法   两个思路相同, 只不过我个人绕了远路
        function groupBy(objectArr, basis) {
          return objectArr.reduce((newArr, item) => {
            var k = item[basis];
            if (!newArr[k]) {
              newArr[k] = []
            }
            newArr[k].push(item)
            return newArr
          }, {})
        }
    
        var newArr = groupBy(people, 'age')
        console.log(newArr);
    
    
    		// 隔一些天后再写的解法
        function classify(arr, tag) {
          return arr.reduce((acc, item) => {
            if (acc.hasOwnProperty(item[tag])) {
              acc[item[tag]].push(item)
            } else {
              acc[item[tag]] = [item]
            }
            return acc
          }, {})
        }
    
  5. 数组去重

        let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
    
        var res = arr.reduce(function (acc, item) {
          if (acc.indexOf(item) === -1) {
            acc.push(item)
          }
          return acc
        }, [])
    
        console.log(res);
    
  6. 使用reduce实现map

    //  
    if (!Array.prototype.mapUsingReduce) {
      Array.prototype.mapUsingReduce = function(callback, thisArg) {
        return this.reduce(function(mappedArray, currentValue, index, array) {
          mappedArray[index] = callback.call(thisArg, currentValue, index, array)
          return mappedArray
        }, [])
      }
    }
    
    [1, 2, , 3].mapUsingReduce(
      (currentValue, index, array) => currentValue + index + array.length
    ) // [5, 7, , 10]
    
posted @ 2021-07-29 21:15  只猫  阅读(63)  评论(0编辑  收藏  举报