JavaScript 类数组

类数组定义

类数组其实不是数组,而是一个类似数组的对象。一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象。

即一个类数组对象应当符合以下两点:

  1. 使用数字作为属性名称
  2. 需要具备length属性

常见的类数组对象有 argumentsDOM方法返回结果

下面变量 arrayLike 就是一个类数组对象。

const arrayLike = {
  0:'张三',
  1:'李四',
  length:2
}

访问张三只需要:

arrayLike[0]

由于类数组对象length属性声明了对象有多少个属性,所以可以使用forwhile, do while遍历对象属性:

const arrayLike = {
  0:'张三',
  1:'李四',
  length:2
}
// for
for(let i = 0;i < arrayLike.length; i++) {
  console.log(arrayLike[i])
}
// while
...
// do while
...

字符串也是一种类数组,因为它也满足上述条件:

const str ="abc"
console.log(str.length) // 3
console.log(str[0]) // a

为什么设计类数组?

但是为什么需要类数组这种数据结构呢?下面说说我个人的理解。

JavaScript 是基于对象设计的语言,本质上字符串和数组都是属于对象类型。简单来说,数组就是一种特殊的对象:

const arr = ['张三','李四']
// 完全可以改写成对象方式
const arr = {
  0:'张三',
  1:'李四',
  length:2
}

数组特殊在于其可以通过索引来访问值,还具有 push, shift 等特有的方法。

数组 push 方法内部实现细节:

Array.prototype.push = function(value){
   this[this.length] = value
   // this.length++ 此处length值会在上局语句执行完毕后自增+1
}

push 时候其本质也是往对象上添加了一个数字类型的 key,并自动将 length 属性值加上 1。 push方法其实完全可以在对象上一样适用:

const obj = {
  0:'a',
  1:'b',
  2:'c',
  3:'d',
  length:4,
  push(value){
   this[this.length] = value
   this.length++  
  }
}

理论上可以将数组才具有的push,slice 等方法都加到类数组上面。但是这样为什么不直接使用数组就好了。其实恰恰相反,类数组不需要数组的那些方法,有了反而会画蛇添足。

下面看一个经典的类数组 arguments 对象

function sum(a,b){
    console.log(arguments)
}
sum(1,2)

arguments 就是一个类数组
在这里插入图片描述
由于函数的参数个数是外部传入的,传入的时候已经确认好了。如果 arguments 也有 push方法,那么arguments 就容易被开发者随意篡改。

function sum(a,b){
    arguments.push(3) // 如果为数组容易造成混乱
}
sum(1,2)

所以类数组对象的设计目的更多是只让你遍历和访问下标,而不是去添加或删除元素。当你需要设计一个方法,这个方法需要返回一个数组,但是又不想让这个数组有 push 等可能会修改这个数组的方法,这时候就可以考虑返回一个类数组对象了。

类数组转数组

不过在开发时候有时需要对类数组中数据进行过滤(filter)或者映射(map)等操作,所以就有很多类数组转数组的方法了。
1、Array.from

Array.from(arguments) // ES6 类数组转化成数组

2、es6 展开运算符(…)

function sum(a,b){
    console.log([...arguments]) // [1,2]
}
sum(1,2)

注:经测试,解构可对argumentsDOM方法返回结果起作用。对自建的类数组(如上文arrayLike)无效,会报错:arrayLike is not iterable
3、call,apply 方法

通过调用数组的 slice 方法来实现转换

Array.prototype.slice.call(arguments);
Array.prototype.slice.apply(arguments);

通过调用数组的 concat 方法来实现转换

Array.prototype.concat.apply([], arguments);

通过调用数组的 splice 方法来实现转换,此方法会清空arguments本身,并返回数组结构的参数

Array.prototype.splice.call(arguments, 0);
Array.prototype.splice.apply(arguments, [0]);

注: 此方法无法对DOM方法返回结果进行操作,会报:Failed to delete an indexed property from 'NodeList': Index property deleter is not supported.

4、改变了数组方法执行环境

function sum(a,b){

    const arr1 = Array.prototype.filter.call(arguments, value => value > 1) 
    
	const arr2 = Array.prototype.filter.apply(arguments, [value => value > 1]) 
    
    console.log(arr1, arr2) // [2] [2]
}
sum(1,2)

其实类数组转数组这种说法并不严谨。并不是类数组能力上的缺陷一定要转成数组,对于简单的取索引和遍历完全不需要转成数组,转成数组也只是类似于深拷贝了一份,原先的类数组还是原先的类数组!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

定栓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值