Go to comments

JavaScript 类数组

类数组

1. 可以利用属性名模拟数组的特性

2. 可以动态的增长length属性

3. 如果强行让类数组调用push方法,则会根据length属性值的位置进行属性的扩充

一、arguments是类数组

类数组的意思是长的像数组,也可以拿它当数组用,但它就不是数组


我们接触过一个类数组,arguments实参列表就是类数组

function test () {
  console.log(arguments);
}

test(1,2,3,4,5,6); // Arguments(6) [1, 2, 3, 4, 5, 6, callee: ƒ, Symbol(Symbol.iterator): ƒ]


其实arguments不是数组,看着像数组,但数组有的方法arguments全没有,比如push一个7进去

function test () {

	console.log(arguments);

	arguments.push(7); // Uncaught TypeError: arguments.push is not a function
}

test(1,2,3,4,5,6);

系统报错 arguments.push is not a function 意思是没有这个方法。


是数组就有push方法,说明arguments不是数组,那为什么arguments长得像数组呢?

我们管这种数组叫类数组,我们探究一下类数组是怎样构成的


二、类数组是怎样构成的

1、用对象模拟数组的特征

obj是一个对象,对象的属性可以是任何一种形式的,而且属性名可以用双引号(可以用也可以不用),下面obj对象属性名用双引号

var obj = {
	"0" : 'a', // 属性名"0"用双引号,当然直接写0也可以
	"1" : 'b',
	"2" : 'c'
}

console.log(arr[0]); // a

obj[0]  对象obj这样就有点意思


arr[0]  和数组arr访问起来差不太多

var arr = ['a', 'b', 'c'];

console.log(obj[0]); // a

2、可以动态的增长length属性

现在obj还是对象,我们改一改,给obj对象加个length属性,属性值是3,属性名都加双引号

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	"length" : 3
}

console.log(obj); // {0: "a", 1: "b", 2: "c", length: 3}


再加一个push属性,push属性是Array.prototype.push上的方法

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	"length" : 3,
	"push" : Array.prototype.push
}

console.log(obj); // {0: "a", 1: "b", 2: "c", 3: "d", length: 4, push: ƒ}


这样一个类数组的基本形态就已经构建完了,然后怎么用呢?

obj对象有push方法,只不过拿的是别人的,obj.push( ) 现在obj调用push方法,push方法里面的this就是obj了


arr.push( "d" )  增加一个d进去好使吗?

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	"length" : 3,
	"push" : Array.prototype.push
}

obj.push('d'); // push一个"d"进去

console.log(obj); // {0: "a", 1: "b", 2: "c", 3: "d", length: 4, push: ƒ}

1). 会发现返回结果加了一个 3 : d 不是我们写的

2). 并且length属性的值变成4了


这些都是一个对象不能具备的,为什么调用了一个push()方法,又加东西又变东西的?

这块我们探究一下,这样的就叫类数组

3、类数组必须有几个组成部分

1). 首先属性要为索引属性,

     什么叫索引属性?数字( 第0位、第1位... )

2). 然后必须有length属性,最好加上push()方法

3). 如果不加push()方法也叫类数组,类数组最佳关注点就是要有length属性,其它的都好说,一定要有length没有length不叫类数组


这样的obj是对象,可以当做对象来用,只不过它用起来就跟数组一样,可这还不像数组,怎么样让它变成跟数组差不多呢?

4、再添加splice属性

再给obj对象加一个属性让它变的像数组splice()方法

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	"length" : 3,
	"push" : Array.prototype.push,
	"splice" : Array.prototype.splice // 再加一个splice方法
}

console.log(obj); // Object(3) ["a", "b", "c", push: ƒ, splice: ƒ]


这就是一个定律了,

一旦给一个对象加上splice方法之后,这个对象自此之后,长的就完全是数组的样了


但是obj是不是对象呢?是对象

可不可以当数组一样用呢?可以当数组一样用

是对象可以当数组一样用,这就叫类数组,类数组有很多好处一会在说


三、强行让类数组调用push方法

如果强行让类数组调用push方法,则会根据length属性值的位置进行属性的扩充

1、先看看Array.prototype.push 里面写的代码是什么?

不考虑多个参数的,就传一个target参数

Array.prototype.push = function(target){

    this[this.length] = target;  // 第一步:增加一个属性
	this.length ++;              // 第二部:length加加

}


对象obj有没有length属性,我们设置了length属性,对象有length就能经过一系列的处理了

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	"length" : 3,
	"push" : Array.prototype.push,
	"splice" : Array.prototype.splice
}

Array.prototype.push = function(target){

	this[this.length] = target;
	this.length ++;

}

obj.push('d'); 

console.log(obj);

push方法

1). lenght位是第3位,应该是 d

2). 然后length加加,lenght变成4

image.png

2、阿里巴巴出的面试题

问对象obj打印出来是什么样?

var obj = {
 "2" : 'a',
 "3" : 'b',
 "length" : 2,
 "push" : Array.prototype.push
}

obj.push('c');
obj.push('d');

console.log(obj); // {2: "c", 3: "d", length: 4, push: ƒ}



/*------------------------------------------------------------

这种形式叫类数组,叫对象也行只不过换个名。也没给splice属性,没让它长的那么像。push进去两个字母,最后obj是什么样的?

这是错的
obj = {
	"2" : 'a',
	"3" : 'b',
	"4" : 'c',
	"5" : 'd',
	"length" : 4,
}
这也是错的
obj = {
	"2" : 'a',
	"3" : 'c',
	"4" : 'd',
}

看push方法内部原理
Array.prototype.push = function(target){
	obj[obj.length] = target;  // 第一步,增加一个属性
	obj.length ++;             // 第二部,length加1
}

分析push执行
1.因为obj.length=2,push"c",所以2 : c 
2.然后length++变成3
3.再来push(d),d放3这,length++最后得4

这是对的
var obj = {
    "2" :"c",
    "3" : "d"
    "length" : 4
}

------------------------------------------------------------*/


这道题不知道push的内部原理,懂不了类数组。

类数组的关键点在length,length决定在那一位赋东西,

因为push方法里面读的是length,所以会把原来的"2:a"、"3 : b"覆盖掉的,走一下length就明白了。


重做一下这个道题,最后结果是什么?

var obj = {
	"1" : 'a',
	"2" : 'c',
	"3" : 'd',
	"length" : 3,
	"push" : Array.prototype.push
}

obj.push('b');

console.log(obj); // {1: "a", 2: "c", 3: "b", length: 4, push: ƒ}


这是类数组特殊的一个情况,我们学习怎么样往类数组里面push东西,是根据它length的改变而改变,

类数组有很多应用,可以把类数组当做一个数组来用,完全的没问题,而且类数组本身是对象,所以类数组具备数组和对象两种特性,它存储东西更强大有些

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	name : 'abc',
	age : 123,
	length : 3, // 类数组必须有lenght属性
	push : Array.prototype.push,
	splice : Array.prototype.splice
}

console.log(obj); // 对象obj像数组一样 Object(3) ["a", "b", "c", name: "abc", age: 123, push: ƒ, splice: ƒ]

console.log(obj.name); // abc

console.log(obj.age); // 123

console.log(obj.length); // 有数组的长度 3


既能像数组一样用也能像对象一样用,怎么把所有属性全遍历出来? 

"for in"循环

var obj = {
	"0" : 'a',
	"1" : 'b',
	"2" : 'c',
	name : 'abc',
	age : 123,
	length : 3,
	push : Array.prototype.push,
	splice : Array.prototype.splice
}

for(var prop in obj){
	console.log(obj[prop]);
}


//循环结果:
// a
// b
// c
// abc
// 123
// 3
// ƒ push() { [native code] }
// ƒ splice() { [native code] }

类数组的好处就是把数组和对象的特性全拼到一起,但也有一点问题,它并不是所有的数组方法都能用,除非我们自己给添。

DOM方法所能生成的,所有类似于数组的东西全是类数组,

以后高级编程的时候全是类数组了,所以对类数组必须了解到这个深度,这已经是最深了,不用再深了。

四、数组作业

1、第一个作业,封装一个type方法

因为系统的typeof方法,返回结果不是很精准,比如null分辩不出来,null返回的是对象。

现在要完全分辩出来每一个要传进去的东西

typeof([])                       传进去数组,返回array

typeof({})                       传进去对象,返回object

typeof(function)            传进去function,返回function

typeof(new Number())  传进去new Number()数字类型对象,

                                       返回number object(number类型的包装类对象)

typeof(123)                    传进去数字123,返回number


typeof(new Number()) 怎么样返回一个对象形式的数字

Object.prototype.toString.call(new Number(123)); //返回"[object Number]"

Object.prototype.toString.call(123); //call数字打印的也是"[object Number]"

call数字打印的也是"[object Number]",但是没关系,Number可以通过typeof过滤掉,然后过滤不掉的是对象。

对象在放到Object.prototype.toString.call()里面去,能分变出来是什么类型的对象,数组对象、对象对象、还是包装类对象。

2、第二个作业,数组去重

要求在原型链上编程。(unique独一无二的意思,这个人这个事独一无二,比如求婚可以这么说)

Array.prototype.unique = function(){

}

var arr = [1,1,1,1,0,0,0,a,b,a,b];

arr.unique(); // 任意一个数组,数组调用完之后,返回的是 [1, 0, a, b]

这个数组去重非常重要。

提示,可以利用对象的一些特性来写数组去重,叫哈希(键值对的形式)的方法。利用对象是最快的,写完不会超过十行,代码非常少,其实很简单。



Leave a comment 0 Comments.

Leave a Reply

换一张