JavaScript数组方法总结及手写
文章首发: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数组方法总结及手写的更多相关文章
- JavaScript数组方法大集合
JavaScript数组方法集合 本文总结一下js数组处理用到的所有的方法.自己做个笔记. 数组方法 concat() 合并两个或多个数组 concat()能合并两个或者多个数组,不会更改当前数组,而 ...
- 一站式超全JavaScript数组方法大全
一站式JavaScript数组方法大全(建议收藏) 方法一览表 详细操作 本人总结了JavaScript中有关数组的几乎所有方法(包含ES6之后新增的),并逐一用代码进行演示使用,希望可以帮助大家! ...
- JavaScript数组方法--every、some、fill
接上一篇,JavaScript数组方法--concat.push,继续其他的数组方法. every:every() 方法测试数组的所有元素是否都通过了指定函数的测试. 先看其使用方法: functio ...
- 【译】你应该了解的JavaScript数组方法
让我们来做一个大胆的声明:for循环通常是无用的,而且还导致代码难以理解.当涉及迭代数组.查找元素.或对其排序或者你想到的任何东西,都可能有一个你可以使用的数组方法. 然而,尽管这些方法很有用,但是其 ...
- JavaScript数组方法大全(推荐)
原网址:http://www.jb51.net/article/87930.htm 数组在笔试中经常会出现的面试题,javascript中的数组与其他语言中的数组有些不同,为了方便之后数组的方法学习, ...
- JavaScript 数组方法处理字符串 prototype
js中数组有许多方法,如join.map,reverse.字符串没有这些方法,可以“借用”数组的方法来处理字符串. <!doctype html> <html lang=" ...
- 2018.2.27 JavaScript数组方法应用
JavaScript数组方法应用 1.找出元素item在给定数组arr中的位置 function indexOf(arr,item){ return arr.indexOf(item); } func ...
- JavaScript数组方法详解
JavaScript数组方法详解 JavaScript中数组的方法种类众多,在ES3-ES7不同版本时期都有新方法:并且数组的方法还有原型方法和从object继承的方法,这里我们只介绍数组在每个版本中 ...
- JavaScript数组方法速查,32个数组的常用方法和属性
JavaScript数组方法速查手册极简版 http://30ke.cn/doc/js-array-method JavaScript数组方法速查手册极简版中共收了32个数组的常用方法和属性,并根据方 ...
随机推荐
- java高级用法之:JNA中的Function
目录 简介 function的定义 Function的实际应用 总结 简介 在JNA中,为了和native的function进行映射,我们可以有两种mapping方式,第一种是interface ma ...
- Dnscat2隧道
0x01 前言 DNS是用来做域名解析的,是连接互联网的关键,故即使是企业内网,在防火墙高度关闭下,也有着很好的连通性,但是黑客却可以通过将其他协议的内容封装再DNS协议中,然后通过DNS请求和响 ...
- 思科,华为l2tp组网,家庭宽带,公司内网数据分离
拓扑 简介 办公网使用专线接入,拥有固定IP地址,网络出口使用防火墙做NAT,下联交换机接入服务器,办公电脑等,旁挂思科路由器做L2TP LNS 家庭宽带使用ADSL线路,华为路由器做拨号设备与DHC ...
- OpenHarmony3.1 Release版本关键特性解析——Enhanced SWAP内存管理
樊成阳 华为技术有限公司内核专家 陈杰 华为技术有限公司内核专家 OpenAtom OpenHarmony(以下简称"OpenHarmony")是面向全场景泛终端设备的操作系统,终 ...
- Net6 Xunit 集成测试
对于单元测试.集成测试大部分开发的朋友都懒得去写,因为这要耗费精力去设计去开发,做完项目模块直接postman 调用测试(当然这是一个选择,开发也中经常用到),但是如果测试需要多样化数据,各种场景模拟 ...
- HtmlParse:一款超轻量级的HTML文件解析和爬取工具
HtmlParse 是一款基于windwos平台的HTML文档解析工具,可快速构建DOM树,从而轻松实现网页元素的爬取工作.DOM树就是一个HTML文档的节点树,每个节点由:标签(Tag).属性(At ...
- 菜鸟学git的基本命令及常见错误
Git init //在当前项目工程下履行这个号令相当于把当前项目git化,变身!\ git config --global user.name "xxx" # 配置用户名 git ...
- 【Redis】哨兵初始化和主观下线
在的redis启动函数main(server.c文件)中,对哨兵模式进行了检查,如果是哨兵模式,将调用initSentinelConfig和initSentinel进行初始化,initServer函数 ...
- Java创建数据库新建表及初始化表
方法一 package com.crt.openapi; import java.sql.DriverManager;import java.sql.ResultSet;import java.io. ...
- v-if和v-for哪个优先级更高?
首先在实际开发阶段,不应该把v-if和v-for在同一个标签中使用, 在vue2中,v-for的优先级是高于v-if的,如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性 ...