上一篇聊了一些JavaScript中数组的基础,现在可以更加深入的了解一些关于数组的知识,以及前面聊function
的时候说arguments
是一个伪数组的问题。
本篇主要是根据上一篇的方法,用自己的方式去还原一些数据的操作方法,更好的理解数组的本质。
本篇更是侧重于对前面聊的伪数据的进一步的了解。
伪数组
伪数组对比数组
其实说起伪数组前面前面聊过 ,毕竟function
中的arguments
就是一种伪数组。但是没有进一步的进行详细聊,到底伪数组的原理是什么,以及伪数组的进一步的应用。现在开始聊这个。不过还是老规矩,先上代码,后面聊。
function test(){
console.log(arguments);
}
test(1,2,3,4,5);
var arr=[1,2,3,4,5];
console.log(arr);
对比着看两者打印出的内容。
发现其__proto__
一个指向的是Array
一个是Object
;
手动创建伪数组
当然彼此都有各自的length
属性。所以可以看出虽然相似但又不是同一个类型的东西。自然手动也可以创建一个伪数组
var arr1={
0:1,
1:2,
2:3,
3:4,
4:5,
length:5
}
当然自己创建的没有带有
symbol(Symbol.iterator)
: 这个是为迭代而服务的。- callee: ,当前arguments对象是在输入哪个函数的参数对象。(前有一个小篇说过此属性值)
伪数组的神奇操作
这个时候又有可以操作的神奇方式了,那就是将我们创建的伪数组打印的时候像是一个数组,这个涉及到一个神奇的数组属性方法,
var arr2={
0:1,
1:2,
2:3,
3:4,
4:5,
length:5,
splice:Array.prototype.splice
}
可以看出__proto__
的属性值还是Object
但是打印的却不是一对{ }
而一对[]
。神奇不?
既然可以这样,那么是否可以进一步将类似push
的方法也放进去,然后看是否可以调用呢?
var arr3={
0:1,
1:2,
2:3,
3:4,
4:5,
length:5,
splice:Array.prototype.splice,
push:Array.prototype.push,
}
arr3.push(6);
其实push
本身就是一个简单方法,自己也可以实现
// 这个好好理解一下,因为下面例题中需要对这个方法逻辑了解
function mypush(v){
this[this.length]=v;
this.length++;
}
经典例题
现在来一个神奇的例题来了解,以及补充小伪数组上面漏掉的东西。
var arr4={
2:3,
3:4,
length:2,
splice:Array.prototype.splice,
push:Array.prototype.push,
}
arr4.push(1);
arr4.push(2);
console.log(arr4);
//现在不看下面,大胆的猜测一下其打印出的内容是什么?
为什么会出现这样的情况?
首先打印push
前的伪数组。
可以看出属性的key用数字表示 如果splice:Array.prototype.splice
那就会变成数组的下标值,如果前数组后面不会补充但是前面定然会补充的,再做一个实验:
var arr4={
1:3,
3:4,
length:2,
splice:Array.prototype.splice,
push:Array.prototype.push,
}
为啥只有一个空呢?因为splice:Array.prototype.splice
有了数组的性质,其length=2
会直接将其截断,而后面的3:4
又因为其本身是key-value对,所以优先权比较高,而空却只是数组属性而补充的而已。
很简单证明,直接length=3
试试。
var arr4={
1:3,
3:4,
length:3,
splice:Array.prototype.splice,
}
上面的明白的话,可以再搞一个实验,如果将key值变成字母呢?
var arr4={
a:3,
b:4,
length:2,
splice:Array.prototype.splice,
push:Array.prototype.push,
}
arr4.push(1);
arr4.push(2);
console.log(arr4);
可见splice:Array.prototype.splice
有了数组的性质,会影响key值为数字的,其它的就无法体现出数组性质的属性来了。
然后for
循环得到其key
for(key in arr4){
console.log(key);
}
可见如果通过数组属性补充的位置,不是不算是key
值。
如果看一下key的类型呢?
for(key in arr4){
console.log(typeof key);
}
可见是7个字符串,可见哪怕写的属性值为数字,本质还是String
。
这个时候又有大胆想法了
//既然无法同.数字得到那变成字符串呢?
arr4.'2';
arr4[2];//和数组取值有点像只能
如果其它key为非数字呢?
arr4.a;
arr4["a"];
伪数组转换成真正数组
这个需要神奇的一个Array.prototype.slice
当然也不是像是打印出数组的样子用:Array.prototype.splice
var arr4={
2:3,
3:4,
length:2,
slice:Array.prototype.slice,
push:Array.prototype.push,
}
而是这样操作:
var arr4={
2:3,
3:4,
length:4
}
arr5=Array.prototype.slice.call(arr4);
应用
其实前面说了那样多,无论如何说其根本还是有什么用呢?
例子1
1: 如果将方法的参数放在一个数组中当然不是放在后面,如果那样话就太简单了,比如 arr =[1,2,3],参数是"a","b","c" 最后arr为["a","b","c",1,2,3],记住一点参数是不固定。
方法1:
var arr=[1,2,3]
function test(){
for (i=0;i<arguments.length;i++){
arr.splice(i,0,arguments[i])
}
}
方法2:
var arr=[1,2,3]
function test(){
arr=Array.prototype.slice.call(arguments).concat(arr);
}
例子2
var arr=[2,4,5,6,5,0,0,"a","b","a"]
定义一个原型方法:将数组中的元素去重.
//直接将元素作为key和value,方便我们判断。
Array.prototype.uni=function(){
var newobj={
};
var newarr=[];
for(i=0;i<this.length;i++){
//if(!newobj[this[i]]) 这样不行,因为有的元素值是0,0再布尔值隐式转换的时候有问题不会将0完全去重
if(!newobj.hasOwnProperty(this[i])){
newobj[this[i]]=this[i];
newarr.push(this[i])
}
}
return newarr;
}
var arr=[2,4,5,6,5,0,0,"a","b","a"];
arr.uni();
例子3
写一个方法,输入数字然后返回星期几
方法1:
function test(num){
switch (num){
case 0:
console.log("Sunday");
break;
case 1:
console.log("Monday");
break;
case 2:
console.log("Tuesday");
break;
case 3:
console.log("Wednesday");
break;
case 4:
console.log("Thursday");
break;
case 5:
console.log("Friday");
break;
case 6:
console.log("Saturday");
break;
default:
console.log("输入错误");
break;
}
}
方法2
function test(num){
var arr=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
if(arr[num]){
console.log(arr[num]);
}else{
console.log("输入错误");
}
}
或者
function test(num){
var arr=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
arr[num] ? console.log(arr[num]):console.log("输入错误");
}