JS内置对象Array

72 阅读7分钟

创建数组的4种方法:

var arr=[]//数组字面量
var arr2=new Array()//构造函数
var arr3=Array()//通过内置方法
var arr4=Array.of()//静态方法

所有的数组都继承Array.prototype,在JS中数组的底层实继承对象而来的,下标和元素,形成键值对。JS中对象通过点运算符访问属性,最终运行的时候都是通过方括号来访问的,如obj.name——>obj['name']。

稀松数组: 有占位符的数组就叫稀松数组,数组会忽略掉最后的逗号,如:

var arr=[,1,2,,3,]//数组字面量
console.log(arr.length);//5
console.log(arr[0]);//undefined

后面打印undefined,就像访问某一个对象不存在的属性时,JS就返回undefined。并不是数组arr中第0位存的时undefined。

获取数组所有静态成员

console.log(Object.getOwnPropertyDescriptors(Array));

获取数组所有实例成员

console.log(Array.prototype);

数组截断

var arr = [1, 2, 3]
arr.length=1
console.log(arr);//[1]

1、数组的静态方法

Object.getOwnPropertyDescriptors(Array)

1-1、 isArray接受一个参数,判断这个参数是不是数组,如果是就返回true,否则返回false,判断一个变量是否为数组的3种方法:

var arr=[]
console.log(Array.isArray([]));//true
console.log(Array.isArray({}));//false
console.log(arr instanceof Array);//true
console.log(Object.prototype.toString.call(arr));//[object Array]

1-2 、from方法让类数组/伪数组,转换成真正的数组,返回一个新的数组;(方法内部的arguments对象就是类数组)

参数1:类数组对象/可迭代对象

参数2:回调方法,新数组中每一个元素都执行该方法,(可选参数) 该方法接受2个参数,数组元素、元素下标(可选参数)

参数3:指定回调函数内部this的指向。(可选参数)

function test() {
	var obj = {flag:"good"}
	console.log(Array.from(arguments)); //[1,2,3,4]
	// 让每一个元素*2
	var temp = Array.from(arguments, function(item, index, arr) {
		return item * 2
	})
	// 让每一个元素后面+'good'
	
	var temp2 = Array.from(arguments, function(item, index, arr) {
		return item * 2+ this.flag//this指向obj
	},obj)
	//from的第二,第三参数,等同新数组执行map方法
	var temp3 = Array.from(arguments).map(function(item, index, arr) {
		return item * 2
	})
	var temp4 = Array.from(arguments).map(function(item, index, arr) {
		return item * 2+ this.flag//this指向obj
	},obj)
	//让类数组转真正数组的第二种方法:
	var temp5=Array.prototype.slice.call(arguments)
	console.log(temp);
}
test(1, 2, 3, 4)

由于length属性可以对数组进行截断,如果类数组中没有length属性,那么返回的就是一个空数组。由于数组下标总是从0开始的,如果数组中没有0属性,那么0下标对应的值实undefinded,直到有对应小标的值,而且下标的值大于对象中的length属性,那么这些属性都会被截断。如下:

var obj={
	2:2,
	3:3,
}
console.log(Array.from(obj));//[]

var obj1={
	2:2,
	3:3,
	length:2
}
console.log(Array.from(obj1));//[undefined, undefined]

var obj3 = {
	2: 2,
	3: 3,
	length: 3
}
console.log(Array.from(obj3)); //[undefined, undefined,2]

Object.prototype.myPush=function() {
	for (var i = 0; i < arguments.length; i++) {
		this[this.length] = arguments[i]
		this.length++
	}
	return this.length
}
var obj4 = {
	2: 2,
	3: 3,
	length: 2
}
obj4.myPush(0)
obj4.myPush(1)
console.log(obj4);//{2: 0, 3: 1, length: 4}
console.log(Array.from(obj4)); //[undefined, undefined,0,1]

1-3、of 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型,与Array方法唯一的区别就是一个参数的时候:如下:

var arrOf =Array.of(3)//[3] length=1
var arr = new Array(3)//[3] length=3
var arr2= Array(3)//[3] length=3
console.log(arr,arr.length);//[]  length=3

2、数组的常用实例方法总共30个:

2-1影响原数组的方法:

第1组操作数组末尾的方法: push,pop:

push:将一个或多个元素添加到数组的末尾,并返回该数组的新长度;

pop:从数组中删除最后一个元素,并返回该元素的值。

第2组操作数组头部的方法: unshift,shift:

unshift:将一个或多个元素添加到数组的头部,并返回该数组的新长度;

shift:从数组中删除第一个元素,并返回该元素的值。

记忆方法:push unshift单词字母个数长,使数组变长;pop ,shift单词字面个数短,使数组变短。 下面模拟数组的push和unshift方法:

Array.prototype.myPush = function() {
	for (var i = 0; i < arguments.length; i++) {
		this[this.length] = arguments[i]
	}
	return this.length
}

Array.prototype.myUnshift = function() {
	for (var i = 0; i < arguments.length; i++) {
		this.splice(0, 0, arguments[i])
	}
	return this.length
}

第3组 resovle、splice、sort

3-1、resovle: 数组反转:返回一个新数组

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

3-2、splice: 删除数组的元素,或者添加元素 ,并以数组的形式返回被删除的元素 第1参数:是开始删除元素的下标,

如果该参数大于数组的下标,则不删除元素; 如果该参数不是数字,则从第0下标开始删除

第2参数(可选):删除元素的个数,如果不填,就全部删除包括第一参数后面所有的元素;

如果该参数不是数字,它总是等于0,则删除元素的个数为0个。

第2+n参数(可选):在开始删除元素的下标新增加元素;

注: 第一参数如果打印

var arr1=[1,2,3]
console.log(arr1.splice(1));//[2,3]
console.log(arr1);[1]

var arr=[1,2,3]
console.log(arr.splice(1,1));//[2]
console.log(arr);//[1,2]

var arr1=[1,2,3]
console.log(arr1.splice(1,2,'a','b'));//[2,3]
console.log(arr1);//[1,'a','b']

3-3、sort: 数组排序,默认是按照字典顺序排序,返回新数组。接受一个可传参数,该参数是一个函数,自定义排序规则:

var arr = [1, 2, 13,'2', 'a', 'b']
console.log(arr.sort());//[1, 13, 2, "2", "a", "b"]

var objs = [
	{ id: 2, name: '姓名2' },
	{ id: 1, name: '姓名1' },
	{ id: 4, name: '姓名4' },
	{ id: 3, name: '姓名3' },
]
// 对ID升序排序
var newObjs=objs.sort(function(item1,item2){
	var result=item1.id- item2.id
	// result的3中情况说明:
	// result 大于0 item2在前面 
	// result 等于0 不做处理 
	//result 小于0 item1在前面
	return result
})
console.log(newObjs);

2-2:不影响原数组的方法:

第1组:valueOf 、toString、join

1-1、valueOf: 返回数组的本身

1-2、toString: 以字符串的形式返回元素

1-3、join: 接受一个参数(可传),以该参数连接元素,返回字符串,如果该参数不传,效果和toString一样:

var arr = [1, 2, 13,'2', 'a', 'b']
console.log(arr.valueOf());//[1, 2, 13,'2', 'a', 'b']
console.log(arr.toString());//1, 2, 13,'2', 'a', 'b'
console.log(arr.join())//1, 2, 13,'2', 'a', 'b'
console.log(arr.join('--'))//1--2--13--2--a--b

第2组:slice 、concat

2-1、concat:用于数组拼接,再原数组后面添加新元素,返回新数组,原数组不变: 参数(可传0+n个)任何数据类型,(如果是引用类型,只是保存实例的地址,如果是数组,则会拼接元素

var arr = [1, 2]
var obj={name:'七鸽'}
var newArr=arr.concat(813,null,undefined,true,'a',NaN,obj,[18,22])
console.log(arr);//[1,2]
console.log(newArr);//[1, 2, 813, null, undefined, true, "a", NaN, {name:'七鸽'}, 18,22]
obj.name='舞载'
console.log(newArr)//[1, 2, 813, null, undefined, true, "a", NaN, {name:'舞载'}, 18, 22]

2-2、slice:用于截取数组的一部分,返回新数组,原数组不变

参数1(可传):表示截取的开始下标,非数字,默认为0

参数2(可传):表示截取的截止下标,非数字,默认为0

说明:[arg1,arg2):是以这样的区间取值,

1、 arg1>arg2或者arg1大于数组的长度,返回空数组。

2、arg2大于于数组的长度或者不填写,则会截取到最一位元素

3、负值是表示,倒计数。

var arr = [1, 2,3,4,5,6]
console.log(arr.slice())//[1, 2, 3, 4, 5, 6]
console.log(arr.slice(1))//[2, 3, 4, 5, 6]
console.log(arr.slice(1,3));//[2,3]
console.log(arr.slice(3,1));//[]
console.log(arr.slice(-3,-1));//[4,5]

第3组:find 、findIndex

3-1:find: 法返回在数组中第一次出现满足条件的元素。否则返回 [undefined]

第1参数,查的元素(自定义函数;该函数接受1个必传参数,2个可传参数)

第2参数(可传):改变变第一参数内部this的指向

var result = arr.find(function(item ,index,arr) {
	console.log(this.name);
	return item.id > 2
}, { name: '七鸽' })

console.log(result);

3-2:findIndex: 法返回在数组中第一次出现满足条件的元素的位置,如果没有出现则返回 -1。

第1参数,查的元素(自定义函数;该函数接受1个必传参数,2个可传参数)

第2参数(可传):改变变第一参数内部this的指向 :

var arr = [
	{ id: 2, pid: '1' },
	{ id: 3, pid: '2' },
	{ id: 4, pid: '2' }
]

var result = arr.findIndex(function(item ,index,arr) {
	console.log(this.name);
	return item.id == 2
}, { name: '七鸽' })

console.log(result);//1

 

第4组:filter 、map、forEach

5-1、filter: 方法用于过滤数组成员,满足条件的成员组成一个新数组返回;

第1参数:以函数为参数,该函数接受1个必传参数,2个可传参数

第2参数(可传):改变第一参数内部this的指向

var arr = [1, 2,3,4,5,6]
var obj = { MAX: 3 };
let newArr= arr.filter(function (item,index,arr) {
 return item > this.MAX;
}, obj)
console.log(newArr);//[4, 5, 6]

5-2、map: 方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。

第1参数:以函数为参数,该函数接受1个必传参数,2个可传参数

第2参数(可传):改变变第一参数内部this的指向

注:跳过空位,null 和undefined都会处理。

 var arr = [1, , null, 4, undefined, 6]
 var obj = { double: 3 };
 let newArr = arr.map(function(item, index, arr) {
 	return item* this.double;
 }, obj)
 console.log(newArr);// [3, , 0, 12, NaN, 18]

5-3、forEach: :遍历数组每一个可枚举的元素,无法终止。

第1参数:以函数为参数,该函数接受1个必传参数,2个可传参数

第2参数(可传):改变第一参数内部this的指向

注:跳过空位, null 和undefined都会处理。

var arr = [1, , null, 4, undefined, 6]
 var out =[];
 let newArr = arr.forEach(function(item, index, arr) {
 	 this.push(item);
 }, out)
 console.log(out);// [3, empty, 0, 12, NaN, 18]

第5组:reduce 、rigthReduce 都是用来遍历数组每一个元素,然后累计为一个值,并返回,reduce是从左到右,rigthReduce是从右到左。

第1参数:以函数为参数,该函数接受2个必传参数,2个可传参数 如:(a,b,index,arr)后面2个是可传参数

第2参数(可传):设置初始计数值:

注:过空位,null 和undefined都会处理。

var arr = [1, , null, 4, 6]
var result = arr.reduce(function(a, b, index, arr1) {

	return a + b
}, 10)
console.log(result);21

var arr = [1, , 4, 6]
var result = arr.reduce(function(a, b, index, arr1) {

	return a * b
}, 10)
console.log(result);//240

var arr = [1,null , 4, 6]
var result = arr.reduce(function(a, b, index, arr1) {

	return a * b
}, 10)
console.log(result);//0

var arr = [1,undefined , 4, 6]
var result = arr.reduce(function(a, b, index, arr1) {

	return a * b
}, 10)
console.log(result);//NaN

第6组:some、every

6-1、some: 用来判断数组的元素是否存在符合某种条件: 只要有一个符号,回调函数就终止,并返回true,否则返回false

第1参数:以函数为参数,该函数接受1个必传参数,2个可传参数

第2参数(可传):改变第一参数内部this的指向

var arr = [1, 2,3,4,5,6]
var count1=0
var count2=0
var result= arr.some(function(item,index,arr1){
	++count1
	return item>3
})

var result2= arr.some(function(item,index,arr1){
	++count2
	console.log(this.name);//七鸽
	return item>8
},{name:'七鸽'})

console.log(result,count1);//true 4
console.log(result2,count2);//false 6

6-2、every: 用来判断所有的元素都满足某一个条件,参数和some一样:只要一个元素不满足,终止回调函数,并返回false;

第1参数:以函数为参数,该函数接受1个必传参数,2个可传参数

第2参数(可传):改变第一参数内部this的指向

var arr = [1, 2,3,4,5,6]
var count1=0
var count2=0
var result= arr.every(function(item,index,arr1){
	++count1
	return item>3
})

var result2= arr.every(function(item,index,arr1){
	++count2
	console.log(this.name);//七鸽
	return item>0
},{name:'七鸽'})

console.log(result,count1);//true 1
console.log(result2,count2);//false 6

第7组:includes、indexOf,lastIndexOf,方法用来判断一个数组是否包含一个指定的元素

第1参数,查的元素 第2参数(可传):指定开始查找的下标: 1、includes返回boolean值, 2、indexOf 从左到右查找,找到就返回该元素的下标,找不到就返回-1。

2、lastIndexOf 从左到右查找,找到就返回该元素的下标,找不到就返回-1。

var arr = [1, 2,3,4,2,6,5,6]
console.log(arr.includes(2));//true 
console.log(arr.includes(2,4));//false 
console.log(arr.indexOf(2));//1
console.log(arr.lastIndexOf(2));//4

2-2:随手记:

1、重新数组push方法

Array.prototype.myPush = function() {
	for (var i = 0; i < arguments.length; i++) {
		this[this.length] = arguments[i]
	}
	return this.length
}
var arr = [1, 2, 3]
var length = arr.myPush('a', 'b', 'c')
console.log(arr);
console.log(length);

2、重写unshift方法:

Array.prototype.myUnshiftPush = function() {
	for (var i = 0; i < arguments.length; i++) {
		this.splice(0, 0, arguments[i])
	}
	return this.length
}
var arr = [1, 2, 3]
var length = arr.myUnshiftPush('a', 'b', 'c')
console.log(arr);
console.log(length);

3、数组元素按照字节数排序

var arr = ['abcd2', 'JS的语言', '你好七鸽',]
arr.sort(function(a,b){
	return getBytes(a)-getBytes(b)
})
function getBytes(str){
	let bytes=0
	var length=str.length
	for (var i = 0; i <length; i++) {
		if(str.charCodeAt(i)>255){
			bytes++
		}
	}
	return length+bytes
}
console.log(arr);

**4、数组去重 **

var arr = [1, 10, 3, 4, 6, 03, 1, 4, 6, 10, 3, 2]

function unique1(arr) {
	var obj = {}
	var newArr=[]
	for (var i = 0; i < arr.length; i++) {
         // !obj[arr[i]] 对于0,null,undefined,false,NaN这样的数据是排除不了的	
		if (!obj.hasOwnProperty(arr[i])) {
			obj[arr[i]] = arr[i]
			newArr.push(arr[i])
		}
	}
	console.log(newArr);
}

function unique2(arr) {
	var newArr=[]
	for (var i = 0; i < arr.length; i++) {
		// if (!newArr.includes(arr[i])) {
		// 	newArr.push(arr[i])
		// }
		if (newArr.indexOf(arr[i])==-1) {
			newArr.push(arr[i])
		}
	}
	console.log(newArr);
}
function unique3(arr) {
	var newArr=[...new Set(arr)]
	console.log(newArr);
}
unique1(arr)
unique2(arr)
unique3(arr)

5、重写typeof 方法

不同数据类型的Object.prototype.toString方法返回值如下。

  • 数值:返回[object Number]
  • 字符串:返回[object String]
  • 布尔值:返回[object Boolean]
  • undefined:返回[object Undefined]
  • null:返回[object Null]
  • 数组:返回[object Array]
  • arguments 对象:返回[object Arguments]
  • 函数:返回[object Function]
  • Error 对象:返回[object Error]
  • Date 对象:返回[object Date]
  • RegExp 对象:返回[object RegExp]
  • 其他对象:返回[object Object]
var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/[object (.*?)]/)[1].toLowerCase();
};

type(false); // "boolean"
type(3); // "number"
type({}); // "object"
type([]); // "array"
type(null); // "null"
type(); // "undefined"
type(/abcd/); // "regex"
type(new Date()); // "dat

实现判断数据类型的方法:

var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/[object (.*?)]/)[1].toLowerCase();
};

['Null',
 'Undefined',
 'Object',
 'Array',
 'String',
 'Number',
 'Boolean',
 'Function',
 'RegExp'
].forEach(function (item) {
  type['is' + item] = function (o) {
    return type(o) === item.toLowerCase();
  };
});

type.Array([]) // true
type.isObject({}) // true
type.isNumber(NaN) // true
type.isRegExp(/abc/) // true

6字符串去重

function unique(str){
	var newStr='';
	var arr=str.split('')
	for (let key in arr) {
		if(!newStr.includes(str[key])){
			newStr+=str[key]
		}
	}
	return newStr;
}
console.log(unique('abdbebad'));

**7、统计字符串出现的次数,并且找出第一次重写一个的字符 **

function staticChar(str) {
	var obj = {};
	var char = ''
	var arr = str.split('')
	for (var i = 0; i < arr.length; i++) {
		if (obj.hasOwnProperty(arr[i])) {
			obj[arr[i]] = obj[arr[i]] + 1;
		} else {
			obj[arr[i]] = 1
		}
	}
	for (let key in obj) {
		if (obj[key] === 1) {
			char = key
			break
		}
	}

	return {obj,char}
}
console.log(staticChar('abcdtkabcd'));

8、平扁数据转换树结构


function arrayToTree(data, pid) {
	var result = [];
	var getChildren = initGetChildren();
	5
	getChildren(data, result, pid);
	return result
}

function initGetChildren() {
	var i = arr.length - 1
	return function getChildren(arr, reslut, pid) {
		for (; i > -1; i--) {
			mycount++
			if (arr[i].pid == pid) {
				let item = arr.splice(i, 1)[0];
				var obj = { ...item, children: [] }
				i = arr.length - 1
				reslut.push(obj)
				getChildren(arr, obj.children, obj.id)
			}
		}
		i = arr.length - 1
	}
}

var arr = [
	{ id: 2, pid: '1' },
	{ id: 3, pid: '2' },
	{ id: 1, pid: '0' },
	{ id: 4, pid: '3' },
]

arrayToTree(arr, 0)

9、findIndex和indexOf的区别:

参数上的区别:

findIndex:接受的参数是一个回调函数,和改变回调函数内部指向的对象。

indexOf:接受的参数是,要查找的元素,和开始查找的的下标。

使用场景:

1、 已经知道目标元素,查找在数组中的下标,2个方法都可以,推荐使用indexOf,代码如下:

var obj = { 'item': '项目4' }
var arr = [
	{ 'item': '项目1' },
	{ 'item': '项目2' },
	{ 'item': '项目3' },
	obj,
	{ 'item': '项目5' },
]
console.log(arr.indexOf(obj));
console.log(arr.findIndex(function(item,index,arr){
	return item.item==obj.item;
}));

2、如果目标元素是一个对象,而且只知道这个对象的某一个属性的值,比如要查找item='项目3'的对象。此时只能用findIndex方法,代码如下:

console.log(arr.findIndex(function(item,index,arr){
	return item.item=='项目3';
}));