头图

javascript 数组: 单一变量存储多个值

数组每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引。

  1. 数组是值的有序集合
  2. 固定长度
  3. 可以存放不同的数据结构
  4. 一段线性分配的内存.

常用方法

属性名称说明
length长度方法长度方法
名称说明
concat()连接两个或多个数组,并返回已连接数组的副本。
copyWithin将数组中的数组元素复制到指定位置或从指定位置复制。
entries返回键/值对数组迭代对象。
every检查数组中的每个元素是否通过测试。
fill用静态值填充数组中的元素。
filter使用数组中通过测试的每个元素创建新数组。
find返回数组中第一个通过测试的元素的值。
findIndex返回数组中通过测试的第一个元素的索引。
forEach为每个数组元素调用函数。
from从对象创建数组。
includes检查数组是否包含指定的元素。
indexOf在数组中搜索元素并返回其位置。
isArray检查对象是否为数组。
join将数组的所有元素连接成一个字符串。
keys返回 Array Iteration 对象,包含原始数组的键.
lastIndexOf在数组中搜索元素,从末尾开始,并返回其位置。
map使用为每个数组元素调用函数的结果创建新数组。
pop删除数组的最后一个元素,并返回该元素。
push将新元素添加到数组的末尾,并返回新的长度。
reduce将数组的值减为单个值(从左到右)。
reduceRight将数组的值减为单个值(从右到左)。
reverse反转数组中元素的顺序。
shift删除数组的第一个元素,并返回该元素。
slice选择数组的一部分,并返回新数组。
some检查数组中的任何元素是否通过测试。
sort对数组的元素进行排序。
splice从数组中添加/删除元素。
toString将数组转换为字符串,并返回结果。
unshift将新元素添加到数组的开头,并返回新的长度。

详解

slice 函数

截取数组中的几个元素 组成新的数组

  1. slice(start,end)表示从下标start开始到下标end(不包括end)进行截取,得到的是一个新数组,不改变原数组。
  2. 当start为负值时表示从倒数第几个元素开始往后截取
  3. 不填end的话就表示从倒数第几个元素开始截取,一直截取到数组末尾元素。
// 简单复制,浅拷贝
var _array = [1,2,3,4,5]
var copyArray = _array.slice();

// 获取从 N 开始的子数组
// 希望弹出数组的第一个元素并使用它,返回剩余的数组,但希望在不修改原始数组的情况下执行此操作。
function useone (arr) {
  const usedItem = arr[0]
  return arr.slice(1)
}

// 获取从末尾 N 开始的子数组,负索引使删除任意数量的元素变得简单
const sliceArr = _array.slice(-3)
console.log('sliceArr ',sliceArr) //[3,4,5]

// 获取数组的前n个
const first4 = _array.slice(0, 4) // [1,2,3,4]

// 获取数组中某段子数组
function getSegement(arr, begin, length) {
  return arr.slice(begin, begin + length);
}
console.log(getSegement(_array,1,3)) // [2,3,4]

// 类似数组的对象转换
Array.prototype.slice.call(arguments)

// 修改数组中的特定索引
// slice在函数上下文中一个强大而常见的用法是替换数组中特定项的值。从本质上讲,这很简单,只需要分配新值,但是在函数世界中,不能修改原始数组。相反,可以将slice与扩展运算符一起使用,以返回一个相同但对于要更新的​​索引的新数组:
function replaceIdx(arr,index,newVal) {
    return [
        ...arr.slice(0,index),
        newVal,
        ...arr.slice(index+1)
    ]
}

// 偏函数应用
var partial = function() {
  const fn = arguments[0];
  const args = Array.prototype.slice.call(arguments, 1);

  // Return a function that calls fn
  return function() {
    var remainingArgs = Array.prototype.slice.call(arguments);
    return fn.apply(this, args.concat(remainingArgs));
  }
}

// 将任意长度多余的参数强制转换为数组
function myFunc(a, b) { 
  const extraArgs = Array.prototype.slice.call(arguments, 2); 
}
myFunc(1, 2, 3, 4, 5, 6, 7, 8) // 得到a == 1,b === 2,extraArgs=== [3,4,5,6,7,8]

splice 函数

splice()方法有三个参数,分别表示从哪个下标开始,删几个元素。可以实现增加,删除,替换数组元素的功能。arr.splice(-5,5)表示从倒数第五个元素开始,删五个元素。巧妙的是该方法的返回值是删除的元素集合。同时该方法改变了原数组。原数组变成了除了删除的元素剩下的元素集合。

var numbers = [1,2,3,'hello','javascript',33,'world', {"name":"wxh","age":33}];

// 复制数组
var _array = [];


console.log(numbers.splice(0,2,'a','b','c')) // [ 1, 2 ]
console.log(numbers) // [ 'a','b','c', 3,'hello','javascript',33,'world',{ name: 'wxh', age: 33 } ]

forEach 函数

//标准
forEach(callback[,thisArg])

//简单示例
Array.forEach(function(item, index, array){
    //回调函数内容
}, args);

// 扩展
if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (callback, thisArg) {
        for (var i = 0; i < this.length; i++) {
            //当thisArg为undefined时,JS引擎会将window作为其调用者
            if (this[i])
                callback.call(thisArg, this[i], i, this);
        }
    }
}

filter 函数

3个参数同forEach,args也同forEach,唯一不同的是,函数有回调函数里有return返回值。

  1. 简单来说,该方法返回值是一个数组。
  2. 初始时,这个数组是空数组,该方法会通过回调函数遍历整个数组(指Array这个),
  3. 假如当前的元素返回值为true(或者可以隐式转换为true的,比如一个长度大于0的字符串),
  4. 那么会将当前元素添加到被返回的数组中。

例如:[1, 2, 3],
回调函数的return是item > 1, 
当第一个元素1时,1>1为false,因此不会添加到返回的数组中,
而2和3 >1显然是true,因此会被添加到数组中。最终,返回值是[2,3]。

//标准
filter(callback[,thisArg])

//简单示例
Array.filter(function(item, index, array){
    //回调函数内容
}, args);

// 扩展
if (!Array.prototype.filter) {
    Array.prototype.filter = function (callback, thisArg) {
        var temp = [];
        for (var i = 0; i < this.length; i++) {
            if (this[i]) {
                if (callback.call(thisArg, this[i], i, this)) {
                    //如果callback返回true,则该元素符合过滤条件,将元素压入temp中
                    temp.push(this[i]);
                }
            }
        }
        return temp;
    }
}

map 函数

3个参数同forEach,args也同forEach,唯一不同的是,函数有回调函数里有return返回值。
简单来说,该方法的返回值也是一个数组(类filter);

  1. 和filter的区别在于,filter是将原数组元素,选择性加入到新数组中。
  2. map是将原数组的每个元素,进行处理后,放到新数组中。

例如:[1,2,3]作为原数组,map回调函数内的代码为:
return item + 10;
那么就相当于将1+10放到数组中,然后将2+10放到数组中,再将3+10放到数组中。
结果为:[11, 12, 13]
当然,也可以写更复杂的逻辑,比如if(item>3)时+10,然后else if(item>2)时+5,否则else -10
那么结果就是[-9, 7, 13]

//标准
map(callback[,thisArg])

//简单示例
Array.map(function(item, index, array){
    //回调函数内容
}, args);

// 扩展
if (!Array.prototype.map) {
    Array.prototype.map = function (callback, thisArg) {
        var temp = [];
        for (var i = 0; i < this.length; i++) {
            if (this[i]) {
                var newItem = callback.call(thisArg, this[i], i, this);
                temp[i] = newItem//将callback返回的新元素压入temp中
            }
        }
        return temp;
    }
}

reduce 函数

首先看回调函数,他有四个参数,
item是当前元素,别的地方写的是currentValue表示当前值,为了方便理解,我这里写item和上面统一风格
index是当前元素的索引;
Array是整个数组(可以通过这个修改源数组);
上面3个都很好理解。

第一个参数previousValue是核心。他表示上一次执行回调函数时的返回值。
例如,有数组[1, 2, 3, 4]
当我遍历到第二个元素时,回调函数的previousValue的值是1,item的值为2,
return我写为:return previousValue + item
那么当遍历到第三个元素时,回调函数的previousValue的值则为3(因为1+2),item的值为3
当遍历到第四个元素时,previous的值则为6(因为3+3),
最终reduce的返回值为10(因为6+4)

那么问题来了,为什么没提到遍历第一个元素?
原因是,当reduce没有第二个参数时,遍历从数组的第二个元素开始,
第一次执行回调函数的previousValue的值是数组第一个元素的值

当reduce存在第二个参数时(哪怕是null或者undefined),遍历都将从第一个元素开始;
第一次执行回调函数时(遍历第一个元素),previousValue的值是第二个参数的值,而item是第一个元素的值

所以在使用的时候需要注意,如果需要执行和数组元素个数一样次数的回调函数,那么必须设置reduce的第二个参数;
如果不设置,那么回到函数次数执行的次数,将比数组元素个数少1。

//标准
reduce(callback[,initialValue])

//简单示例
arr.reduce(function (previousValue, item, index, Array) {
    return xxx;    //xxx表示省略
});

// 扩展
if (!Array.prototype.reduce) {
    Array.prototype.reduce = function (callback, initialValue) {
        var previousValue = initialValue || this[0];//如果不指定intialValue,则默认为数组的第一个元素
        //如果不指定initialValue(即第二个参数),i从1(第二个元素)开始遍历,否则就从0(第一个元素)开始遍历
        for (var i = initialValue ? 0 : 1; i < this.length; i++) {
            //previousValue 累加每一次返回的结果
            if (this[i])
                previousValue = callback(previousValue, this[i], i, this.toString());
        }
        return previousValue;
    }
}

reduceRight 函数

//标准
reduceRight(callback[,initialValue])

//简单示例
arr.reduceRight(function (previousValue, item, index, Array) {
    return xxx;    //xxx表示省略
});
// 扩展
if (!Array.prototype.reduceRight) {
    Array.prototype.reduceRight = function (callback, initialValue) {
        var previousValue = initialValue || this[this.length - 1];//如果不指定intialValue,则默认为数组的第一个元素
        //如果不指定initialValue(即第二个参数),i从1(第二个元素)开始遍历,否则就从0(第一个元素)开始遍历
        for (var i = (initialValue ? this.length - 1 : this.length - 2); i > -1; i--) {
            //previousValue 累加每一次返回的结果
            if (this[i])
                previousValue = callback(previousValue, this[i], i, this);
        }
        return previousValue;
    }
}

every 函数

返回值是true或者false
初始情况下是true;
然后遍历数组,有一个不满足,则为false,并且终止遍历过程。
回调函数的this依然默认指向window,或者是every的第二个参数。

空数组的every返回结果是true。

//标准
every(callback, thisArg);

//简单示例
arr.every(function(item, index, array){
    return item > xx;
});

if (!Array.prototype.every) {
    Array.prototype.every = function (callback, thisArg) {
        var result = true;
        for (var i = 0; i < this.length; i++) {
            if (this[i]) {
                if (!callback.call(thisArg ? thisArg : window, this[i], i, this)) {
                    result = false;
                    break;
                }
            }
        }
        return result; //所有元素都符合条件,返回true
    }
}

indexOf 函数

用于查找第一个参数是否在数组中;
如果不在,返回-1;
如果在,返回在数组中遇见的第一个的下标;
例如:[1,2,3,2].indexOf(2)的返回值是1,虽然第二个和第四个元素都是,但是先遇见第二个,而第二个的下标是1

如果indexOf有第二个参数,那么从数组中第二个参数所指向的下标位置开始往后找;
例如:[1,2,3,2].indexOf(2,2)的返回值是3,因为开始下标是2(即第三个元素3),因此从第三个开始,遇见的第一个2的下标是2;
判断时含第二个参数所指向的数组元素

//标准
arr.indexOf(searchElement, fromIndex);

//简单示例
[1,2,3].indexOf(2);    //1(数组的第二个元素)
[1,2,3].indexOf(4);    //-1(未找到,注意,-1不是false,隐式转换后他的值为true)

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement, fromIndex) {
        var result = -1;
        for (var i = fromIndex ? fromIndex : 0; i < this.length; i++) {
            if (this[i]) {
                if (searchElement === this[i]) {
                    result = i;
                    break;
                }
            }
        }
        return result; //所有元素都符合条件,返回true
    }
}

lastIndexOf 函数

//标准
arr.lastIndexOf(searchElement, fromIndex);

//简单示例
[1,2,1].lastIndexOf(1);    //2
[1,2,1].lastIndexOf(1, 1);    //0

if (!Array.prototype.lastIndexOf) {
    Array.prototype.lastIndexOf = function (searchElement, fromIndex) {
        var result = -1;
        for (var i = (fromIndex ? fromIndex : this.length - 1); i > -1; i--) {
            if (this[i]) {
                if (searchElement === this[i]) {
                    result = i;
                    break;
                }
            }
        }
        return result; //所有元素都符合条件,返回true
    }
}

from 函数

Array.from() 从类数组对象或者可迭代对象中创建一个新的数组实例。

console.log(Array.from([1,2,3],x=>x*x)); // 2,4,9

Array.isArray() 用来判断某个变量是否是一个数组对象。

console.log(Array.isArray(Array.from([1,2,3]))); // true

Array.of() 根据一组参数来创建新的数组实例,支持任意的参数数量和类型。

console.log(Array.of(1, 2, 3));// [1,2,3]

concat 函数

连接两个或更多的数组,并返回结果

var arr = [ 1, 2, 3 ];
var arr2= arr.concat("4", "5", "6");   //["1", "2", "3", "4", "5", "6"];

join 函数

把数组的所有元素放入一个字符串并通过指定的分隔符进行分隔

arr.join("+");   //"1+2+3";

reverse 函数

反转数组中元素的顺序。

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

sort 函数

数组排序 按照字符串的方式来排序。

toString 函数

把数组转换为字符串,并返回结果

find 函数

返回传入一个测试条件,符合条件的数组第一个元素,当数组中的元素在测试条件时返回true时, find() 返回符合条件的元素,之后的值不会再调用执行函数。如果没有符合条件的元素返回 undefined

const pets = [
  { type: 'Dog', name: 'Max'},
  { type: 'Cat', name: 'Karl'},
  { type: 'Dog', name: 'Tommy'},
];

var pet = pets.find(pet => pet.type ==='Dog' && pet.name === 'Tommy');
console.log(pet); // { type: 'Dog', name: 'Tommy' }

some 函数

用于检测数组中的元素是否满足指定条件,如果有一个元素满足条件,则表达式返回true, 剩余的元素不会再执行检测,如果没有满足条件的元素,则返回false。

let arr = [1, 2, 3, 4, 5]
console.log(arr.some(item => item === 2)); // true

// ES5循环实现 some 方法
const selfSome = function (fn, context) {
    let arr = Array.prototype.slice.call(this) // 复制数组原型对象
    // 空数组直接返回 false,数组的 every 方法则相反返回 true
    if(!arr.length) return false
    for (let i = 0; i < arr.length; i++) {
        if(!arr.hasOwnProperty(i)) continue;
        let res = fn.call(context,arr[i],i,this)
        if(res)return true
    }
    return false
}
// 挂载
Array.prototype.selfSome ||(Object.defineProperty(Array.prototype, 'selfSome', {
    value: selfSome,
    enumerable: false,
    configurable: true,
    writable: true
}))

console.log(arr.selfSome(item => item === 2)) // true

数组与字符串转换

var arr = ['wxh','cjk','dbt','cjk']
console.log(arr.join(",")) // 以 逗号 进行分割
Array.from(new Set(arr)) // ['wxh','cjk','dbt']  // 数组去重

var str = "wxh,cjk,dbt"
console.log(str.split(","))
console.log(Array.from(str)) // ['w', 'x', 'h', ',',....]

数组与对象转换

let arrayLike = {
'0': 'wxh',
'1': 'cjk',
'2': 'dbt',
length: 3
};
// ES5 的写法
var arr1 = [].slice.call(arrayLike); // ['wxh', 'cjk', 'dbt']

// ES6 的写法
let arr2 = Array.from(arrayLike); // ['wxh', 'cjk', 'dbt']

// NodeList 对象
let arr3 = document.querySelectorAll('p');
Array.from(arr3).forEach(function (item) {
  console.log(item);
});

// arguments 对象
function foo() {
  var args = Array.from(arguments);

}

learningCoder
42 声望1 粉丝