js之数组知识

一.数组的定义(来源于Array.prototype)

1.构造函数方法:

  (1)var arr = new Array();//没有参数等价于 var arr = [];

  (2)var arr = new Array(length);//创建指定长度的数组;预分配一个数组空间;但数组中没有存储值,甚至数组的索引属性'0','1'等还未定义

  (3)var arr=new Array(值1,值2,值3...)

2.字面量:var arr = []; var arr=[1,2,3]

区别:new Array()只有一个参数(不能为小数:非法!报错!)时,会被当成是长度,并成为一个稀松数组;

var arr1 = new Array(4);
var arr2 = [4];
console.log(arr1);//[undefined*4]
console.log(arr2);//[4]
var arr = new Array(3.4);
console.log(arr);//Uncaught RangeError: Invalid array length

二.数组的读写(不可溢出读,结果为undefined;可以溢出写)

原理:数组索引仅仅是对象属性名的一种特殊类型,这意味着javascript数组没有'越界错误'的概念,.当试图查询任何对象不存在的属性还是,不会报错,只会得到undefined值.

var arr = [1,2];
console.log(arr[2]);//undefined
arr[4] = 5;//溢出写
console.log(arr);//[1,2,undefined,undefined,5];
console.log(arr[3]);//undefined--->实际上是arr['3']
var obj = {};
console.log(obj.age);//undefined
var arr = [];
console.log(arr['age']);//undefined

注意:数组是对象的特殊形式.使用方括号访问数组就像方括号访问对象的属性一样,javascript将指定的数字索引值转换为字符串---索引1变为'1'---然后将其作为属性名来使用.

数组的特别之处在于:当使用小于等于2^32-2的非负整数作为属性名时,数组会自动维护其length属性值;

arr[Math.pow(2,32)-2] = 67;//索引
arr[Math.pow(2,32)-1] =22;// 属性名

arr[1]--->实际上是arr['1'];

 var arr = [1,2,3,4];
 console.log(arr);
//[1, 2, 3, 4]
//0:1
//1:2
//2:3
//3:4
//length:4
console.log(arr[1])//2,实际上是访问数组的'1'属性;

(1)可以用负数或非整数来索引数组.这种情况下,数值转换为字符串,字符串作为属性名来使用(即索引不是非负整数的情况下,只能当做常规的对象属性);

(2)同样,如果凑巧使用了非负整数(即0和正整数)的字符串,它就当做数组索引,而非对象属性.

(3)当使用的一个浮点数和一个整数相等时,也是当做数组索引

即除了(2)和(3)情况,[]内的值都当成对象属性名(转换为字符串)

var arr = [1,2,3,4];
arr[-2] = 'name';//-2当做属性-------(1)
arr[1.5] = 9;//1.5当做属性-----------(1)
arr['3'] = 15;//数组索引;等价于arr[3]------(2)
arr[1.00] = 23//数组索引;等价于arr[1]=23---(3)
arr['1.00']=4;//1.00当做属性1.00
arr['age'] = 6;//age:属性
console.log(arr);// [1, 23, 3, 15, -2: "name", 1.5: 9, 1.00: 4,age:6]
console.log(arr.length)//4 索引值为小于2^32的非负整数会自动维护其length值
var obj = {};//空对象或不空的
arr[obj] = '5';//属性名为[object Object]: "5"

三.稀松数组:包含从0开始的不连续索引的数组;length属性值大于元素的个数,可以用Array()构造函数或简单地指定数组的索引值大于当前的的数组长度来创建稀疏数组

1.var arr = new Array(5);//数组没有元素,但a.length = 5

2. a = [];//当前length为0;

 a[1000] = 0;//1000>0;稀疏数组,length变为1001;

 四.数组的常用方法

(一)改变原数组的:reverse,push,pop,unshift,shift,splice,sort;

(1)reverse()---颠倒数组中元素的顺序并返回新的数组。

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

(2)push()---向数组的末尾添加一个或更多元素,并返回新的长度。

var arr=[1,2,3];
var a = arr.push(4,5);
console.log(arr);//[]1,2,3,4,5]
console.log(a);//5

(3)pop()---删除并返回数组的最后一个元素(没有形参,写了会被忽略)

var arr=[1,2,3];
var a = arr.pop(4,5);//自动忽略掉参数4,5
console.log(arr);//[1,2]
console.log(a);//3

(4)unshift()---向数组的开头添加一个或更多元素,并返回新的长度。

var arr=[1,2,3];
var a = arr.unshift(4,5);
console.log(arr);//[4,5,1,2,3]
console.log(a);//3

(5)shift()---删除并返回数组的第一个元素

var arr=[1,2,3];
var a = arr.shift();//没有形参,有的话会忽略
console.log(arr);//[2,3]
console.log(a);//3

(6)splice()---删除元素,并向数组添加新元素,并返回删除的元素

它有三个参数,第一个参数时截取开始的位置,第二个参数是截取的长度,第三个参数是一组数据,代表要在截取的位置添加的数据

var arr=[1,2,3];
var a = arr.splice(1,2,4,5)//从第一位开始截取两位数据2,3,并在当前位置添加数据4,5;
console.log(arr);//[1,4,5]
console.log(a);//[2,3]
var b = arr.splice(1,2,[7,8],9);//这里splice是插入数组本身,区别concat连接数组是数组的元素;
console.log(arr);//[1,[7,8],9];
console.log(b);//[4,5];
var arr=[1,2,3];
var a = arr.splice(-1,2,4,5)//从倒数第一位(第二位)(-1+arr.length=2)开始截取两位数据(这里只有一位数据了)3,并在当前位置添加数据4,5;
console.log(arr);//[1,2,4,5]
console.log(a);//[3]
如果不写要添加的数据的话,这个方法就变成了在数组中删除数据的作用了。
如果截取的长度是0,然后添加数据的话,这个方法就变成了在数据的特定位置添加数据的作用了。
 (7)sort()---从小到大排序---return最后排序后的数组(如果数组包括undefined元素,会被排到数组的尾部)
var arr = [1,2,,3,4];
var a=arr.sort();
console.log(a);//[1,2,3,4,undefined]
var arr=[1,5,3,9,-7,2];
var a = arr.sort();
console.log(arr);//[-7, 1, 2, 3, 5, 9]
console.log(a);//[-7, 1, 2, 3, 5, 9]
在sor后面添加reverse就相当于降序排序:
var arr=[1,5,3,9,-7,2];
var a = arr.sort().reverse();
console.log(arr);//[9, 5, 3, 2, 1, -7]
console.log(a);//[9, 5, 3, 2, 1, -7]
注意:这里的sort()是按ASCII码排序的,若要比较数的大小,需要在sort()内部添加函数
var arr=[1,3,10,2,5];
var a = arr.sort();
console.log(arr);//[1,10,2,3,5]
var arr = [1,2,undefined,null,3,4];
var a=arr.sort();
console.log(a);//[1,2,3,4,null,undefined]--根据ASCII码进行排序

sort()函数有个接口:

注意:

看返回值return:

(1)当返回值为负数时,前面的数在前面

(2)当返回值为正数时,后面的数在前面  

var arr=[1,3,10,2,5];
arr.sort(function(a,b){
    if(a>b){
        return 1;//a>b,b放在a前面,即小的数在前面
    }else{
        return -1;//a<b,a放在前面,即小的数在前面
    }
})
console.log(arr);//[1,2,3,5,10]
上面例子实际上就是a-b>0;返回正数,否则返回负数(升序排序)
将上面的算法进行简化:
var arr=[1,3,10,2,5];
arr.sort(function(a,b){
  return a-b;
})
console.log(arr);//[1,2,3,5,10]
 升序:return a - b;
 降序:return b - a
思考:若是有一个有序数组,希望进行乱序,怎么写?
理解:当返回值为随机数(即可能是正,可能是负的情况),进行比较的两个数的顺序是不确定的;
var arr=[1,2,3,4,5];
arr.sort(function(){
  return Math.random()-0.5;//Math.random()--->[0,1);
})
console.log(arr);
sort()不仅仅局限于对数字进行排序,也可以是根据某个属性对对象,字符串等进行排序
var deng = {
    name:'deng',
    age:12
};
var zao={
    name:'zao',
    age:34
};
var li={
    name:'li',
    age:10
}
var arr= [deng,zao,li];
arr.sort(function(a,b){
    return a.age-b.age;//1.按照年龄进行升序
 //return a.name.length - b.name.length;//2.按照名字长度升序

})
console.log(arr);

 根据字节长度进行排序

//字节长度,汉字为2;字母为1;
function retBytes(str){
    var num = str.length;
    for(var i = 0 ; i< str.length;i++){
        if(str.charCodeAt(i) > 255){//返回指定位置的字符的 Unicode 编码;
            num += 1;
        }
    }
    return num;
}
var arr = ['Ming','李dang','王明','merheyka'];
arr.sort(function(a,b){
    return retBytes(a) - retBytes(b);
})
console.log(arr);//["Ming", "王明", "李dang", "merheyka"]
(二)不改变原数组的:concat,slice,join,toString,

(1)concat----连接两个或更多的数组,并返回一个新数组。

它的元素包括调用concat()的原始数组的元素和concat()的每个参数.若这些参数中的任何一个自身是数组,这连接的是数组的元素,而非数组本身;

但注意:concat()不会递归扁平化数组的数组.concat()也不会修改调用的数组;

var arr1 = [1,2,3];
var arr2 = [4,5];
var arr=arr1.concat(arr2);//等价于var arr = [].concat(arr1,arr2);concat可以有一个或多个参数
console.log(arr);
//[1,2,3,4,5] console.log(arr1);//[1,2,3] console.log(arr2);//[4,5]
var arr3 = [6,[7,8]];
arr = arr1.concat(arr3);
console.log(arr);//[1,2,3,6,[7,8]];

(2)slice---从某个已有的数组返回选定的元素

 slice可以有0个参数,1个参数或者2个参数(参数可以为负数(等价于 负数+数组长度)超出2个的参数会自动被忽略,认为只有2个参数)

第一种情况:0个参数:截取整个数组(用于将类数组转化为数组)

var obj = {
    '0':'a',
    '1':'b',
    'length':2
}
var a=Array.prototype.slice.call(obj);
console.log(a);//['a','b']

第二种情况:1个参数:从第几位开始,一直截取到最后一位

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

第三种情况:2个参数:slice(从该位开始截取,截取到该位); 例slice(2,4)从第2位开始截取到第四位(不包括该位),即第二位和第三位

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

(3) join---把数组的所有元素放入一个字符串。元素通过指定的符号进行连接。(可以用这个方法来进行大量字符串的连接工作)

var arr = ['a', 'b', 'c'];
var str = arr.join('-');
console.log(str); // "a-b-c"

join--若不传参数(默认为逗号连接) join() 等价于join(',');

拼接字符串:使用arr.join("");

扩展;:split:字符串转换为数组的方法根据符号将字符串拆分为数组

var arr = ['a', 'b', 'c'];
var str = arr.join('-');
console.log(str); // "a-b-c"
var a = str.split('-');
console.log(a);//['a','b','c']

注意:一个数组通过join()方法和split()后得到的数组与原来的数组不一定是一样的;通过split返回的数组;每个数都是字符串

var arr = [1, 2, 3];
console.log(typeof arr[0]);//number
var str = arr.join('-');
console.log(str); // "a-b-c"
var a = str.split('-');
console.log(a);//['1','2','3']
console.log(typeof a[0]);//string

小题目:将下面的字符串拼到一起

var str1 = 'tianmao';
var str2 = 'taobao';
var str3 = 'jindong';
var str4 = 'weipinghui';
var str5 = 'shuning';
var str6 = 'pingduoduo';

 1.用+运算符去连接字符串---由于字符串时存在栈里面的(先进后出),栈操作消耗性能大

var arr = [str1,str2,str3,str4,str5,str6];
var str = '';
for(var i = 0 ; i < arr.length;i++){
    str += arr[i];
}
console.log(str);//tianmaotaobaojindongweipinghuishuningpingduoduo

2.用join方法----推荐

var arr = [str1,str2,str3,str4,str5,str6];
str = arr.join('');
console.log(str);//tianmaotaobaojindongweipinghuishuningpingduoduo

 (4)toString()----把数组转换为逗号分隔的字符串列表.注意:输出不包括方括号或其他任何形式的包裹数组值的分隔符.

var arr = [1,2,3,4];
var str = arr.toString();
console.log(str);//"1,2,3,4"

[1,[2,3]].toString();//'1,2,c' 这里与不适用任何参数的调用join()返回的结果一样

(5)toLocalString():toString的本地化版本.

它调用元素的toLocalString()的方法将每个数组元素转化为字符串,并使用本地化(和自定义实现的)分隔符将这些字符串连接起来.

(三)ES5中的数组方法

 

1.forEach()-----这个方法会改变原数组,它让数组中的元素从头到尾遍历一遍,每一个都调用一下我们在forEach里面传递的方法,中间不会停止
可以有三个参数(数组元素,元素索引,数组本身)
var arr = [1, 2, 3, 4];
arr.forEach(function (ele, index) {
  arr[index] += 1;
})
console.log(arr); // [2, 3, 4, 5]
2.map()-----这个方法和forEach很像,只是map不会改变原数组,而是返回一个新的数组,它也是让传递一个指定的方法,让数组中的每一个元素都调用一遍这个方法。不过记得map方法最后有返回值。如果是稀疏数组,返回的也是相同方式的稀疏数组,它具有相同的长度,相同的缺失元素
var arr = [1, 2, 3];
var test = arr.map(function (x) {
     return x * x;
 });
console.log(test); // 1 4 9
console.log(arr); // 1 2 3    
3.filter()---------过滤的作用,它同样不会改变原数组,而是返回一个原数组的子集。我们同样会传递一个方法,每一个元素都会调用一下这个方法,但是只有返回true的元素才会被添加到新数组里面,返回false的不会被添加到新数组里面。
var a = [1, 2, 3, 4, 5];
var b = a.filter(function (x) {
     return x > 2;
});
console.log(a);//[1,2,3,4,5]
console.log(b); // [3,4,5]

 同时,filter()会跳过稀疏数组里面缺少的元素,它的返回数组总是稠密的。

var arr = [1,,,,,,3,4];
var b = arr.filter(function () {
      return true;
})
console.log(arr); // [1,3,4]

4.every和some

这两个方法是数组的逻辑判定,他们对数组应用指定的函数进行判定,返回true或者false。
every是如果每一个元素经过传递的方法的判定之后都返回true,那么最后才返回true。
some是只要有一个元素返回true,那么就返回true。
根据数学上的惯例,在空数组上调用时,every()返回true,some()返回false
var arr = [1 ,2 ,3];
console.log(arr.some(function (x) {return x<3;})); //true
console.log(arr.every(function (x) {return x<3;})); //false
5.reduce()和reduceRight():使用指定的函数将数组元素进行组合,最后变成一个值,reduce是从左向右,reduceRight是从右向左。有两个参数,第一个是方法,第二个是可选参数,即我们最后的这个值的初始值。
当我们没有设置初始值的时候,用数组的第一个元素的值作为初始值。不过当数组为空的时候,不带初始值就会报错。
当我们的数组只有一个元素并且没有指定初始值,或者有一个空数组并且指定一个初始值的情况下,reduce只是简单地返回那个值,而不会调用函数。
var arr = [1, 2, 3];
var sum = a.reduce(function (x, y) { return x + y}, 0);// 6------0 + 1 + 2 + 3 = 6;
var temp = [1];
var temoOut = a.reduce(function (x, y) {return x * x * y}); // 1 不会调用这个函数,因为数组只有一个值,除非我们设置一个初始值

 6.indexOf()和lastIndexOf():搜索整个数组中具体给定值的元素,返回找到的第一个元素的索引或者如果没有找到就返回-1.indexOf()从头到尾搜索,而lastIndexOf()则反向搜索

var a = [0,1,2,1,0];
a.indexOf(1);//1-->a[1] = 1;
a.lastIndexOf(1);//3--->a[3] = 1;
a.indexOf(3);//-1;没有值

 注意:indexOf()和lastIndexOf()不接收一个函数作为其参数(不报错---返回-1);

indexOf()和lastIndexOf()可以有两个参数,第一个是需要搜索的值,第二个是指定数组中的一个索引,从那里开始搜索 

 ---以上知识参考了:javascript权威指南

posted @ 2018-08-16 22:47  StupidTom  阅读(466)  评论(0编辑  收藏  举报