每天一道面试题(1) - javascript中的类数组和鸭式辩形

今天决定每天写一道面试题(偶尔懒了也可以不写, 不强迫自己), 对前端常见的面试题进行一些话术的总结和知识点整合吧

正好今天听同事校招面试问到一个类数组, 那么就由此开始吧

本文将从以下几个方面进行讲述

什么是类数组

类数组, 顾名思义, 不是数组, 长的像数组;
其实类数组本质是一个对象, 只不过是具有如下两个特性的对象

  • 拥有length属性 和数字索引
  • 不具有普通数组的操作方法

具有length属性, 主要是为了保证类数组可以进行遍历

与数组的区别就是没有数组的方法, 比如pop,push,slice等等, 不能进行这些数组操作

为什么需要类数组 以及 常见的类数组有哪些

为什么需要类数组

因为在有些地方, 我们需要数据具有数组的形式但是又不能有数组的方法从而防止对这些数据进行改动, 因此就有了类数组

常见的类数组有哪些

arguments

函数参数

function args() {
    console.log(arguments)
    console.log(Object.prototype.toString.call(arguments))
    console.log(arguments.length)
}
args(1, 2, 3)
[Arguments] { '0': 1, '1': 2, '2': 3 }
[object Arguments]
3

由代码可见, arguments的本质上也是一个对象, 这个对象的构造函数是Arguments

HTMLCollection

通过getElementsByTagName和getElementsByClassName选择器筛选出的DOM元素
image

由图可见, HTMLCollection有length属性, 也是类数组; 它的构造函数是HTMLCollection

NodeList

通过querySelectorAll筛选出的NodeList
image

和HTMLCollection类似

鸭式辩形

其实上面的形式都是鸭式辩形
总结起来就是

const obj = {
  0:'a',
  1:'b',
  length:2
}

同时还可以给对象添加一些其他的函数比如

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

这样类数组就有了数组的push方法

类数组的遍历

上面提到过, 类数组其实是对象的变形, 所以类数组可以使用for in的遍历方法对对象进行遍历

但是这个方法会把类数组中的其他属性遍历出来, 比如length, push

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

所以对于类数组, 我们通常使用for循环的方式进行遍历, 因为类数组有length属性, 遍历到此就结束了

for (let i = 0; i < obj.length; i++) {
    console.log(obj[i])
}
a
b
c
d

而且由于类数组的key值一定是从0开始到某值, 这样也是使我们能取到obj[i]值的原因

for (let i = 0; i < 10; i++) {
    console.log(obj[i])
}
a
b
c
d
undefined
undefined
undefined
undefined
undefined
undefined

因为其他属性的key值不是i了, 而是length, push等

类数组转为数组

如果想要类数组使用数组上的某些方法, 可以使用Array原型上的方法

Array.prototype.slice.call(obj,1)
Array.prototype.map.call(a, function(x) { 
    return x.toUpperCase();
})
Array.prototype.push.call(obj, 3) //返回length的值5

使用数组上的slice和map方法可以返回一个数组

let arr = Array.prototype.map.call(obj, function (x) {
    return x.toUpperCase()
})
console.log(arr, Object.prototype.toString.call(arr))

let arr2 = Array.prototype.slice.call(obj)
console.log(arr2, Object.prototype.toString.call(arr2))
[ 'A', 'B', 'C', 'D' ] '[object Array]'
[ 'a', 'b', 'c', 'd' ] '[object Array]'

另外还有

Array.from(obj)

判断类数组

//判断是否是一个类数组
function isArrayLike(o) {
    if (
        o && //o非null, undefined
        typeof o === 'object' && // o是对象
        isFinite(o.length) && //o.length是有限数值
        o.length >= 0 && //o.length是非负值
        o.length === Math.floor(o.length) && //o.length是整数
        o.length < 4294967296 //o.length< 2^32
    ) {
        return true
    } else {
        return false
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值