Why underscore

最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中。

阅读一些著名框架类库的源码,就好像和一个个大师对话,你会学到很多。为什么是 underscore?最主要的原因是 underscore 简短精悍(约 1.5k 行),封装了 100 多个有用的方法,耦合度低,非常适合逐个方法阅读,适合楼主这样的 JavaScript 初学者。从中,你不仅可以学到用 void 0 代替 undefined 避免 undefined 被重写等一些小技巧 ,也可以学到变量类型判断、函数节流&函数去抖等常用的方法,还可以学到很多浏览器兼容的 hack,更可以学到作者的整体设计思路以及 API 设计的原理(向后兼容)。

之后楼主会写一系列的文章跟大家分享在源码阅读中学习到的知识。

  • underscore-1.8.3 源码解读项目地址 https://github.com/hanzichi/underscore-analysis
  • underscore-1.8.3 源码全文注释 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/underscore-1.8.3-analysis.js
  • underscore-1.8.3 源码解读系列文章 https://github.com/hanzichi/underscore-analysis/issues

欢迎围观~ (如果有兴趣,欢迎 star & watch~)您的关注是楼主继续写作的动力

Main

很快,Array Functions 部分到了尾声,今天来做个了(xiao)结。

underscore 给数组(以及 arguments,这里特别说明下,underscore 的数组扩展方法,同样适用于 arguments)增加了 20 个扩展方法,值得一提的是,很多有意思的方法,比如 map,shuffle 等,都被放在了 Collection Functions 中。本文来看看 Array Functions 中还有哪些有意思的方法(之前没有被提及)。

_.compact

这个方法很有意思,它的作用是剔除数组中的假值,返回数组副本。

实现非常的简单:

_.compact = function(array) {return _.filter(array, _.identity);
};

_.filter 我们在以后会讲到,这里你可以把它理解为 Array.prototype.filter 的一个 polyfill,来看看 _.identity 是个什么东东。

_.identity = function(value) {return value;
};

乍一看,_.identity 似乎没什么卵用,传入一个参数,原封不动返回这个参数,什么鬼?而再看 _.compact 的实现,就会发现非常巧妙!细细品味下,直接过滤了数组的假值,而 _.identity 在源码中能在多个地方复用。

从这个方法可以想到 PHP 的 array_filter 函数。array_filter 的基本用法和 Array.prototype.filter 相似,都是为了过滤数组中的元素。

function isOdd($num) {return $num & 1;
}$a = Array(1, 2, 3);$a = array_filter($a, 'isOdd');var_dump($a);// array
//   0 => int 1
//   2 => int 3

但是,值得注意的是:

If no callback is supplied, all entries of array equal to FALSE (see converting to boolean) will be removed.

这就有点 6 了,直接把 _.filter 和 _.compact 两个方法合二为一了。

$a = Array(0, 1, 2, 3, null, false, 4);$a = array_filter($a);var_dump($a);// array
//   1 => int 1
//   2 => int 2
//   3 => int 3
//   6 => int 4

Array.prototype.filter 为何不设计成这样呢?没有 callback 传入的时候,直接过滤假值...

_.difference & _.without

先来看 _.without,它的作用是从数组中剔除指定的元素。

var a = [1, 2, 3, 4, 5];
var ans = _.without(a, 1, 2, 3);
console.log(ans); // [4, 5]

恩,没错,剔除数组 a 中的 value 为 1, 2, 3 的元素,这个过程中用 === 来进行比较。该方法传入的第一个参数是数组,后面的参数为单个元素。

而 _.difference 呢?和 _.without 的唯一区别是,第二个参数开始传入的是数组。(分别和数组中的元素比较)

var a = [1, 2, 3, 4, 5];
var ans = _.difference(a, [1, 2, 3], [5, 6]);
console.log(ans); // [4]

从 a 数组中剔除 1,2,3,5,6。

仔细一想,如果已经实现了 _.difference,我们把 _.without 的参数放入数组,然后传入 _.difference 就 ok 了!倒过来就不行了(思考下为什么)。

来看 _.difference 的实现,非常简单:

// _.difference(array, *others)
_.difference = function(array) {// 将 others 数组展开一层// rest[] 保存展开后的元素组成的数组// strict 参数为 true// 不可以这样用 _.difference([1, 2, 3, 4, 5], [5, 2], 10);// 10 就会取不到var rest = flatten(arguments, true, true, 1);// 遍历 array,过滤return _.filter(array, function(value){// 如果 value 存在在 rest 中,则过滤掉return !_.contains(rest, value);});
};

不熟悉 flatten 的可以看看 前文,当 shallow 和 strict 均为 true 时,展开一层,并且过滤非数组元素,即可以起到将多个数组合并的作用。之后利用 ._filter 进行过滤即可。

而 _.without 方法则建立在 _.difference 基础上。

_.without = function(array) {// slice.call(arguments, 1)// 将 arguments 转为数组(同时去掉第一个元素)// 之后便可以调用 _.difference 方法return _.difference(array, slice.call(arguments, 1));
};

总结

数组的扩展方法就解读到这里了,相关源码可以参考 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L450-L693 这部分。接下去要解读的是 Collection Functions 部分,所谓 Collection,正是 Object & Array,也就是说这部分方法既可以用于 Object 也能用于 Array,比如我们熟悉的 map,filter,shuffle 等等,都在这部分内。

放个预告,下一篇会暂缓下 Collection Functions,讲下 array-like 相关的东西,敬请期待。

PS:坚持一件事真的挺难,一个月来,每天坚持看点源码,几乎把所有业余时间花在了上面,写了 10 篇随笔,每篇文章写的时间不短,关键还需要构思,如何提炼出一个主题,如何写让人看了会有所收获,恩,继续坚持。请关注我的 Repo https://github.com/hanzichi/underscore-analysis 支持我~

【跟着子迟品 underscore】Array Functions 相关源码拾遗 小结相关推荐

  1. 【Android 异步操作】AsyncTask 异步任务 ( AsyncTask 异步任务执行方法 execute 方法相关源码解析 )

    文章目录 一.AsyncTask 异步任务执行方法 execute() 引入 二.AsyncTask 异步任务执行方法 execute() 三.sDefaultExecutor 线程池解析 四.exe ...

  2. 详述 Spring MVC 启动流程及相关源码分析

    文章目录 Web 应用部署初始化过程(Web Application Deployement) Spring MVC 启动过程 Listener 的初始化过程 Filter 的初始化 Servlet ...

  3. Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)

    前言 registerBeanPostProcessors initMessageSource 如何实际应用国际化处理 initApplicationEventMulticaster onRefres ...

  4. 跟着小马哥学系列之 Spring IoC(源码篇:@Import)

    跟着小马哥学系列之 Spring IoC(源码篇:@Import) 简介 @ Import 简介 元信息 元注解 属性 @Import 注解 value 属性取值范围 ImportSelector I ...

  5. 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  6. 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  7. 【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )

    文章目录 一.回调 StateChangedListener 接口 二.JobHandler 处理 ( 任务检查 ) 三.maybeRunPendingJobsH 方法 四.assignJobsToC ...

  8. 【Android 电量优化】JobScheduler 相关源码分析 ( ConnectivityController 底层源码分析 | 构造函数 | 追踪任务更新 | 注册接收者监听连接变化 )

    文章目录 一.ConnectivityController 连接控制器引入 二.ConnectivityController 构造方法解析 ( 注册接收者 ) 三.mConnectivityRecei ...

  9. linux htb 源代码,LINUX TC:HTB相关源码

    LINUX TC:HTB相关源码 收藏 HTB(hierarchy token buffer)是linux tc(traffic control)模块中的排队队列的一种.它的配置比CBQ要简单.同时实 ...

最新文章

  1. 没有场景,不做单点技术输出,360数科如何做金融科技的最佳实践?
  2. python3.8.1安装教程-python3.8.1 安装
  3. 程序员面试题精选100题(17)-把字符串转换成整数[算法]
  4. Python中*args 和**kwargs的用法
  5. hdu 2188悼念512汶川大地震遇难同胞——选拔志愿者(博弈)
  6. JasperReports JSF插件用例系列
  7. mysql 存储过程 循环结构 命名_mysql存储过程----循环结构
  8. C++子对象和堆对象
  9. 【NOIP2016提高A组五校联考2】running
  10. ENGINEER 05
  11. 使用outlook邮件服务器,使用OUTLOOK配置邮件服务
  12. python 绘图及可视化
  13. md 生成目录 码云_DuangDuangDuang!码云项目的 Readme.md 特殊技能
  14. 蓝海创意云丨建筑设计:BIM技术在异形建筑中的应用(以梅溪湖为例)
  15. Windows设备信息获取:(摄像头,声卡为例)Qt,WindowsAPI对比说明(2)
  16. Windows日常效率生产力开发环境工具个人集合
  17. 最简单深度学习Python实现(二分类问题)
  18. 前端登录界面通用模版
  19. visio取消捕捉连接点方法
  20. matlab loglog

热门文章

  1. Exchange 2010向外网发邮件的配置
  2. 分享:Dlib 17.49 发布,跨平台 C++ 通用库
  3. 分布式系统工程实现:GFSamp;Bigtable设计的优势,互联网营销
  4. ASP.NET中随机数生成及应用
  5. VS2005 和 SQL Server 2005 安装顺序不同会发生什么?
  6. 手把手教你走进Hyperledger Fabric
  7. centos执行-查看,复制,删除-命令的脚本
  8. Dockefile CentOS SSH 服务的实现
  9. SQL SERVER 查看并结束某个进程
  10. 老张喝茶 教你同步异步 阻塞与非阻塞(转)