创建数组的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, 0,3, 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';
}));