javascript基础之-[数组]

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);

}

你可能感兴趣的