数组Api太多记不住?那就24个api全部手写一遍吧!!!要是还不行,咱就吃海参!!!

355 阅读46分钟

2022从手写数组Api开启新的一年

广大前端好儿女,苦数组Api久矣。

2022的此时此刻,彻彻底底拿下它。

1、unshift(在数组开头插入元素,并返回新的长度)

现在,我们希望在数组中插入一个新元素(数1),不像之前那样插入到最后,而是放到数组的开头。为了实现这个需求,首先要腾出数组里第一个元素的位置,把所有的元素向右移动一位。我们可以循环数组中的元素,从最后一位(长度值就是数组的末尾位置)开始,将对应的前一个元素(i-1)的值赋给它(i),依次处理,最后把我们想要的值赋给第一个位置(索引 0)上。我们可以将这段逻辑写成一个函数,甚至将该方法直接添加在 Array 的原型上,使所有数组的实例都可以访问到该方法。下面的代码表现了这段逻辑。

原生实现

单个参数:

​
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 
Array.prototype.insertFirstPosition = function(value) { 
 for (let i = this.length; i >= 0; i--) { 
 this[i] = this[i - 1]; 
 } 
 this[0] = value; 
}; 
numbers.insertFirstPosition(-1); 

下图描述了我们刚才的操作过程。

image-20220119101209826

多个参数:

//myUnshift 数组入队
Array.prototype.myUnshift = function(){
    var L = this.length;
    for(var i = L + arguments.length - 1 ; i >= 0 ; i--){
        if(i > arguments.length - 1){
            this[i] = this[i - arguments.length];
        }else{
            this[i] = arguments[i];
        }
    }
    return this.length;
}    
​
var arr = [1,2,3,4,5,6]
​
arr.myUnshift(-2,-3)
arr //[-2, -3, 1, 2, 3, 4, 5, 6]

unshift 使用

定义和用法

unshift() 方法将新项添加到数组的开头,并返回新的长度。

注释: unshift() 方法会改变数组的长度。

提示: 如需在数组末尾添加新项,请使用 push() 方法。

使用 unshift 方法 在 JavaScript 里,数组有一个方法叫 unshift,可以直接把数值插入数组的开头(此方法背后的逻辑和 insertFirstPosition 方法的行为是一样的)。 numbers.unshift(-2); numbers.unshift(-4, -3);

那么,用 unshift 方法,我们就可以在数组的开始处添加值-2,然后添加-3、-4 等。这样数组就会输出数-4 到 9。

[-4, -3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

参考文章:

1、www.w3school.com.cn/jsref/jsref…

2、blog.csdn.net/weixin_3419…

2、shift(数组开头删除第一个元素,并返回该删除的元素)

shift使用

定义和用法

shift() 方法移除数组的第一项,如果数组为空返回undefined。

注释: shift() 方法会改变数组的长度。

注释: shift 方法的返回值是被移除的项目。

注释: shift() 方法会改变原始数组。

提示: 如需删除数组的最后一项,请使用 pop() 方法。

注意点:

返回值

从数组中移除的元素;undefined如果数组为空。

案例:

Array.shift() 返回被移除的数组元素:
​
const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.shift();   // 返回 "Banana"

原生实现

//myShift()数组出队
Array.prototype.myShift = function(){
    if (this.length == 0) {
        return undefined;
    }
    var firstElement = this[0];
    for(var i = 1 ; i < this.length ; i++){
        this[i-1] = this[i];
    }
    this.length = this.length-1;
    return firstElement;
}
​
var arr = [1,2,3,4,5,6,0]
var firstElement = arr.myShift() //1
  • 还有一种思路,看看就行,上面一种掌握就ok。

在这里插入图片描述

我们把数组里所有的元素都左移了一位,但数组的长度依然是 17,这意味着数组中有额外50 第 3 章 数组的一个元素(值是 undefined)。在最后一次循环里,i+1 引用了数组里还未初始化的一个位置。 在 Java、C/C+或 C#等一些语言里,这样写可能会抛出异常,因此不得不在 numbers.length- 1处停止循环。 可以看到,我们只是把数组第一位的值用第二位覆盖了,并没有删除元素(因为数组的长度和之前还是一样的,并且多了一个未定义元素)。 要从数组中移除这个值,还可以创建一个包含刚才所讨论逻辑的方法,叫作 removeFirstPosition。但是,要真正从数组中移除这个元素,我们需要创建一个新的数组,将所有不是undefined 的值从原来的数组复制到新的数组中,并且将这个新的数组赋值给我们的数组。要完成这项工作,也可以像下面这样创建一个 reIndex 方法。

在这里插入图片描述

Array.prototype.reIndex = function(myArray) { 
 const newArray = []; 
 for(let i = 0; i < myArray.length; i++ ) { 
 if (myArray[i] !== undefined) { 
 // console.log(myArray[i]); 
 newArray.push(myArray[i]); 
 } 
 } 
 return newArray; 
} 
// 手动移除第一个元素并重新排序
Array.prototype.removeFirstPosition = function() { 
 for (let i = 0; i < this.length; i++) { 
 this[i] = this[i + 1]; 
 } 
 return this.reIndex(this); 
}; 
numbers = numbers.removeFirstPosition(); 

参考文章:

1、www.w3school.com.cn/jsref/jsref…

2、developer.mozilla.org/en-US/docs/…

3、blog.csdn.net/weixin_3419…

3、pop(移除数组中的一个元素(默认最后一个元素),并且返回该元素的值)

定义和用法

定义和用法

pop() 方法移除数组的最后一个元素,并返回该元素。

注释: pop() 方法会改变数组的长度。

提示: 如需删除数组的第一个元素,请使用 shift() 方法。

案例:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.pop(); //"Mango"

原生实现

//Mypop() 数组出栈
Array.prototype.myPop = function(){
    if (this.length == 0) {
        return undefined;
    }
    var last = this[this.length-1];
    this.length = this.length-1;
    return last;
}

参考文章

1、www.w3school.com.cn/jsref/jsref…

2、blog.csdn.net/weixin_3419…

4、push(数组末尾添加新项目,并返回新长度)

定义和用法

push() 方法向数组末尾添加新项目,并返回新长度。

提示: 新的项目将被添加到数组的末尾。

注释: push() 方法会改变数组的长度。

提示: 如需在数组的开头添加项目,请使用 unshift() 方法。

案例:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi"); //5

原生实现

//myPush() 数组入栈
Array.prototype.myPush = function(){
    var L = this.length;
    for(var i = L ; i < L + arguments.length ; i++){
        this[i] = arguments[i - L];
    }
    return this.length;
}

参考文章:

1、www.w3school.com.cn/jsref/jsref…

2、blog.csdn.net/weixin_3419…

小总结:

1、unshift前插入、push后插入返回数组长度

2、shift前删除、pop后删除返回该删除的元素值

5、splice(改变原始数组,返回删除的项目)

定义和用法

定义和用法

splice() 方法向/从数组添加/删除项目,并返回删除的项目。

注释: splice() 方法会改变原始数组。

语法

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

案例:

const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "June"]
​
months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "May"]
​

原生实现

    Array.prototype.splice2 = function(start, num){
        const newAdd = [].slice.call(arguments, 2); // 新增项
        if (start < 0) {
            start = this.length + start;
            if(start < 0) start = 0;
        }
​
        let end;
        if (num <= 0) {
            end = start;
        } else if (!num) {
            end = this.length;
        } else {
            end = start + num;
            if(end > this.length) end = this.length;
        }
​
        let returnRrr = [];   // 截取项 == 返回值
        let beforeArr = [];   // 截取部分之前的
        let afterArr = [];    // 截取部分之后的
        for (let i = 0; i < this.length; i++) {
            if (i < start ) {
                beforeArr.push(this[i])
            }
            if (i + 1 > end) {
                afterArr.push(this[i])
            }
            if(i >= start && i < end){
                returnRrr.push(this[i])
            }
        }
        this.length = 0;
        [...beforeArr,...newAdd,...afterArr].forEach((item,idx) => this[idx] = item);
        return returnRrr
    }
​
​

参考文章:

1、blog.csdn.net/weixin_4352…

2、www.w3school.com.cn/jsref/jsref…

3、developer.mozilla.org/zh-CN/docs/…

4、juejin.cn/post/702390…

6、slice(不会改变原始数组,返回数组中被选中的元素)

定义和用法

定义和用法

slice() 方法以新的数组对象,返回数组中被选中的元素。

slice() 方法选择从给定的 start 参数开始的元素,并在给定的 end 参数处结束,但不包括。

注释: slice() 方法不会改变原始数组。

实例

从数组中选择元素:

var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1, 3);//['Orange', 'Lemon']

原生实现

    /**
    * 封装 slice
    * 思路:先考虑清楚start,end的边界情况,得到最终start,end值,然    * 后循环遍历得到新数组
    */
Array.prototype.mySlice = function(start, end) {
​
    let sIdx;
    let eIdx;
    if (start !== 0 && start) {
      
        sIdx = start > 0 ? start : this.length + start;
        console.log(sIdx,'sIdx')
    }else{
        sIdx = 0
    }
​
    //end不传值情况需要特别注意
    if (end !== 0 && end) {
        eIdx = end > 0 ? end : this.length + end;
        console.log(eIdx,'eIdx')
    }else if(end == 0 ){
        eIdx = 0
    }else {
        eIdx = this.length
    }
​
     // 声明一个空数组
     const result = [];
​
     // 遍历对象 可以优化,方法很多的
    for(let i=sIdx;i<eIdx;i++) {
   
      // 将下标对应的元素压入数组,if判断是为了去除多余的undefined的值
      if(arr[i]) {
        result.push(arr[i]);
      }
      
    }
​
    return result;
​
}
​
var arr = [1,3,4,52,2,8];
arr.mySlice(1,3)
arr.mySlice(1,0)
arr.mySlice(1,12)
arr.mySlice(1)
arr.mySlice(-2,-1)
arr.mySlice()

参考文章:

1、www.w3school.com.cn/jsref/jsref…

2、developer.mozilla.org/zh-CN/docs/…

3、developer.mozilla.org/zh-CN/docs/…

4、blog.csdn.net/weixin_4352…

5、blog.csdn.net/weixin_4261…

7、concat(连接两个或多个数组,不会更改现有数组,而是返回一个新数组)

定义和用法

定义和用法

concat() 方法用于连接两个或多个数组。

concat() 方法不会更改现有数组,而是返回一个新数组,其中包含已连接数组的值。

实例

连接两个数组:

var sedan = ["S60", "S90"];
var SUV = ["XC40", "XC60", "XC90"];
var Volvo = sedan.concat(SUV);

原生实现

function concat (arr, ...args) {
    // 声明一个空数组
    const result = [...arr];
    // 遍历数组
    args.forEach(item => {
      // 判断 item 是否为数组
      if (Array.isArray(item)) {
        result.push(...item);
      } else {
        result.push(item);
      }
    });
    // 返回 result
    return result;
  }
​
// 数组合并
let arr = [1,2,3];
const result = arr.concat([4,5,6], 7,8);
console.log(result);
const result = concat(arr, [4,5,6], 7,8,[9,10]);

参考文章:

1、www.w3school.com.cn/jsref/jsref…

2、blog.csdn.net/weixin_4261…

3、developer.mozilla.org/zh-CN/docs/…

8、遍历数组-foreach(按顺序为数组中的每个元素调用一次函数)

定义和用法

定义和用法

forEach() 方法按顺序为数组中的每个元素调用一次函数。

注释: 对于没有值的数组元素,不执行forEach() 方法。

语法

arr.forEach(callback(currentValue [, index [, array]])[, thisArg])

参数

  • callback

    为数组中每个元素执行的函数,该函数接收一至三个参数:

    currentValue数组中正在处理的当前元素。index 可选数组中正在处理的当前元素的索引。array 可选forEach() 方法正在操作的数组。

  • thisArg 可选

    可选参数。当执行回调函数 callback 时,用作 this 的值。

返回值

undefined

描述

forEach() 方法按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。

可依次向 callback 函数传入三个参数:

  1. 数组当前项的值
  2. 数组当前项的索引
  3. 数组对象本身

如果 thisArg 参数有值,则每次 callback 函数被调用时,this 都会指向 thisArg 参数。如果省略了 thisArg 参数,或者其值为 nullundefinedthis 则指向全局对象。按照函数观察到 this 的常用规则callback 函数最终可观察到 this 值。

forEach() 遍历的范围在第一次调用 callback 前就会确定。调用 forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach() 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()),之后的元素将被跳过——参见下面的示例

forEach() 为每个数组元素执行一次 callback 函数;与 map() 或者 reduce() 不同的是,它总是返回 undefined 值,并且不可链式调用。其典型用例是在一个调用链的最后执行副作用(side effects,函数式编程上,指函数进行 返回结果值 以外的操作)。

forEach() 被调用时,不会改变原数组,也就是调用它的数组(尽管 callback 函数在被调用时可能会改变原数组)。(译注:此处说法可能不够明确,具体可参考EMCA语言规范:'forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.',即 forEach 不会直接改变调用它的对象,但是那个对象可能会被 callback 函数改变。)

//案例
const array1 = ['a', 'b', 'c'];
array1.forEach(element => console.log(element));
// expected output: "a"
// expected output: "b"
// expected output: "c"
​
​
var fruits = ["apple", "orange", "cherry"];
fruits.forEach(myFunction);
​
function myFunction(item, index) {
document.getElementById("demo").innerHTML += index + ":" + item + "<br>"; 
}

原生实现

实现一个forEach方法

forEach()方法对数组的每个元素执行一次给定的函数

arr.forEach(function(currentValue, currentIndex, arr) {}, thisArg)

//currentValue 必需。当前元素 //currentIndex 可选。当前元素的索引 //arr 可选。当前元素所属的数组对象。 //thisArg 可选参数。当执行回调函数时,用作 this 的值。

//看这个方法之前,建议大家先搞明白不同情况下,this代表什么
//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
Array.prototype._forEach = function(fn, thisArg) {
    if (typeof fn !== 'function') throw "参数必须为函数";
    if(!Array.isArray(this)) throw "只能对数组使用forEach方法";
    let arr = this; //数组调用的_forEach函数,那函数里面的this就是该数组
    for(let i=0; i<arr.length; i++) {
        fn.call(thisArg, arr[i], i, arr) //如果thisArg没有传参,那fn里面的this就是windows
    }
}
​
​
//下面是测试案例
// test
let arr = [1,2,3,4,5];
arr._forEach((item, index) => {
    console.log(item, index);
})
​
// test thisArg
function Counter() {
    this.sum = 0;
    this.count = 0;
}
// 因为 thisArg 参数(this)传给了 forEach(),每次调用时,它都被传给 callback 函数,作为它的 this 值。
Counter.prototype.add = function (array) {
    //add函数里面的this,就是obj调用add函数时候,obj自己,就是this。别问为什么,问了,       
    //就去看看this指向的知识点。
    array._forEach(function (entry) {
        this.sum += entry;
        ++this.count;
    }, this);
      // ^---- Note
};
​
const obj = new Counter();
obj.add([2, 5, 9]);
​
console.log(obj.count); // 3 === (1 + 1 + 1)
console.log(obj.sum);  // 16 === (2 + 5 + 9)

参考文章:

1、Array.prototype.forEach():developer.mozilla.org/zh-CN/docs/…

2、实现一个forEach方法:segmentfault.com/a/119000002…

3、JavaScript Array forEach() 方法:www.w3school.com.cn/jsref/jsref…

9、map(返回执行回调函数的结果组成的新数组,不改变原数组)

定义和用法

map不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)

定义和用法

map() 方法使用为每个数组元素调用函数的结果创建新数组。

map() 方法按顺序为数组中的每个元素调用一次提供的函数。

注释: map() 对没有值的数组元素不执行函数。

注释: map() 不会改变原始数组。

语法

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array 
}[, thisArg])

参数

  • callback

    生成新数组元素的函数,使用三个参数:currentValue``callback 数组中正在处理的当前元素。index可选callback 数组中正在处理的当前元素的索引。array可选map 方法调用的数组。

  • thisArg可选

    执行 callback 函数时值被用作this

返回值

一个由原数组每个元素执行回调函数的结果组成的新数组。

描述

map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。

因为map生成一个新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,请用forEach或者for-of替代。你不该使用map: A)你不打算使用返回的新数组,或/且 B) 你没有从回调函数中返回值。

callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身。

如果 thisArg 参数提供给map,则会被用作回调函数的this值。否则undefined会被用作回调函数的this值。this的值最终相对于callback函数的可观察性是依据the usual rules for determining the this seen by a function决定的

map不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)

注意点:map 方法处理数组元素的范围是在 callback 方法第一次调用之前就已经确定了。调用map方法之后追加的数组元素不会被callback访问。如果存在的数组元素改变了,那么传给callback的值是map访问该元素时的值。在map函数调用后但在访问该元素前,该元素被删除的话,则无法被访问到。

根据规范中定义的算法,如果被map调用的数组是离散的,新数组将也是离散的保持相同的索引为空。

案例:

const array1 = [1, 4, 9, 16];
​
// pass a function to map
const map1 = array1.map(x => x * 2);
​
console.log(map1);
console.log( array1)
// expected output: Array [2, 8, 18, 32]

原生实现

/**
 * 
 * @param {*} callback 
 * @param {*} thisArg 
 * @returns 
 */
Array.prototype.map = function(callback, thisArg) {
    if (this == undefined) {
      throw new TypeError('this is null or not defined');
    }
    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function');
    }
    const res = [];
    // 让O成为回调函数的对象传递(强制转换对象)
    const O = Object(this);
    //js中 something >>> 0是什么意思? https://zhuanlan.zhihu.com/p/100790268
    const len = O.length >>> 0;
   
    for (let i = 0; i < len; i++) {
      if (i in O) {
        // 调用回调函数并传入新数组
        res[i] = callback.call(thisArg, O[i], i, this);
      }
    }
    return res;
  }
​
  
var array1 = [1, 4, 9, 16];
var map1 = array1.map(x => x * 2);

参考文章:

1、Array.prototype.map() developer.mozilla.org/zh-CN/docs/…

2、32个手写JS,巩固你的JS基础(面试高频)juejin.cn/post/687515…

3、js中 something >>> 0是什么意思? zhuanlan.zhihu.com/p/100790268

4、用reduce实现map segmentfault.com/a/119000002…

5、Object developer.mozilla.org/zh-CN/docs/…

10、filter(不会改变原数组,它返回过滤后的新数组。)

定义和用法

定义和用法

filter() 方法创建数组,其中填充了所有通过测试的数组元素(作为函数提供)。

注释: filter() 不会对没有值的数组元素执行该函数。

注释: filter() 不会改变原始数组。

语法

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])

参数

  • callback

    用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。它接受以下三个参数:

    element数组中当前正在处理的元素。index可选正在处理的元素在数组中的索引。array可选调用了 filter 的数组本身。

  • thisArg可选

    执行 callback 时,用于 this 的值。

返回值

一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

描述

filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。

callback 被调用时传入三个参数:

  1. 元素的值
  2. 元素的索引
  3. 被遍历的数组本身

如果为 filter 提供一个 thisArg 参数,则它会被作为 callback 被调用时的 this 值。否则,callbackthis 值在非严格模式下将是全局对象,严格模式下为 undefinedcallback 函数最终观察到的 this 值是根据通常函数所看到的 "this"的规则确定的。

filter 不会改变原数组,它返回过滤后的新数组。

filter 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。

案例:

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
​
const result = words.filter(word => word.length > 6);
​
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]

原生实现

Array.prototype.filter = function(callback, thisArg) {
    if (this == undefined) {
      throw new TypeError('this is null or not undefined');
    }
    if (typeof callback !== 'function') {
      throw new TypeError(callback + 'is not a function');
    }
    const res = [];
    // 让O成为回调函数的对象传递(强制转换对象)
    const O = Object(this);
    // >>>0 保证len为number,且为正整数
    const len = O.length >>> 0;
    for (let i = 0; i < len; i++) {
      // 检查i是否在O的属性(会检查原型链)
      if (i in O) {
        // 回调函数调用传参
        if (callback.call(thisArg, O[i], i, O)) {
          res.push(O[i]);
        }
      }
    }
    return res;
  }
  
  

或者

Array.prototype.sx_filter = function (callback) {
    const res = []
    for (let i = 0; i < this.length; i++) {
        callback(this[i], i, this) && res.push(this[i])
    }
    return res
}
​
console.log(players.sx_filter(item => item.num >= 23))
​

参考文章:

1、JavaScript Array filter() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.filter() developer.mozilla.org/zh-CN/docs/…

3、32个手写JS,巩固你的JS基础(面试高频)juejin.cn/post/687515…

4、史上最全!熬夜整理56个JavaScript高级的手写知识点!!专业扫盲! juejin.cn/post/702390…

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

定义和用法

定义和用法

reduce() 方法将数组缩减为单个值。

reduce() 方法为数组的每个值(从左到右)执行提供的函数。

函数的返回值存储在累加器中(结果/总计)。

注释: 对没有值的数组元素,不执行 reduce() 方法。

注释: reduce() 方法不会改变原始数组。

语法

arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

参数

  • callback

    执行数组中每个值 (如果没有提供 initialValue则第一个值除外)的函数,包含四个参数:

    **accumulator**累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。currentValue数组中正在处理的元素。index 可选数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。array可选调用reduce()的数组

  • initialValue可选

    作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

返回值

函数累计处理的结果

案例:

const array1 = [1, 2, 3, 4];
const reducer = (previousValue, currentValue) => previousValue + currentValue;
​
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

原生实现

Array.prototype.reduce = function(callback, initialValue) {
    if (this == undefined) {
      throw new TypeError('this is null or not defined');
    }
    if (typeof callback !== 'function') {
      throw new TypeError(callbackfn + ' is not a function');
    }
    const O = Object(this);
    const len = this.length >>> 0;
    let accumulator = initialValue;
    let k = 0;
    // 如果第二个参数为undefined的情况下
    // 则数组的第一个有效值作为累加器的初始值
    // 2.判断对象是否为数组/对象的元素/属性:
    // 格式:(变量 in 对象)......注意,,, https://www.cnblogs.com/lxg0/p/5671755.html
    if (accumulator === undefined) {
      while (k < len && !(k in O)) {
        k++;
      }
      // 如果超出数组界限还没有找到累加器的初始值,则TypeError
      //如果数组为空且没有提供initialValue,会抛出TypeError 。
      if (k >= len) {
        throw new TypeError('Reduce of empty array with no initial value');
      }
      accumulator = O[k++]; //这里k++,代表除开第一位有效值被当做initialValue,从有效值后一位开始循环执行callback函数
    }
    while (k < len) {
      if (k in O) {
        accumulator = callback.call(undefined, accumulator, O[k], k, O);
      }
      k++;
    }
    return accumulator;
  }
​

参考文章:

1、JavaScript Array reduce() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.reduce() developer.mozilla.org/zh-CN/docs/…

3、32个手写JS,巩固你的JS基础(面试高频)juejin.cn/post/687515…

12、every(检查数组中的所有元素是否都通过了测试,返回一个布尔值,不改变原始数组)

**every()** 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

定义和用法

定义和用法

every() 方法检查数组中的所有元素是否都通过了测试(被作为函数提供)。

every() 方法对数组中存在的每个元素执行一次函数:

  • 如果找到函数返回 false 值的数组元素,every() 返回 false(并且不检查剩余值)
  • 如果没有出现 false,every() 返回 true

注释: every() 不对没有值的数组元素执行函数。

注释: every() 不改变原始数组。

语法

arr.every(callback(element[, index[, array]])[, thisArg])

参数

  • callback

    用来测试每个元素的函数,它可以接收三个参数:element用于测试的当前值。index可选用于测试的当前值的索引。array可选调用 every 的当前数组。

  • thisArg

    执行 callback 时使用的 this 值。

返回值

如果回调函数的每一次返回都为 truthy 值,返回 **true** ,否则返回 **false**

描述

every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个会使 callback 返回 falsy 的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 trueevery 就会返回 truecallback 只会为那些已经被赋值的索引调用。不会为那些被删除或从未被赋值的索引调用。

callback 在被调用时可传入三个参数:元素值,元素的索引,原数组。

如果为 every 提供一个 thisArg 参数,则该参数为调用 callback 时的 this 值。如果省略该参数,则 callback 被调用时的 this 值,在非严格模式下为全局对象,在严格模式下传入 undefined。详见 this 条目。

every 不会改变原数组。

every 遍历的元素范围在第一次调用 callback 之前就已确定了。在调用 every 之后添加到数组中的元素不会被 callback 访问到。如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。

every 和数学中的"所有"类似,当所有的元素都符合条件才会返回true。正因如此,若传入一个空数组,无论如何都会返回 true。(这种情况属于无条件正确:正因为一个空集合没有元素,所以它其中的所有元素都符合给定的条件。)

案例:

一、
const isBelowThreshold = (currentValue) => currentValue < 40;
​
const array1 = [1, 30, 39, 29, 10, 13];
​
console.log(array1.every(isBelowThreshold));
// expected output: true
​
二、
function isBigEnough(element, index, array) {
  return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough);   // false
[12, 54, 18, 130, 44].every(isBigEnough); // true
​
​

原生实现

if (!Array.prototype.every) {
    Array.prototype.every = function(callbackfn, thisArg) {
      'use strict';
      var T, k;
  
      if (this == null) {
        throw new TypeError('this is null or not defined');
      }
  
      // 1. Let O be the result of calling ToObject passing the this
      //    value as the argument.
      var O = Object(this);
  
      // 2. Let lenValue be the result of calling the Get internal method
      //    of O with the argument "length".
      // 3. Let len be ToUint32(lenValue).
      var len = O.length >>> 0;
  
      // 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
      if (typeof callbackfn !== 'function') {
        throw new TypeError();
      }
  
      // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
      if (arguments.length > 1) {
        T = thisArg;
      }
  
      // 6. Let k be 0.
      k = 0;
  
      // 7. Repeat, while k < len
      while (k < len) {
  
        var kValue;
  
        // a. Let Pk be ToString(k).
        //   This is implicit for LHS operands of the in operator
        // b. Let kPresent be the result of calling the HasProperty internal
        //    method of O with argument Pk.
        //   This step can be combined with c
        // c. If kPresent is true, then
        if (k in O) {
  
          // i. Let kValue be the result of calling the Get internal method
          //    of O with argument Pk.
          kValue = O[k];
  
          // ii. Let testResult be the result of calling the Call internal method
          //     of callbackfn with T as the this value and argument list
          //     containing kValue, k, and O.
          var testResult = callbackfn.call(T, kValue, k, O);
  
          // iii. If ToBoolean(testResult) is false, return false.
          if (!testResult) {
            return false;
          }
        }
        k++;
      }
      return true;
    };
  }
  

参考文章:

1、JavaScript Array every() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.every() developer.mozilla.org/zh-CN/docs/…

13、some(测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值)

定义和用法

**some()** 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。(并且不检查剩余值,不改变原始数组。)

定义和用法

some() 方法检查数组中的任何元素是否通过测试(作为函数提供)。

some() 方法对数组中存在的每个元素执行一次函数:

  • 如果找到函数返回真值的数组元素,some() 返回真(并且不检查剩余值)
  • 否则返回 false

注释: some() 对没有值的数组元素不执行函数。

注释: some() 不改变原始数组。

语法

arr.some(callback(element[, index[, array]])[, thisArg])

参数

  • callback

    用来测试每个元素的函数,接受三个参数:element数组中正在处理的元素。index 可选数组中正在处理的元素的索引值。array可选some()被调用的数组。

  • thisArg可选

    执行 callback 时使用的 this 值。

返回值

数组中有至少一个元素通过回调函数的测试就会返回**true**;所有元素都没有通过回调函数的测试返回值才会为false。

描述

some() 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some() 将会立即返回 true。否则,some() 返回 false

注意点:callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。

callback 被调用时传入三个参数:元素的值,元素的索引,被遍历的数组。

如果一个thisArg参数提供给some(),它将被用作调用的 callbackthis 值。否则, 它的 this value将是 undefinedthis的值最终通过callback来观察,根据 the usual rules for determining the this seen by a function的this判定规则来确定。

some() 被调用时不会改变数组。

some() 遍历的元素的范围在第一次调用 callback. 前就已经确定了。在调用 some() 后被添加到数组中的值不会被 callback 访问到。如果数组中存在且还未被访问到的元素被 callback 改变了,则其传递给 callback 的值是 some() 访问到它那一刻的值。已经被删除的元素不会被访问到。

案例:

下面的例子检测在数组中是否有元素大于 10。
​
function isBiggerThan10(element, index, array) {
  return element > 10;
}
​
[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

原生实现

// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
    Array.prototype.some = function(fun/*, thisArg*/) {
      'use strict';
  
      if (this == null) {
        throw new TypeError('Array.prototype.some called on null or undefined');
      }
  
      if (typeof fun !== 'function') {
        throw new TypeError();
      }
  
      var t = Object(this);
      var len = t.length >>> 0;
  
      //用 void 0 代替 undefined https://github.com/lessfish/underscore-analysis/issues/1
      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;  
​
      console.log(thisArg,'thisArg')  //undefined
      for (var i = 0; i < len; i++) {
        if (i in t && fun.call(thisArg, t[i], i, t)) {
          return true;
        }
      }
  
      return false;
    };
  }
​
  const array = [1, 2, 3, 4, 5];
​
//Test
// checks whether an element is even
const even = (element) => element % 2 === 0;
​
console.log(array.some(even));

参考文章:

1、JavaScript Array some() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.some() developer.mozilla.org/zh-CN/docs/…

3、用 void 0 代替 undefined github.com/lessfish/un…

14、find(方法返回数组中第一个通过测试的元素的值,不会改变数组)

**find()** 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined

定义和用法

定义和用法

find() 方法返回数组中第一个通过测试的元素的值(作为函数提供)。

find() 方法对数组中存在的每个元素执行一次函数:

  • 如果找到函数返回 true 值的数组元素,则 find() 返回该数组元素的值(并且不检查剩余值)
  • 否则返回 undefined

注释: find() 不对空数组执行该函数。

注释: find() 不会改变原始数组。

语法

arr.find(callback[, thisArg])

参数

  • callback

    在数组每一项上执行的函数,接收 3 个参数:element当前遍历到的元素。index可选当前遍历到的索引。array可选数组本身。

  • thisArg可选

    执行回调时用作this 的对象。

返回值

数组中第一个满足所提供测试函数的元素的值,否则返回 undefined

描述

find方法对数组中的每一项元素执行一次 callback 函数,直至有一个 callback 返回 true。当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回 undefined

注意点: callback函数会为数组中的每个索引调用即从 0length - 1,而不仅仅是那些被赋值的索引,这意味着对于稀疏数组来说,该方法的效率要低于那些只遍历有值的索引的方法。

callback函数带有3个参数:当前元素的值、当前元素的索引,以及数组本身。

如果提供了 thisArg参数,那么它将作为每次 callback函数执行时的this ,如果未提供,则使用 undefined

find方法不会改变数组。

在第一次调用 callback函数时会确定元素的索引范围,因此在 find方法开始执行之后添加到数组的新元素将不会被 callback函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍旧会被访问到,但是其值已经是undefined了。

案例:

const array1 = [5, 12, 8, 130, 44];
​
const found = array1.find(element => element > 10);
​
console.log(found);
// expected output: 12
​

原生实现

// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    value: function(predicate) {
     // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }
​
      var o = Object(this);
​
      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;
​
      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
​
      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];
​
      // 5. Let k be 0.
      var k = 0;
​
      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return kValue.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        // e. Increase k by 1.
        k++;
      }
​
      // 7. Return undefined.
      return undefined;
    }
  });
}

或者:

参数代表含义
​
item:遍历项
index:遍历项的索引
arr:数组本身
​
Array.prototype.sx_find = function (callback) {
    for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
            return this[i]
        }
    }
    return undefined
}
​
console.log(players.sx_find(item => item.name === '科比')) // { name: '科比', num: 24 }
console.log(players.sx_find(item => item.name === '安东尼')) // undefined

参考点:

1、稀疏数组

在一些后端语言中,如 C,数组内的值通常被分配在一系列连续的内存地址上,但是在 js 中,某些数组内存则不是连续的,所谓稀疏,顾名思义,不连续,存在一些空隙;

2、质数

质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

参考文章:

1、JavaScript Array find() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.find() developer.mozilla.org/zh-CN/docs/…

3、史上最全!熬夜整理56个JavaScript高级的手写知识点!!专业扫盲!juejin.cn/post/702390…

4、稀疏数组 knightyun.github.io/2019/08/02/…

15、findIndex(返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。)

**findIndex()**方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。

定义和用法

findIndex() 方法返回数组中通过测试的第一个元素的索引(作为函数提供)。

findIndex() 方法对数组中存在的每个元素执行一次函数:

  • 如果找到函数返回 true 值的数组元素,则 findIndex() 返回该数组元素的索引(并且不检查剩余值)
  • 否则返回 -1

注释: findIndex() 不会为没有值的数组元素执行函数。

注释: findIndex() 不会改变原始数组。

语法

arr.findIndex(callback[, thisArg])

参数

  • callback

    针对数组中的每个元素, 都会执行该回调函数, 执行时会自动传入下面三个参数:element当前元素。index当前元素的索引。array调用findIndex的数组。

  • thisArg

    可选。执行callback时作为this对象的值.

返回值

数组中通过提供测试函数的第一个元素的索引。否则,返回-1

描述

findIndex方法对数组中的每个数组索引0..length-1(包括)执行一次callback函数,直到找到一个callback函数返回真实值(强制为true)的值。如果找到这样的元素,findIndex会立即返回该元素的索引。如果回调从不返回真值,或者数组的length为0,则findIndex返回-1。

注意点:与某些其他数组方法(如Array#some)不同,在稀疏数组中,即使对于数组中不存在的条目的索引也会调用回调函数。

回调函数调用时有三个参数:元素的值,元素的索引,以及被遍历的数组。

如果一个 thisArg 参数被提供给 findIndex, 它将会被当作this使用在每次回调函数被调用的时候。如果没有被提供,将会使用undefined

findIndex不会修改所调用的数组。

在第一次调用callback函数时会确定元素的索引范围,因此在findIndex方法开始执行之后添加到数组的新元素将不会被callback函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍然会被访问到。

案例:

const array1 = [5, 12, 8, 130, 44];
​
const isLargeNumber = (element) => element > 13;
​
console.log(array1.findIndex(isLargeNumber));
// expected output: 3
​
​
//或者
//查找数组中首个质数元素的索引
//以下示例查找数组中素数的元素的索引(如果不存在素数,则返回-1)。function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}
​
console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2

15、lastIndexOf(在数组中搜索元素,从末尾开始,并返回其位置)

定义和用法

**lastIndexOf()** 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。

定义和用法

lastIndexOf() 方法在数组中搜索指定项目,并返回其位置。

搜索将从指定位置开始,如果未指定开始位置,则从末尾开始,并在数组的开头结束搜索。

如果未找到该项目,则 lastIndexOf() 方法返回 -1。

如果要搜索的项目不止一次出现,lastIndexOf() 方法将返回最后一次出现的位置。

提示: 如果要从头到尾搜索,使用 indexOf() 方法。

语法

arr.lastIndexOf(searchElement[, fromIndex])

参数

  • searchElement

    被查找的元素。

  • fromIndex 可选

    从此位置开始逆向查找。默认为数组的长度减 1(arr.length - 1),即整个数组都被查找。如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。

    返回值

    数组中该元素最后一次出现的索引,如未找到返回-1。

描述

lastIndexOf 使用严格相等(strict equality,即 ===)比较 searchElement 和数组中的元素。

案例:

const animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];
​
console.log(animals.lastIndexOf('Dodo'));
// expected output: 3
​
console.log(animals.lastIndexOf('Tiger'));
// expected output: 1
​
​
例子:查找所有元素
下例使用 lastIndexOf 查找到一个元素在数组中所有的索引(下标),并使用 push 将所有添加到另一个数组中。
​
var indices = [];
var array = ['a', 'b', 'a', 'c', 'a', 'd'];
var element = 'a';
var idx = array.lastIndexOf(element);
​
while (idx != -1) {
  indices.push(idx);
  idx = (idx > 0 ? array.lastIndexOf(element, idx - 1) : -1);
}
​
console.log(indices);
// [4, 2, 0];

原生实现

if (!Array.prototype.lastIndexOf) {
    Array.prototype.lastIndexOf2 = function (searchElement /*, fromIndex*/) {
        'use strict';
​
        if (this === void 0 || this === null) {
            throw new TypeError();
        }
​
        var n, k,
            t = Object(this), //数组
            len = t.length >>> 0; //数组长度
        if (len === 0) {
            return -1;
        }
​
        n = len - 1;  //默认数组最后一位索引
        //有fromIndex传参情况下
        if (arguments.length > 1) {
            n = Number(arguments[1]);   // 这里n重新赋值,有fromIndex传参情况下,n就是fromIndex
            if (n != n) {
                n = 0;
            }
            else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {  //  1/0  Infinity
                //Math.abs(x) 函数返回指定数字 “x“ 的绝对值    可以理解 Math.floor()为向下取整
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
​
        // console.log(len - Math.abs(n),'-100情况下')
        // 从此位置开始逆向查找。默认为数组的长度减 1(arr.length - 1),即整个数组都被查找。如果该值大于或等于数组的长度,
        // 则整个数组 如果为负值,将其视为从数组末尾向前的偏移。
        // 即使该值为负,数组仍然会被从后向前查找。
        // 如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
        for (k = n >= 0
            ? Math.min(n, len - 1)
            : len - Math.abs(n); k >= 0; k--) {
            console.log(k, 'k')
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
​
        return -1;
    };
}
​
//   另外,该实现是为了绝对兼容 Firefox 和 the SpiderMonkey JavaScript 引擎中的 lastIndexOf,包括了几种临界情况。
//   如果你要在实际应用中使用该实现,可以忽略这些临界情况,从而简化 fromIndex 的计算。var animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];
​
console.log(animals.lastIndexOf2('Dodo', -100));
​

参考文章:

1、JavaScript Array lastIndexOf() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.lastIndexOf() developer.mozilla.org/zh-CN/docs/…

3、Math.min() developer.mozilla.org/en-US/docs/…

4、Math.floor() developer.mozilla.org/zh-CN/docs/…

5、Math.abs() developer.mozilla.org/zh-CN/docs/…

16、indexOf(在数组中搜索元素,从末尾开始,并返回其位置)

**indexOf()**方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。

定义和用法

定义和用法

indexOf() 方法在数组中搜索指定项目,并返回其位置。

搜索将从指定位置开始,如果未指定开始位置,则从头开始,并在数组末尾结束搜索。

如果未找到该项目,则 indexOf() 返回 -1。

如果该项目出现多次,则 indexOf() 方法返回第一次出现的位置。

注释: 第一项的位置为 0,第二项的位置为 1,依此类推。

提示: 如果您想从尾到头搜索,请使用 lastIndexOf() 方法。

语法

arr.indexOf(searchElement[, fromIndex])

参数

  • searchElement

    要查找的元素

  • fromIndex 可选

    开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找 ,以此类推。 注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组。如果抵消后的索引值仍小于0,则整个数组都将会被查询。其默认值为0.

返回值

首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1

案例:

const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
​
console.log(beasts.indexOf('bison'));
// expected output: 1
​
// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4
​
console.log(beasts.indexOf('giraffe'));
// expected output: -1
​
或者
找出指定元素出现的所有位置
var indices = [];
var array = ['a', 'b', 'a', 'c', 'a', 'd'];
var element = 'a';
var idx = array.indexOf(element);
while (idx != -1) {
  indices.push(idx);
  idx = array.indexOf(element, idx + 1);
}
console.log(indices);
// [0, 2, 4]

原生实现

// Production steps of ECMA-262, Edition 5, 15.4.4.14
// Reference: http://es5.github.io/#x15.4.4.14
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(searchElement, fromIndex) {
  
      var k;
  
      // 1. Let O be the result of calling ToObject passing
      //    the this value as the argument.
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }
  
      var O = Object(this);
  
      // 2. Let lenValue be the result of calling the Get
      //    internal method of O with the argument "length".
      // 3. Let len be ToUint32(lenValue).
      var len = O.length >>> 0;
  
      // 4. If len is 0, return -1.
      if (len === 0) {
        return -1;
      }
  
      // 5. If argument fromIndex was passed let n be
      //    ToInteger(fromIndex); else let n be 0.
      var n = +fromIndex || 0;
  
      if (Math.abs(n) === Infinity) {
        n = 0;
      }
  
      // 6. If n >= len, return -1.
      if (n >= len) {
        return -1;
      }
  
      // 7. If n >= 0, then Let k be n.
      // 8. Else, n<0, Let k be len - abs(n).
      //    If k is less than 0, then let k be 0.
      k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
  
      // 9. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ToString(k).
        //   This is implicit for LHS operands of the in operator
        // b. Let kPresent be the result of calling the
        //    HasProperty internal method of O with argument Pk.
        //   This step can be combined with c
        // c. If kPresent is true, then
        //    i.  Let elementK be the result of calling the Get
        //        internal method of O with the argument ToString(k).
        //   ii.  Let same be the result of applying the
        //        Strict Equality Comparison Algorithm to
        //        searchElement and elementK.
        //  iii.  If same is true, return k.
        if (k in O && O[k] === searchElement) {
          return k;
        }
        k++;
      }
      return -1;
    };
  }
  
  
  或者
 /**
 * Array实现: 循环遍历
 *
 * @param {*} arr
 * @param {*} searchVal
 * @param {number} [fromIndex=0]
 * @returns
 */
function aIndexOf(arr, searchVal, fromIndex = 0) {
  const len = arr.length;
  if (fromIndex < 0) fromIndex += len
  if (fromIndex >= len) return -1
  for (let i = fromIndex; i < len; i++) {
    if (arr[i] === searchVal) return i
  }
  return -1
}

参考文章:

1、JavaScript Array indexOf() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.indexOf() developer.mozilla.org/zh-CN/docs/…

3、(建议收藏)手写实现搞一搞:indexOf()知多少 zhuanlan.zhihu.com/p/377910028

17、includes( 检查数组是否包含指定的元素)

定义和用法

**includes()** 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false

定义和用法

includes() 方法确定数组是否包含指定的元素。

如果数组包含元素,则此方法返回 true,否则返回 false。

注释: includes() 方法区分大小写。

语法

arr.includes(valueToFind[, fromIndex])

参数

  • valueToFind

    需要查找的元素值。Note: 使用 includes()比较字符串和字符时是区分大小写的。

  • fromIndex 可选

    fromIndex 索引处开始查找 valueToFind。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜 (即使从末尾开始往前跳 fromIndex 的绝对值个索引,然后往后搜寻)。默认为 0。

返回值

返回一个布尔值 Boolean 。 ]如果在数组中(或 fromIndex 指定的范围中)找到了 valueToFind,则返回 true,否则返回 false

0 的值将全部视为相等,与符号无关(即 -0 与 0 和 +0 相等),但 false 不被认为与 0 相等。

Note: 技术上来讲,includes() 使用 零值相等 算法来确定是否找到给定的元素。

案例:

const array1 = [1, 2, 3];
​
console.log(array1.includes(2));
// expected output: true
​
const pets = ['cat', 'dog', 'bat'];
​
console.log(pets.includes('cat'));
// expected output: true
​
console.log(pets.includes('at'));
// expected output: false

原生实现

// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
    Object.defineProperty(Array.prototype, 'includes', {
      value: function(valueToFind, fromIndex) {
  
        if (this == null) {
          throw new TypeError('"this" is null or not defined');
        }
  
        // 1. Let O be ? ToObject(this value).
        var o = Object(this);
  
        // 2. Let len be ? ToLength(? Get(O, "length")).
        var len = o.length >>> 0;
  
        // 3. If len is 0, return false.
        if (len === 0) {
          return false;
        }
  
        // 4. Let n be ? ToInteger(fromIndex).
        //    (If fromIndex is undefined, this step produces the value 0.)
        var n = fromIndex | 0;
  
        // 5. If n ≥ 0, then
        //  a. Let k be n.
        // 6. Else n < 0,
        //  a. Let k be len + n.
        //  b. If k < 0, let k be 0.
        var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
  
        //NaN是特殊情况
        function sameValueZero(x, y) {
          return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
        }
  
        // 7. Repeat, while k < len
        while (k < len) {
          // a. Let elementK be the result of ? Get(O, ! ToString(k)).
          // b. If SameValueZero(valueToFind, elementK) is true, return true.
          if (sameValueZero(o[k], valueToFind)) {
            return true;
          }
          // c. Increase k by 1.
          k++;
        }
  
        // 8. Return false
        return false;
      }
    });
  }
  
  

或者

/**
 * includes()方法用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。
 * @param {*} searchElement  必须。需要查找的元素值。
 * @param {*} fromIndex 可选。从该索引处开始查找item。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜索。默认为 0。
 * @returns 
 */
Array.prototype.myIncludes = function (searchElement, fromIndex = 0) {
   
    //判断第二个参数是否为负数 
    if(fromIndex<0){
        fromIndex = this.length + fromIndex;
    }
    //循环判断是否找到查询元素
    for (var i = fromIndex; i < this.length; i++) {
        
        if (Object.is(this[i],searchElement)) {
            return true;
        }
    }
    //循环过后完全没匹配到
    return false;
​
}
//使用了Object.is()方法来解决了NaN的问题

参考文章:

1、JavaScript Array includes() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.includes() developer.mozilla.org/zh-CN/docs/…

3、数组方法之includes(写出我的myIncludes) blog.csdn.net/qq_41555854…

4、Object.is() developer.mozilla.org/zh-CN/docs/…

5、JavaScript 中的相等性判断 developer.mozilla.org/zh-CN/docs/…

18、from(从对象创建数组)

**Array.from()** 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。

定义和用法

from() 方法从具有 length 属性或可迭代对象的任何对象返回 Array 对象。

语法

Array.from(arrayLike[, mapFn[, thisArg]])

参数

  • arrayLike

    想要转换成数组的伪数组对象或可迭代对象。

  • mapFn 可选

    如果指定了该参数,新数组中的每个元素会执行该回调函数。

  • thisArg 可选

    可选参数,执行回调函数 mapFnthis 对象。

返回值

一个新的数组实例。

描述

Array.from() 可以通过以下方式来创建数组对象:

  • 伪数组对象(拥有一个 length 属性和若干索引属性的任意对象)
  • 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

Array.from() 方法有一个可选参数 mapFn,让你可以在最后生成的数组上再执行一次 map 方法后再返回。也就是说Array.from(obj, mapFn, thisArg)就相当于Array.from(obj).map(mapFn, thisArg), 除非创建的不是可用的中间数组。 这对一些数组的子类,typed arrays 来说很重要, 因为中间数组的值在调用 map() 时需要是适当的类型。

from()length 属性为 1 ,即 Array.from.length === 1

在 ES2015 中, Class 语法允许我们为内置类型(比如 Array)和自定义类新建子类(比如叫 SubArray)。这些子类也会继承父类的静态方法,比如 SubArray.from(),调用该方法后会返回子类 SubArray 的一个实例,而不是 Array 的实例。

案例:

console.log(Array.from('foo'));
// expected output: Array ["f", "o", "o"]console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]

原生实现

// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
    Array.from = (function () {
      var toStr = Object.prototype.toString;
      //判断参数是不是函数
      var isCallable = function (fn) {
        return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
      };
      var toInteger = function (value) {
        var number = Number(value);
        if (isNaN(number)) { return 0; }
        // 该全局 isFinite() 函数用来判断被传入的参数值是否为一个有限数值(finite number)。
        // 在必要情况下,参数会首先转为一个数值。
        if (number === 0 || !isFinite(number)) { return number; }
        return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
      };
​
      //Math.pow() 函数返回基数(base)的指数(exponent)次幂,即 baseexponent。
      var maxSafeInteger = Math.pow(2, 53) - 1;
      var toLength = function (value) {
        var len = toInteger(value);
        return Math.min(Math.max(len, 0), maxSafeInteger);
      };
  
      // The length property of the from method is 1.
      return function from(arrayLike/*, mapFn, thisArg */) {
        // 1. Let C be the this value.
        var C = this;
  
        // 2. Let items be ToObject(arrayLike).
        var items = Object(arrayLike);
  
        // 3. ReturnIfAbrupt(items).
        if (arrayLike == null) {
          throw new TypeError("Array.from requires an array-like object - not null or undefined");
        }
  
        // 4. If mapfn is undefined, then let mapping be false.
        var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
        var T;
        if (typeof mapFn !== 'undefined') {
          // 5. else
          // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
          if (!isCallable(mapFn)) {
            throw new TypeError('Array.from: when provided, the second argument must be a function');
          }
  
          // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
          if (arguments.length > 2) {
            T = arguments[2];
          }
        }
  
        // 10. Let lenValue be Get(items, "length").
        // 11. Let len be ToLength(lenValue).
        var len = toLength(items.length);
  
        // 13. If IsConstructor(C) is true, then
        // 13. a. Let A be the result of calling the [[Construct]] internal method
        // of C with an argument list containing the single item len.
        // 14. a. Else, Let A be ArrayCreate(len).
        var A = isCallable(C) ? Object(new C(len)) : new Array(len);
  
        // 16. Let k be 0.
        var k = 0;
        // 17. Repeat, while k < len… (also steps a - h)
        var kValue;
        while (k < len) {
          kValue = items[k];
          if (mapFn) {
            A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
          } else {
            A[k] = kValue;
          }
          k += 1;
        }
        // 18. Let putStatus be Put(A, "length", len, true).
        A.length = len;
        // 20. Return A.
        return A;
      };
    }());
  }
​

19、isArray( 检查对象是否为数组)

Array.isArray() 用于确定传递的值是否是一个 Array

定义和用法

定义和用法

isArray() 方法确定对象是否为数组。

如果对象是数组,则此函数返回 true,否则返回 false。

语法

Array.isArray(obj)

参数

  • obj

    需要检测的值。

返回值

如果值是 Array,则为true; 否则为false。

描述

如果对象是 Array ,则返回true,否则为false。

有关更多详细信息,请参阅文章严格判定JavaScript对象是否为数组

See the article “Determining with absolute accuracy whether or not a JavaScript object is an array” for more details. Given a TypedArray instance, false is always returned.

案例:

// 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array('a', 'b', 'c', 'd'))
// 鲜为人知的事实:其实 Array.prototype 也是一个数组。
Array.isArray(Array.prototype);
​
// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray(new Uint8Array(32))
Array.isArray({ __proto__: Array.prototype });

原生实现

if (!Array.isArray) {
    Array.isArray = function(arg) {
      return Object.prototype.toString.call(arg) === '[object Array]';
    };
  }

参考文章:

1、 JavaScript Array isArray() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.isArray() developer.mozilla.org/zh-CN/docs/…

3、手写数组的API www.cnblogs.com/yalong/p/11…

20、join( 将数组的所有元素连接成一个字符串)

**join()** 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

定义和用法

定义和用法

join() 方法将数组作为字符串返回。

元素将由指定的分隔符分隔。默认分隔符是逗号 (,)。

注释: join() 方法不会改变原始数组。

语法

arr.join([separator])

参数

  • separator 可选

    指定一个字符串来分隔数组的每个元素。如果需要,将分隔符转换为字符串。如果缺省该值,数组元素用逗号(,)分隔。如果separator是空字符串(""),则所有元素之间都没有任何字符。

  • 返回值

    一个所有数组元素连接的字符串。如果 arr.length 为0,则返回空字符串。

描述

所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。

如果一个元素为 undefinednull,它会被转换为空字符串。

案例:

示例
使用四种不同的分隔符连接数组元素
下例首先创建了一个数组 a,包含有三个元素,然后用四种不同的分隔符连接所有数组元素。首先是默认的分隔符逗号,然后是一个逗号加空格,接下来是一个加号前后加空格,最后是一个空字符串。
​
var a = ['Wind', 'Rain', 'Fire'];
var myVar1 = a.join();      // myVar1的值变为"Wind,Rain,Fire"
var myVar2 = a.join(', ');  // myVar2的值变为"Wind, Rain, Fire"
var myVar3 = a.join(' + '); // myVar3的值变为"Wind + Rain + Fire"
var myVar4 = a.join('');    // myVar4的值变为"WindRainFire"
​
​
连接类数组对象
下面的示例将连接类数组对象(arguments),通过在Array.prototype.join上调用Function.prototype.call。
​
function f(a, b, c) {
  var s = Array.prototype.join.call(arguments);
  console.log(s); // '1,a,true'
}
f(1, 'a', true);
​

原生实现

参考文章:

1、JavaScript Array join() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.join() developer.mozilla.org/zh-CN/docs/…

21、sort( 对数组的元素进行排序)

定义和用法

**sort()** 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的

由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。

语法

arr.sort([compareFunction])

参数

  • compareFunction 可选

    用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。firstEl第一个用于比较的元素。secondEl第二个用于比较的元素。

返回值

排序后的数组。请注意,数组已原地排序,并且不进行复制。

描述

如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 "Banana" 会被排列到 "cherry" 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 "80" 要比 "9" 要靠前。

如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
  • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。

所以,比较函数格式如下:

所以,比较函数格式如下:

function compare(a, b) {
if (a < b ) {           // 按某种排序标准进行比较, a 小于 b
 return -1;
}
if (a > b ) {
 return 1;
}
// a must be equal to b
return 0;
}

Copy to Clipboard

要比较数字而非字符串,比较函数可以简单的以 a 减 b,如下的函数将会将数组升序排列

function compareNumbers(a, b) {
return a - b;
}

案例:

示例
创建、显示及排序数组
下述示例创建了四个数组,并展示原数组。之后对数组进行排序。对比了数字数组分别指定与不指定比较函数的结果。
​
var stringArray = ["Blue", "Humpback", "Beluga"];
var numericStringArray = ["80", "9", "700"];
var numberArray = [40, 1, 5, 200];
var mixedNumericArray = ["80", "9", "700", 40, 1, 5, 200];
​
function compareNumbers(a, b)
{
  return a - b;
}
​
console.log('stringArray:' + stringArray.join());
console.log('Sorted:' + stringArray.sort());
​
console.log('numberArray:' + numberArray.join());
console.log('Sorted without a compare function:'+ numberArray.sort());
console.log('Sorted with compareNumbers:'+ numberArray.sort(compareNumbers));
​
console.log('numericStringArray:'+ numericStringArray.join());
console.log('Sorted without a compare function:'+ numericStringArray.sort());
console.log('Sorted with compareNumbers:'+ numericStringArray.sort(compareNumbers));
​
console.log('mixedNumericArray:'+ mixedNumericArray.join());
console.log('Sorted without a compare function:'+ mixedNumericArray.sort());
console.log('Sorted with compareNumbers:'+ mixedNumericArray.sort(compareNumbers));

原生实现

//简单实现
var arr = [7, 2, 6, 5, 9, 4, 3, 1, "c", "a", "b"]
​
function sort(a, orderBy = "asc") {
    let arrs = []
    let stringCode = []
    //将字符串和数字筛选出来并转成ASCII码
    for (let i of a) {
        if (typeof i !== "number" && typeof i === "string") {
            stringCode.push(i.charCodeAt())
            arrs.push(i.charCodeAt())
        } else if (typeof i === "number") {
            arrs.push(i)
        }
    }
    
    console.log(arrs,'arrs')  // [7, 2, 6, 5, 9, 4, 3, 1, 99, 
    97, 98] 'arrs'
 
    console.log(stringCode,'stringCode')   //[99, 97, 98] 'stringCode'
    //排序
    if (orderBy === "asc") {
        for (let i = 0; i < arrs.length; i++) {
            for (let g = i + 1; g < arrs.length; g++) {
                if (arrs[i] > arrs[g]) {
                    let a1 = JSON.parse(JSON.stringify(arrs[i])), 
                    b1 = JSON.parse(JSON.stringify(arrs[g]));
                    arrs[g] = a1;
                    arrs[i] = b1;
                }
            }
        }
    }else{
        for (let i = 0; i < arrs.length; i++) {
            for (let g = i + 1; g < arrs.length; g++) {
                if (arrs[i] < arrs[g]) {
                    let a1 = JSON.parse(JSON.stringify(arrs[i])), b1 = JSON.parse(JSON.stringify(arrs[g]));
                    arrs[g] = a1;
                    arrs[i] = b1;
                }
            }
        }
    }
​
    //把ASCII码转回字符串
    for (let v in arrs) {
        for (let c of stringCode) {
            if (arrs[v] === c) {
                arrs[v] = String.fromCharCode(arrs[v]);
            }
        }
    }
    return arrs
}
​
console.log(sort(arr,"desc"))
/*[
  'c', 'b', 'a', 9, 7,
  6,   5,   4,   3, 2,
  1
]
*/
​

img

简单手写js的Array.sort() blog.csdn.net/weixin_4206…

参考文章:

1、JavaScript Array sort() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.sort() developer.mozilla.org/zh-CN/docs/…

3、讲下 V8 sort 的大概思路,并手写一个 sort 的实现 zhuanlan.zhihu.com/p/371867327

4、简单手写js的Array.sort() blog.csdn.net/weixin_4206…

5、[算法总结] 十大排序算法 zhuanlan.zhihu.com/p/42586566

6、原生JS数组sort()排序方法内部原理探究 juejin.cn/post/684490…

22、reverse( 反转数组中元素的顺序,会改变原数组)

**everse()** 方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组

定义和用法

定义和用法

reverse() 方法反转数组中元素的顺序。

注释: reverse() 方法将改变原始数组。

语法

arr.reverse()

返回值

颠倒后的数组。

描述

reverse 方法颠倒数组中元素的位置,改变了数组,并返回该数组的引用。

reverse方法是特意类化的;此方法可被 calledapplied于类似数组对象。对象如果不包含反映一系列连续的、基于零的数值属性中的最后一个长度的属性,则该对象可能不会以任何有意义的方式运行。

案例:

示例
颠倒数组中的元素
下例将会创建一个数组 sourceArray,其包含三个元素,然后颠倒该数组。
​
 reverse() 的调用返回了一个颠倒后的数组 a的引用。
​
const a = [1, 2, 3];
​
console.log(a); // [1, 2, 3]a.reverse();
​
console.log(a); // [3, 2, 1]
颠倒类数组中的元素
下例创造了一个类数组对象 a, 包含3个元素和一个 length 属性, 然后颠倒这个类数组对象。  reverse() 的调用返回一个颠倒后的类数组对象 a的引用。
​
const a = {0: 1, 1: 2, 2: 3, length: 3};
​
console.log(a); // {0: 1, 1: 2, 2: 3, length: 3}
​
Array.prototype.reverse.call(a); //same syntax for using apply()
​
console.log(a); // {0: 3, 1: 2, 2: 1, length: 3}
​
​

原生实现

  var arr=[1,2,3,4,5];
    function reverse(myArr){
        var left=0;//存储左边第一个位置
        var right=arr.length-1;//存储右边最后一个位置
        while(left<right){//停止进行的条件
        var temp=myArr[left];//利用一个中间变量来交换位置
        myArr[left]=myArr[right];
        myArr[right]=temp;
        left++;
        right--;
    }
    reverse(arr);
    console.log(arr);//[5,4,3,2,1]
————————————————
版权声明:本文为CSDN博主「归零-li」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tozeroblog/article/details/82533206

参考文章:

1、JavaScript Array reverse() 方法 www.w3school.com.cn/jsref/jsref…

2、Array.prototype.reverse() developer.mozilla.org/zh-CN/docs/…

3、数据结构与算法——使用原生js实现js中自带的reverse()方法 blog.csdn.net/tozeroblog/…

23、flat(递归遍历数组,返回新数组)

**flat()** 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

定义和用法

语法

var newArray = arr.flat([depth])

参数

  • depth 可选

    指定要提取嵌套数组的结构深度,默认值为 1。

返回值

一个包含将数组与子数组中所有元素的新数组。

案例:

示例
扁平化嵌套数组
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
​
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
​
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
​
//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
扁平化与数组空项
flat() 方法会移除数组中的空项:
​
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]

原生实现

reduce + concat + isArray + recursivity
// 使用 reduce、concat 和递归展开无限多层嵌套的数组
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
​
function flatDeep(arr, d = 1) {
   return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
                : arr.slice();
};
​
flatDeep(arr1, Infinity);
flatDeep(arr1);
// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

参考文章:

1、Array.prototype.flat() developer.mozilla.org/zh-CN/docs/…

2、JavaScript基础:手写数组扁平化flat方法 blog.csdn.net/imagine_tio…

24、fill(用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引)

**fill()** 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。

定义和用法

语法

arr.fill(value[, start[, end]])

参数

  • value

    用来填充数组元素的值。

  • start 可选

    起始索引,默认值为0。

  • end 可选

    终止索引,默认值为 this.length

返回值

修改后的数组。

描述

fill 方法接受三个参数 value, start 以及 end. startend 参数是可选的, 其默认值分别为 0this 对象的 length属性值。

如果 start 是个负数, 则开始索引会被自动计算成为 length+start, 其中 lengththis 对象的 length属性值。如果 end 是个负数, 则结束索引会被自动计算成为 length+end

**fill** 方法故意被设计成通用方法, 该方法不要求 this 是数组对象。

**fill** 方法是个可变方法, 它会改变调用它的 this 对象本身, 然后返回它, 而并不是返回一个副本。

当一个对象被传递给 **fill**方法的时候, 填充数组的是这个对象的引用。

案例:

示例
[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1);         // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3);         // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2);       // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN);     // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5);         // [1, 2, 3]
Array(3).fill(4);                // [4, 4, 4]
[].fill.call({ length: 3 }, 4);  // {0: 4, 1: 4, 2: 4, length: 3}// Objects by reference.
var arr = Array(3).fill({}) // [{}, {}, {}];
// 需要注意如果fill的参数为引用类型,会导致都执行同一个引用类型
// 如 arr[0] === arr[1] 为true
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

原生实现

if (!Array.prototype.fill) {
  Object.defineProperty(Array.prototype, 'fill', {
    value: function(value) {
​
      // Steps 1-2.
      if (this == null) {
        throw new TypeError('this is null or not defined');
      }
​
      var O = Object(this);
​
      // Steps 3-5.
      var len = O.length >>> 0;
​
      // Steps 6-7.
      var start = arguments[1];
      var relativeStart = start >> 0;
​
      // Step 8.
      var k = relativeStart < 0 ?
        Math.max(len + relativeStart, 0) :
        Math.min(relativeStart, len);
​
      // Steps 9-10.
      var end = arguments[2];
      var relativeEnd = end === undefined ?
        len : end >> 0;
​
      // Step 11.
      var final = relativeEnd < 0 ?
        Math.max(len + relativeEnd, 0) :
        Math.min(relativeEnd, len);
​
      // Step 12.
      while (k < final) {
        O[k] = value;
        k++;
      }
​
      // Step 13.
      return O;
    }
  });
}
​

参考文章:

1、Array.prototype.fill() developer.mozilla.org/zh-CN/docs/…