[Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法

时间:2022-05-13 02:19:00

前面有几条都讲过关于Array.prototype的标准方法。这些标准方法被设计成其他对象可复用的方法,即使这些对象并没有继承Array。

arguments对象

在22条中提到的函数arguments对象。它是一个类数组对象,并不是一个标准的数组,所以无法使用数组原型中的方法,因此无法使用arguments.forEach这样的形式来遍历每一个参数。这里我们必须使用call方法来对使用forEach方法。

function highlight(){
[].forEach.call(arguments,function(widget){
widget.setBackground('yellow');
});
}

forEach是一个函数对象,所以它继承了Function.prototype对象中的call方法。这里就可以使用一个指定的对象作为函数内部this的绑定对象来调用它,并紧随任意数量的参数。
## NodeList对象
在Web平台,DOM的NodeList类是另一个类数组对象。类似的document.getElementsByTagName会返回一个NodeList类数组对象。这个对象也没有继承自Array.prototype.

类数组对象

怎样构建一个类数组对象?

  • 具有一个范围在0到2^32-1的整形length属性

  • length属性大于该对象的最大索引。索引是一个范围在0到2^32-1的整数,它的字符串表示是该对象中的一个key

实现上面这两点,就可以使一个对象与Array.prototype中任一方法兼容。
一个简单的对象字面量也可以用来创建一个类数组对象。

var arrayLike={0:'a',1:'b',2:'c',length:3};
var res=Array.prototype.map.call(arrayLike,function(s){
return s.toUpperCase();
});
res;//['A','B','C']

字符串

也是可以表现为数组,因为它们是可索引,并且其长度也可以通过length属性获取。
因此,Array.protoype中的方法操作字符串时并不会修改原始字符串。

var res=Array.prototype.map.call('abc',function(s){return s.toUpperCase();});
res;//['A','B','C']

模拟数组

模拟数组的所有行为,归功于数组行为的两方面:

    • 将length属性值设为小于n的值会自动地删除索引值大于或等于n的所有属性

    • 增加一个索引值为n(大于或等于length属性值)的属性会自动地设置length属性为n+1

其中第2条规则不好实现,因为需要监控索引属性的增加以自动地更新length属性。

对于Array.prototype中的方法,这两条都不是必须的,因为在增加或删除索引属性的时候它们都会强制地更新length属性。
Array方法中只有一个不是通用的,即数组连接方法concat。该方法可以由任意的类数组接收者调用,但它会检查其参数[[Class]]属性。如果参数是一个真实的数组,那么concat会将该数组的内容连接起来作为结果;否则,参数将以一个单一的元素来连接。
例如,不能简单地连接一个以arguments对象作为内容的数组。

function namesColumn(){
return ['Names'].concat(arguments);
}
namesColumn('张三','李四','王五');//["Names", Arguments[3]0: "张三"1: "李四"2: "王五"callee: namesColumn()length: 3Symbol(Symbol.iterator): values()__proto__: Object]

使concat方法将一个类数组对象视为真实数组,需要把类数组转换为真正的数组。使用slice对类数组对象进行转换。

function namesColumn(){
return ['Names'].concat([].slice.call(arguments));
}
namesColumn('张三','李四','王五');//["Names", "张三", "李四", "王五"]

提示

  • 对于类数组对象,通过提取方法对象并使用其call方法来复用通用的Array方法

  • 任意一个具有索引属性和恰当length属性的对象都可以使用通用的Array方法

[Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法的更多相关文章

  1. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  2. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  3. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  4. &lbrack;Effective JavaScript 笔记&rsqb;第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  5. &lbrack;Effective JavaScript 笔记&rsqb;第40条:避免继承标准类

    ECMAScript标准库里配备了许多重要的类,如Array,function,以及Date等.扩展这些类生成子类可以方便完成很多工作,但它们的定义具有很多特殊的行为,所以很难写出行为正确的类. Ar ...

  6. &lbrack;Effective JavaScript 笔记&rsqb;第58条:区分数组对象和类数组对象

    示例 设想有两个不同类的API.第一个是位向量:有序的位集合 var bits=new BitVector(); bits.enable(4); bits.enable([1,3,8,17]); bi ...

  7. &lbrack;Effective JavaScript 笔记&rsqb;第68条:使用promise模式清洁异步逻辑

    构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...

  8. &lbrack;Effective JavaScript 笔记&rsqb;第66条:使用计数器来执行并行操作

    第63条建议使用工具函数downloadAllAsync接收一个URL数组并下载所有文件,结果返回一个存储了文件内容的数组,每个URL对应一个字符串.downloadAllAsync并不只有清理嵌套回 ...

  9. &lbrack;Effective JavaScript 笔记&rsqb;第22条:使用arguments创建可变参数的函数

    第21条讲述使用可变参数的函数average.该函数可处理任意数量的参数并返回这些参数的平均值. 如何创建可变参数的函数 1.实现固定元数的函数 书上的版本 function averageOfArr ...

随机推荐

  1. GridView点击行触发SelectedIndexChanged事件

    1.在<% @Page ...... %>指令中添加 EnableEventValidation="false" 2.在RowDataBound事件中添加 protec ...

  2. 基于Yahoo网站性能优化的34条军规及自己的见解

    1.尽量减少HTTP请求次数 终端用户响应的时间中,有80%用于下载各项内容,这部分时间包括下载页面中的图像.样式表.脚本.Flash等.通过减少页面中的元素可以减少HTTP请求的次数,这是提高网页速 ...

  3. Razor语法

    1. 截取字符串  @(i.Title.Length > 18 ? i.Title.Substring(0, 18) + "" : i.Title) 2. 格式化日期  @s ...

  4. spring:bean的定义

    一个完整的Bean的配置文件: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans ...

  5. 人人API 分享到人人功能 修改版

    最近在搞一个日程管理网站, 需要实现分享到人人功能, 所以找了一下人人API, 然后根据自己需要修改了一下. 首先得有一个人人给的js文件, 如下: var Renren = Renren || {} ...

  6. 给sftp创建新用户、默认打开和限制在某个目录

    一.环境: CentOS 6.8 使用 FileZilla 进行 sftp 连接 二.背景 给外包的工作人员提供我司服务器的某一目录的访问(包括读写)权限,方便他们部署代码文件. 之所以是某一目录的访 ...

  7. win7下通过easyBCD引导安装Ubuntu16&period;04(并处理遇到的坑)

    Ubuntu16.04作为目前最新版本的ubuntu系统,相信很多人都想在自己的电脑上安装一下,然而系统的安装方法各式各样,u盘法.grub引导法等等,这里我将介绍在win7系统下用easyBCD软件 ...

  8. vue项目首屏加载优化实战

    问题 单页面应用的一个问题就是首页加载东西过多,加载时间过长.特别在移动端,单页面应用的首屏加载优化更是绕不开的话题.下面我会写出我在项目中做的一些优化,希望大家能够相互讨论,共同进步. 我的项目vu ...

  9. WEB控件没有什么所谓好不好,而是用得好不好

    这几天Insus.NET有写几篇博文,虽然写得没怎么样,但均是Insus.NET现实开发过程中所遇或是所想的一些内容.<没有什么,开发ASP.NET时随便写写,想到什么写什么>http:/ ...

  10. 20155233 刘高乐 Exp9 Web安全基础

    WebGoat 输入java -jar webgoat-container-7.1-exec.jar 在浏览器输入localhost:8080/WebGoat,进入WebGoat开始实验 Cross- ...