【高级程序设计(第四版) 】- Array

192 阅读10分钟

MDN-Javasript标准内置对象(Array)

创建数组

构造函数模式

  使用new Array()与Array()创建数组性质一致。如果构造函数中只传入一个参数,若参数为数值则创建一个长度为该值的空数组;若参数为其他类型,则创建一个只包含该值的数组

 let emptyList = new Array(5);
 let emptyList1 = Array(5);
 let elementList = new Array('5');
 console.log(emptyList); // [empty * 5], 每个元素值都为undefined
 console.log('emptyList', emptyList); // [empty * 5], 每个元素值都为undefined
 console.log('emptyList1', emptyList1); // [empty * 5], 每个元素值都为undefined
 console.log('elementList', elementList); // ['5']

字面量方式

  使用数组字面量方式创建数组不会调用Array()构造函数。使用数组字面量初始化数组时,可以使用一串逗号来创建空位(hole)。ECMAScript 会将逗号之间相应索引位置的值当成空位,es6会将这些空位当成存在的元素,其值为undefined

 let colors = ['red', 'blue', 'yellow'];
 let emptyList = [,,,];
 let numbers = [1,2,3,];
 console.log('colors', colors); // ['red', 'blue', 'yellow']
 console.log('emptyList', emptyList); // [empty * 3] 每个元素值都为undefined
 console.log('numbers', numbers); // [1,2,3]

静态方法创建 - Array.from()、Array.of()

  • Array.from(arrayLike[, mapFn(element)[, thisArg]]): 用于将类数组结构转换为数组
    • arrayLike: 类数组参数: 任何可迭代的结构,或者有length属性和可索引元素的结构
    • mapFn:回调函数,函数参数为数组元素。若指定了当前参数,新数组中每个元素都会执行当前回调函数
    • thisArg: 回调函数mapFn的this对象(原始值变现为包装类型),mapFn若为箭头函数则获取不到当前的thisArg
  • Array.of():将一组参数转换为数组实例
  // Array.from()
  function arrayFrom () {
  	console.log(Array.from(arguments), arguments);
  }
  arrayFrom('11', '22', '44'); // ['11', '22', '44']
  // Array.of
  console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4] 
  console.log(Array.of(undefined)); // [undefined]

检测数组

instanceof Array

Array.isArray()

迭代器方法

返回的是迭代器,需要使用for of,或者Array.from 获取数组实例

keys()、values()、entries()

  • keys():返回数组索引的迭代器
  • values(): 返回数组元素的迭代器
  • entries():返回索引/值对的迭代器
  let colors = ['red', 'green', 'yellow', 'blue'];
  // 因为这些方法都返回迭代器,所以可以将它们的内容
  // 通过 Array.from()直接转换为数组实例
  console.log(Array.from(colors.keys())); // ['red', 'green', 'yellow', 'blue']
  console.log(colors.values()); // Array Iterator {}
  console.log(colors.entries()); // Array Iterator {}

复制和填充方法(改变原数组)

copyWithin()、fill()

若索引值超出数组边界、零长度及方向相反的索引范围,则静默 不进行操作(注意: 支持数组长度范围内的负值)

  • copyWithin(target[,start[,end]]]): 按照指定返回浅复制数组中的部分内容,然后插入指定索引开始的位置不包含end元素
  • fill(value[,start[,end]]):向数组索引开始的位置插入/替换为指定的value值不包含end元素
  const zeroes = [0, 0, 0, 0, 0];
  // 用 7 填充索引大于等于 1 且小于 3 的元素
  zeroes.fill(7, 1, 3); 
  console.log(zeroes); // [0, 7, 7, 0, 0];
  var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  numbers.copyWithin(0, 4, 7); // [4, 5, 6, 3, 4, 5, 6, 7, 8, 9]
  console.log(numbers); // [4, 5, 6, 3, 4, 5, 6, 7, 8, 9];

转换方法(string)

toLocalString()、toString()、valueOf()、join()

  • toLocalString():返回数组中每个值调用toLocalString()返回值用逗号分隔组成的字符串
  • toString(): 返回数组中每个值调用toString()返回值用逗号分隔组成的字符串
  • valueOf(): 返回数组本身
  • join([separator]):返回数组中每个值toString()方法返回值 以separator(默认为逗号)分隔组成的字符串
  let red = {
    toLocalString () {
      return 'toLocalString-red';
    },
    toString () {
      return 'toString-red';
    },
    valueOf () {
      return 'valueOf-red';
    }
  };
  let colors = [red, 'red', 'blue', 'green'];
  console.log('toLocalString', colors.toLocaleString()); // toLocalString-red,red,blue,green
  console.log('toString', colors.toString()); // toString-red,red,blue,green
  console.log('valueOf', colors.valueOf()); // [{xxxx}, 'red', 'blue', 'green']
  console.log('join', colors.join(',')); // toString-red,red,blue,green

栈方法(改变原数组)

  栈是一种后进先出(LIFO,Last-In-First-Out)的结构,也就是最近添加的项先被删除。数据项的插入(称为推入,push)和删除(称为弹出,pop)只在栈的一个地方发生,即栈顶

push()、pop()

  • push(item1[...itemx]): 将参数顺序插入数组的尾部,返回新数组的长度
  • pop(): 删除数组的最后一个元素,返回删除的元素
  let colors = [];
  const count = colors.push('red', 'blue', 'green'); 
  console.log(count, colors); // 3, ['red', 'blue', 'green']
  const popValue = colors.pop();
  console.log('pop', colors); // green
  const pushValue = colors.push('yellow');
  console.log('push', pushValue, colors); // 3 ['red', 'blue', 'yellow']

队列方法(改变原数组)

  队列以先进先出(FIFO,First-In-First-Out)形式限制访问。队列在列表末尾添加数据,但从列表开头获取数据 (push&shift)

shift()、unshift()

  • shift(): 删除数组中的第一个元素,返回删除的元素
  • unshift(item1[...itemx]):将数组顺序插入数组的头部,返回新数组的长度
  let colors = [];
  const count = colors.push('red', 'blue', 'green');
  console.log(count, colors); // 3 ['red', 'blue', 'green']
  const shiftValue = colors.shift();
  console.log(count, shiftValue); // 2, red
  const newCount = colors.unshift('headRed', 'headBlue');
  console.log(newCount, colors); // 4, ['headRed', 'headBlue', 'blue', 'green']

排序方法(改变原数组)

reverse()、sort()

  • reverse():颠倒数组中元素的顺序,返回改变后的原数组
  • sort([sortBy]):对数组元素进行排序 ,默认调用数组中每项值的toString方法进行比较后,按升序返回改变后的元素组
    • sortBy: 比较函数 返回0, -1,1 简而言之返回1(ture隐式转换为1?)表示换位置,其他两者表示不进行位置替换
  let values = [2,4,6,7,1,78,10];
  console.log('defaultValue', values); // [2,4,6,7,1,78,10]
  const reverseValue = values.reverse();
  console.log('reverse', reverseValue, values); // [10,78,1,7,6,4,2]  [10,78,1,7,6,4,2]
  const sortDefault = values.sort();
  console.log('sortDefault', sortDefault, values); // [1,10,2,4,6,7,78]  [1,10,2,4,6,7,78]
  const sortBy = values.sort((value1, value2) => {
    if (value1 > value2) {
      return -1;
    } else if (value1 < value2) {
      return 1;
    } else {
      return 0;
    }
  });
  console.log('sortBy', values); // [1,2,4,6,7,10,78]

操作方法

concat()、slice()、splice()

  • concat(): 将参数加入数组的尾部,若参数为数组则逐一增加,若不是数组则直接追加。返回新组合的数组
  • slice(start[,end]): 返回已有数组从start位置到end位置的数组切片

    start和end可以为负值(数组长度加上这个负值的结果确定位置)

    • start: 切片开始位置
    • end:切片结束位置,(默认为最末端,切片元素不包含end元素)
  • splice(index,howMany[, item1,...itemX])(改变原数组): 从数组中添加/删除/替换项目。返回被删除的项目组成的新数组,若无删除项目则返回空数组
    • index:要删除或添加的起始位置
    • howMany:删除的元素个数
    • itemX: 添加的元素,从index号位置开始添加
  let colors = ['red', 'blue'];
  let concatColors = colors.concat('yellow', ['green', 'pink']);
  console.log('concat', concatColors, colors); // ["red", "blue", "yellow", "green", "pink"] ["red", "blue"]

  const sliceColors = concatColors.slice(3,5);
  console.log('slice', concatColors, sliceColors); // ['red', 'blue', 'yellow', 'green', 'pink'] ['green', "pink"]

  // const spliceDiv = concatColors.splice(2, 2);
  const spliceDiv = concatColors.splice(2, 2, 'addRed', 'addBlue', 'addPink');
  console.log('spliceDiv', concatColors, spliceDiv); // ['red', 'blue', 'addRed', 'addBlue', 'addPink', 'pink']  ['yellow', 'green']

搜索和位置方法(对大小写敏感)

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

  • indexOf(searchVal[, fromIndex]): 从formIndex位置头向后搜索,返回查找元素在数组中的位置 若没有找到则返回-1
  • lastIndexOf(searchVal[, fromIndex]): 从formIndex位置后向前搜索,返回查找元素在数组中的位置 若没有找到则返回-1
  • includes():返回布尔值,表示该数组中是否包含指定元素的匹配项
  let colors = ['yellow', 'red', 'blue', 'black', 'Red', 'green', 'Red'];
  console.log('indexOf', colors.indexOf('red'), colors.indexOf('red', 2)); // 2 -1
  console.log('lastIndexOf', colors.lastIndexOf('Blue'), colors.lastIndexOf('Red')); // -1 6 - 取最后面匹配的Red
  console.log('includes', colors.includes('blue')); // true

断言函数find()、findIndex()(找到匹配项之后不再继续搜索)

  • find(function(currentValue[, index, arr]), thisValue): 查找第一个匹配的数据
  • findIndex(function(currentValue[, index, arr]), thisValue): 查找第一个匹配的索引位置
  let colors = ['yellow', 'red', 'blue', 'black', 'red', 'green'];
  const findValue = colors.find(function(value, index, arr) {
    console.log(index, arr, this.toString());
    return value === 'red';
  }, 'R');
  console.log('find', findValue); // Red
  const findIndexValue = colors.findIndex(function(value, index, arr) {
    return value === 'red';
  }, 'R');
  console.log('findIndex', findIndexValue); // 1

迭代方法

every()、some()、filter()、map()、forEach()

参数: mapFn(currentValue[, index, arr])[, thisValue]    currentValue: 当前数组元素值 index: 当前数组元素索引 arr:当前数组 thisValue:传递给前面函数的值,直接表示为this的值,前面函数不能为箭头函数(原始值包装类型)

  • every(mapFn[,thisValue]):对数组每一项运行传入的函数,如果每一项函数都为true 则返回true
  • some(mapFn[,thisValue]):对数组每一项运行传入的函数,如果存在某一项函数为true,则返回true
  • filter(mapFn[,thisValue]):对数组每一项运行传入的函数,返回一个新数组,包含了符合条件的所有元素组。如果没有符合条件的元素则返回空数组
  • map(mapFn[,thisValue]):对数组每一项都运行传入的函数,返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值
  • forEach(mapFn[,thisValue]):对数组每一项都运行传入的函数, 无返回值
let numbers = [1,2,3,4,5,6,7,8,9,10];
const everyResult = numbers.every((item, index, arr) => item > 2);
console.log('every', everyResult, numbers); // false [1,2,3,4,5,6,7,8,9,10]

const someResult = numbers.some((item, index, arr) => item % 5 === 0);
console.log('some', someResult, numbers); // true [1,2,3,4,5,6,7,8,9,10]

const filterResult = numbers.filter(function (item, index, arr) {
  return  item % Number(this.toString()) === 0;
}, 5)
console.log('filter', filterResult, numbers); // [5, 10] [1,2,3,4,5,6,7,8,9,10]

const mapResult = numbers.map(function(item, index, arr) {
  return item + index + this;
}, 100);
console.log('map', mapResult, numbers); // [101, 103, 105, 107, 109, 111, 113, 115, 117, 119]  [1,2,3,4,5,6,7,8,9,10]

const forEachResult = numbers.forEach((item, index, arr) => item + index);
console.log('forEach', forEachResult, numbers); // undefined  [1,2,3,4,5,6,7,8,9,10]

// 引用类型是按值传递,对引用类型的重新赋值会改变外部的引用类型的值
const forEachResult1 = numbers.forEach((item, index, arr) => {
  arr[index] = item + index;
});
console.log('forEach', forEachResult1, numbers); // undefined  [1,2,3,4,5,6,7,8,9,10]

归并方法

reduce()、reduceRight()

mapFn(total, currentValue[, index, arr])[, initValue] total: 初始值或计算后的值 currentValue: 当前元素 index: 当前元素的索引 arr: 当前元素所属的数组 initValue: 初始值, 前面函数可以是箭头函数

  • reduce(mapFn[,initValue]):从前到后进行归并操作,返回计算的结果值
  • reduceRight(mapFn[, initValue):从后到前进行归并操作,返回计算的结果值
  let numbers = [2,34,5,6,8,32];
  let reduceResult = numbers.reduce((total, currentValue) => {
     return total + currentValue;
  }, 100);
   console.log('reduce', reduceResult); // 187
  let reduceRightResult = numbers.reduceRight((total, currentValue) => {
    return total + currentValue;
  }, 100);
  console.log('reduceRight', reduceRightResult); // 187

综合练习

// Some data we can work with

    const inventors = [
      { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
      { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
      { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
      { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
      { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
      { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
      { first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
      { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
      { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
      { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
      { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
      { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
    ];

    const flavours = ['Chocolate Chip', 'Kulfi', 'Caramel Praline', 'Chocolate', 'Burnt Caramel', 'Pistachio', 'Rose', 'Sweet Coconut', 'Lemon Cookie', 'Toffeeness', 'Toasted Almond', 'Black Raspberry Crunch', 'Chocolate Brownies', 'Pistachio Almond', 'Strawberry', 'Lavender Honey', 'Lychee', 'Peach', 'Black Walnut', 'Birthday Cake', 'Mexican Chocolate', 'Mocha Almond Fudge', 'Raspberry'];

    const people = ['Beck, Glenn', 'Becker, Carl', 'Beckett, Samuel', 'Beddoes, Mick', 'Beecher, Henry', 'Beethoven, Ludwig', 'Begin, Menachem', 'Belloc, Hilaire', 'Bellow, Saul', 'Benchley, Robert', 'Benenson, Peter', 'Ben-Gurion, David', 'Benjamin, Walter', 'Benn, Tony', 'Bennington, Chester', 'Benson, Leana', 'Bent, Silas', 'Bentsen, Lloyd', 'Berger, Ric', 'Bergman, Ingmar', 'Berio, Luciano', 'Berle, Milton', 'Berlin, Irving', 'Berne, Eric', 'Bernhard, Sandra', 'Berra, Yogi', 'Berry, Halle', 'Berry, Wendell', 'Bethea, Erin', 'Bevan, Aneurin', 'Bevel, Ken', 'Biden, Joseph', 'Bierce, Ambrose', 'Biko, Steve', 'Billings, Josh', 'Biondo, Frank', 'Birrell, Augustine', 'Black, Elk', 'Blair, Robert', 'Blair, Tony', 'Blake, William'];

    // Array.prototype.filter()
    // 1. Filter the list of inventors for those who were born in the 1500's
    const fifteen = inventors.filter(inventor => inventor.year >= 1500 && inventor.year < 1600);
    console.table(fifteen);

    // Array.prototype.map()
    // 2. Give us an array of the inventors' first and last names
    const fullNames = inventors.map(inventor => `${inventor.first} ${inventor.last}`);
    console.log('fullNames', fullNames);

    // Array.prototype.sort() - 改变原数组
    // 3. Sort the inventors by birthdate, oldest to youngest
    const ordered = inventors.sort((a, b) => a.year > b.year ? 1 : -1);
    // console.table(ordered);

    // Array.prototype.reduce()
    // 4. How many years did all the inventors live?
    const totalYears = inventors.reduce((total, inventor) => {
      // 返回值会被当做下一轮的total
      return total += (inventor.passed - inventor.year)
    } , 0);
    console.log('totalYears', totalYears);

    // 5. Sort the inventors by years lived
    const oldest = inventors.sort((a, b) => {
      const last = a.passed - a.year;
      const next = b.passed - b.year;
      return last > next ? -1 : 1;
    });
    console.table(oldest);

    // 6. create a list of Boulevards in Paris that contain 'de' anywhere in the name
    // https://en.wikipedia.org/wiki/Category:Boulevards_in_Paris


    // 7. sort Exercise
    // Sort the people alphabetically by last name
    const sortPeople = people.sort((a, b) => {
      const [ aFirstName, aLastName ] = a.split(', ');
      const [ bFirstName, bLastName ] = b.split(', ');
      // a -> z A < Z
      return aLastName > bLastName ? 1 : -1;
    });

    console.log(sortPeople);
    // 8. Reduce Exercise
    // Sum up the instances of each of these
    const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car', 'truck' ];
    const sumData = data.reduce((obj, item) => {
      if (!obj[item]) {
        obj[item] = 0; // 若当前不存在  设置一个参数,并将次数设置为0
      }
      obj[item]++;
      return obj;
    }, {});
    console.log(`sum`, sumData);

es6之前大部分数组方法