原文: https://zswfx.com/articles/5dc8f64a9cf7c17b240e5c6c

我们经常在函数参数里面使用如下操作 Array.prototype.slice.call(arguments, 1), 这样的操作,类似还有 Object.prototype.toString.apply(o)这种操作,为什么可以这样玩呢?

前言

我们经常通过数组的方法去操作类数组,还会使用一些JS对象的方法来获取一个对象的真实的构造函数对象名称。考虑类数组不是一个数组,是一个对象类似如下:

{
    "0": "b",
    "1": "a",
    "length": 2
}

这样就可以使用,为什么呢?

探索

为了搞清上面问题,我们就需要从两个方面入手:

  • call/apply 定义
  • Array.prototype.slice、Object.prototype.toString

第一个需要找一下call/apply 调用流程,第二个看看规范如何定义这些方法

就已apply 为例(call类似), 具体方法以slice和toString为例

apply 规范

使用apply方法,有两个作用

  • 1-8 处理通过 apply 方法传入的参数
  • 9 处理改变函数的this值,并调用函数

上面调用函数,我们接下来就继续看看函数如何处理

Array.prototype.slice

通过规范可以看出,Array也是通过key值获取的,在第10步中可以看到循环获取对象值,通过对象 [[Get]]的方式来获取。

在每个数组方法后面,我们可以看到这样一句话:

使用数组的所有方法,不一定要求对象是数组,只要符合能够通过递增的key值可以获取的类数组对象即可使用.

下面继续看看 toString

toString

我们正常使用 Object.prototype.toString.apply({}) 的结果是 [object Object]. 上面是规范结果

  • 第1步,确定 undefined 值为 [object Undefined]
  • 第2步,确定 null 值为 [object Null],
  • 第3步,通过内部方法 toObject 得到结果 (稍后说明toObject方法)
  • 第4步,获取内部 [[Class]]
  • 第5步,拼接字符串 [object [[Class]], ] 返回结果

由此可得知,我们得到结果其实也是引擎根据规范来处理的。

toObject

toObject 的结果就是返回原始值(Primive Value)的盒装对象(box model object).

最后 [[Class]]的获取结果是一个说明对象分类名称的字符串。

最后

最近探索规范,发现越来越多想法和只是和规范一一验证。探索规范过程也是一种进步过程,任何小的改变,都是有迹可循,任何东西都来自规范。正如有理论支持的代码,才是坚不可摧,否则就如同一盘散沙。

欢迎交流.

zsirfs
832 声望24 粉丝

菜鸟挣扎努力的去学习