文章首发:CSDN

手写数组衍生方法

1.检测是否为数组

    <script>
var arr = [1,2,3]
//判断arr是否为数组,返回布尔值true 或false //法一:Array.isArray()
console.log(Array.isArray(arr));
//法二:instanceof
console.log( arr instanceof Array);
//法三:判断arr的构造函数constructor有无包含Array
console.log(arr.constructor.toString().indexOf('Array')>-1);
//arr.constructor为ƒ Array() { [native code] } //法四:用isPrototypeOf判断arr是否存在于Array的原型链中
console.log(Array.prototype.isPrototypeOf(arr));
/*
法五:万能判断变量类型方法Object.prototype.toString.call()
会返回一个形如 "[object XXX]" 的字符串
*/
console.log(Object.prototype.toString.call(arr).indexOf('Array')>-1);
//即console.log(Object.prototype.toString([])===Object.prototype.toString(arr));
</script>

2.类数组转化为数组

类数组对象,就是含有 length 属性且不是数组的对象,但结构表现上很像一个数组。

类数组对象主要有:

  • 普通函数中的argument
  • 一些获取 Dom 集合的方法,如document.querySelectorAll()、 document.getElementsByClassName、document.getElementsByTagName()等也会返回类数组对象
 <body>
<div>1</div>
<div>2</div>
<script>
let arg = document.querySelectorAll('div');
console.log(arg); //NodeList(2) //法一: 用Array.from
console.log(Array.from(arg)); //Array(2)
//法二 :扩展运算符
console.log([...arg]); //法三:用Array.prototype.slice.call():可将具有length属性的对象转成数组,因为slice方法返回一个新数组
console.log( Array.prototype.slice.call(arg));
//slice方法如果不传参数的话会返回原数组的一个拷贝,通过call显式绑定来实现使arguments也能调用slice方法。 //法四:利用concat
console.log(Array.prototype.concat.apply([], arg));
</script>
</body>

3.数组扁平化

数组扁平化是指将一个多维数组变为一个一维数组

   const arr = [1, [2, [3, [4, 5]]], 6]
// => [1, 2, 3, 4, 5, 6]
//法一:使用内置的flat()
const res1 = arr.flat(Infinity)
//法二:用正则表达式
const res2 = JSON.stringify(arr).replace(/\[|\]/g,"").split(',')
//此时数组元素为字符串类型,若用arr.join()会将中括号自动去掉 //法三:用 reduce 实现数组的 flat 方法(重点关注)
function flatmy(ary) {
//注意函数要有返回值
return ary.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flatmy(cur) : cur)
}, [])
}
console.log(flatmy(arr)) // 法四:函数递归
const res4 = []
const fn = (arr) => {
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
fn(arr[i])
} else {
res4.push(arr[i])
//或 res4 = res4.concat(arr[i])
}
}
return res4
} console.log(fn(arr))
//法五:调用toString
console.log(arr.toString()); //1,2,3,4,5,6
console.log(arr.toString().split(',').map(item => item-0)) //若没有map函数隐式转换则数组里的元素为字符串类型

4.数组去重

  const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]
// => [1, '1', 17, true, false, 'true', 'a', {}, {}]
// 法一:用new Set方法
let res = Array.from(new Set(arr))
// 法二:用indexOf
let res2 = []
for(let v of arr){
if(res2.indexOf(v)==-1) res2.push(v)
} /*法三:用filter */
function myUnique(arr){
return arr.filter((v,index)=>{
return arr.indexOf(v)===index
})
}
// 法四:用sort,排序后相同的元素在相邻位置
function unique(arr) {
arr = arr.sort()
var res= []
for (var i = 0; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
res.push(arr[i])
}
}
return res
}
console.log(unique(arr))

5.数组使用Math.max

Math.max支持传入多个参数,但不可传入一个数组(否则为NaN),若想使用可用一下方法

Math.max.apply(null,arr)
Math.max(...arr)

手写数组内置方法

1. Array.prototype.filter

filter() 方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素

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

参数:

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

element:数组中当前正在处理的元素。

index可选:正在处理的元素在数组中的索引。

array可选:调用了 filter 的数组本身。

thisArg可选:执行 callback 时,用于 this 的值。

Array.prototype.myFilter = function(callback,thisArg){
if(typeof callback != 'function' ) {
throw new TypeError(callback +'不是函数')
}
if(!Array.isArray(this)){
throw new TypeError('必须为数组才可调用此方法')
}
let res = []
//确定回调函数的this指向,看是否传了第二个参数,若无则设为window调用
let context = arguments[1]||window
for(let i = 0; i < this.length; i++){
callback.call(context,this[i],i,this) && res.push(this[i])
}
return res
}

2. Array.prototype.map

map() 方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成

语法:var new_array = arr.map(function callback(currentValue[, index[, array]]) [, thisArg]),参数大致与filter相同

  Array.prototype.myMap = function (callback, thisArg) {
if (typeof callback != 'function') {
throw new TypeError(callback + '不是函数');
}
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let res = []
let context = arguments[1] || window
for (let i = 0; i < this.length; i++) {
res.push(callback.call(context, this[i], i, this))
}
return res
};

3. Array.prototype.reduce(难点)

reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值

语法:Array.reduce(callback(previousValue, currentValue[, currentIndex[, array]])[, initialValue])

参数:

previousValue:上一次调用 callbackFn 时的返回值。第一次调用时为初始值initialValue||array[0]

currentValue:数组中正在处理的元素。在第一次调用时若指定了初始值 initialValue,其值则为 array[0],否则为 array[1]。

currentIndex:数组中正在处理的元素的索引

initialValue :可选,作为第一次调用 callback 函数时参数 previousValue 的值。若指定了 initialValue则 currentValue 将使用数组第一个元素

Array.prototype.myReduce = function (callback, initialValue) {
if (typeof callback != 'function') {
throw new TypeError(callback + '不是函数');
}
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let accumulator = initialValue
if(accumulator === undefined){
//若未设初始值则赋值为数组的第一个元素
accumulator = this[0]
//数组为空且初始值 initialValue 未提供时会报错
if(accumulator === undefined) throw new TypeError('无初始值时数组要为非空');
}
//若给定初始值则起始索引号为0
let startIndex = initialValue !== undefined ? 0 : 1;
for (let i = startIndex; i < this.length; i++) {
accumulator = callback.call(undefined,accumulator,this[i], i, this);
}
return accumulator;
};

4. Array.prototype.forEach

forEach() 方法对数组的每个元素执行一次给定的函数,注意返回值为undefined

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

 Array.prototype.myForEach = function (callback, thisArg) {
if (typeof callback != 'function') {
throw new TypeError(callback + '不是函数');
}
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let context = arguments[1] || window;
for (let i = 0; i < this.length; i++) {
callback.call(context, this[i], i, this);
}
};

5. Array.prototype.some

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

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

 Array.prototype.mySome = function(callback,thisArg){
if (typeof callback != 'function') {
throw new TypeError(callback + '不是函数');
}
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let context = arguments[1] || window
for(let i =0 ; i < this.length; i++){
if( callback.call(context,this[i],i,this)){
return true
}
}
return false
}

6. Array.prototype.find

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

语法:Array.find(callback(element[, index[, array]])[, thisArg])

   Array.prototype.myFind = function(callback,thisArg){
if (typeof callback != 'function') {
throw new TypeError(callback + '不是函数');
}
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let context = arguments[1] || window
for(let i =0 ; i < this.length; i++){
if( callback.call(context,this[i],i,this)){
return this[i]
}
}
return undefined
}

7. Array.prototype.unshift

unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)

语法:arr.unshift(element1, ..., elementN)

Array.prototype.myUnshift = function () {
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let len = arguments.length;
this.length += len;
//注意要从后往前循环,防止后面的值都被覆盖为前面arguments的值
for (let i = this.length - 1; i >= 0; i--) {
//当i小于传入的参数时取传入的参数,否则取原先的值
this[i] = i < len ? arguments[i] : this[i - len];
}
return this.length;
};

8. Array.prototype.join

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

语法:arr.join([separator])

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

如果一个元素为 undefined 或 null,它会被转换为空字符串

  Array.prototype.myJoin = function (s = ',') {
if (!Array.isArray(this)) {
throw new TypeError('必须为数组才可调用此方法');
}
let str = '';
for (let i = 0; i < this.length; i++) {
//判断数组元素是否为undefined或null
if(this[i] === undefined || this[i] === null ) this[i] = ''
if (i === 0) str = `${this[i]}`;
else str = `${str}${s}${this[i]}`;
}
return str;
};

另外还有every、findIndex、includes、push等方法,实现比较简单便不做赘述

参考资料

JavaScript手写数组常用函数

Array MDN

JavaScript数组方法总结及手写的更多相关文章

  1. JavaScript数组方法大集合

    JavaScript数组方法集合 本文总结一下js数组处理用到的所有的方法.自己做个笔记. 数组方法 concat() 合并两个或多个数组 concat()能合并两个或者多个数组,不会更改当前数组,而 ...

  2. 一站式超全JavaScript数组方法大全

    一站式JavaScript数组方法大全(建议收藏) 方法一览表 详细操作 本人总结了JavaScript中有关数组的几乎所有方法(包含ES6之后新增的),并逐一用代码进行演示使用,希望可以帮助大家! ...

  3. JavaScript数组方法--every、some、fill

    接上一篇,JavaScript数组方法--concat.push,继续其他的数组方法. every:every() 方法测试数组的所有元素是否都通过了指定函数的测试. 先看其使用方法: functio ...

  4. 【译】你应该了解的JavaScript数组方法

    让我们来做一个大胆的声明:for循环通常是无用的,而且还导致代码难以理解.当涉及迭代数组.查找元素.或对其排序或者你想到的任何东西,都可能有一个你可以使用的数组方法. 然而,尽管这些方法很有用,但是其 ...

  5. JavaScript数组方法大全(推荐)

    原网址:http://www.jb51.net/article/87930.htm 数组在笔试中经常会出现的面试题,javascript中的数组与其他语言中的数组有些不同,为了方便之后数组的方法学习, ...

  6. JavaScript 数组方法处理字符串 prototype

    js中数组有许多方法,如join.map,reverse.字符串没有这些方法,可以“借用”数组的方法来处理字符串. <!doctype html> <html lang=" ...

  7. 2018.2.27 JavaScript数组方法应用

    JavaScript数组方法应用 1.找出元素item在给定数组arr中的位置 function indexOf(arr,item){ return arr.indexOf(item); } func ...

  8. JavaScript数组方法详解

    JavaScript数组方法详解 JavaScript中数组的方法种类众多,在ES3-ES7不同版本时期都有新方法:并且数组的方法还有原型方法和从object继承的方法,这里我们只介绍数组在每个版本中 ...

  9. JavaScript数组方法速查,32个数组的常用方法和属性

    JavaScript数组方法速查手册极简版 http://30ke.cn/doc/js-array-method JavaScript数组方法速查手册极简版中共收了32个数组的常用方法和属性,并根据方 ...

随机推荐

  1. kill -9 进程杀不掉,怎么办?

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 用ps和grep命令寻找僵尸进程 ps -A -ostat,ppid,pid,cmd | gr ...

  2. 一文看懂:网址,URL,域名,IP地址,DNS,域名解析

    一个执着于技术的公众号 前言 今天给大家梳理一篇关于网址.URL.IP地址.域名.DNS.域名解析的白话长文,并以简单的提问-解答 形式让读者更加深刻理解,希望有助于读者的学习,面试和工作! 1.一个 ...

  3. 如何在Linux上恢复误删除的文件或目录

    Linux不像windows有那么显眼的回收站,不是简单的还原就可以了.linux删除文件还原可以分为两种情况,一种是删除以后在进程存在删除信息,一种是删除以后进程都找不到,只有借助于工具还原,这里分 ...

  4. Hadoop——API操作

    代码示例: package com.atguigu.hdfs; import org.apache.hadoop.conf.Configuration; import org.apache.hadoo ...

  5. python初识数据类型(字典、集合、元组、布尔)与运算符

    目录 python数据类型(dict.tuple.set.bool) 字典 集合 元组 布尔值 用户交互与输出 获取用户输入 输出信息 格式化输出 基本运算符 算术运算符 比较运算符 逻辑运算符 赋值 ...

  6. 安装Siege到Linux(源码)

    运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:siege-4.0.4 硬件要求:无 安装过程 1.安装依赖 [root@localhost ~ ...

  7. TornadoFx设置保存功能((config和preference使用))

    原文地址:TornadoFx设置保存功能(config和preference使用) 相信大部分的桌面软件都是存在一个设置的界面,允许用户进行设置的修改,此修改之后需要保存的本地,若是让开发者自己实现, ...

  8. Django-Model随笔

    Django数据库之Model 常用命令 生成迁移文件 python manage.py makemigrations 实行数据库迁移 python manage.py migrate 数据库表结构反 ...

  9. SpringBoot Restful 接口实现

    目录 SpringBoot 核心注解 SpringBoot Restful 接口实现 封装响应数据 SpringBoot 核心注解 SpringBoot 基础入门 注解 说明 Component 声明 ...

  10. 深入C++04:模板编程

    模板编程 函数模板 模板意义:对类型也进行参数化: 函数模板:是不编译的,因为类型不知道 模板的实例化:函数调用点进行实例化,生成模板函数 模板函数:这才是要被编译器所编译的 函数模板.模板的特例化. ...