Why underscore

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

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

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

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

Main

趁着今天是工作日的最后一天,把源码解读部分 Object Functions 更新完毕。

如果你有心,可能就会发现楼主之前的解读系列文章说的都是 Object 上的扩展方法,也就是源码中 Object Functions 部分。underscore 为 5 种类型添加了扩展方法,分别是 Object -> Array -> Collection -> Function -> Utility,这也正是楼主的源码解读顺序(并不是源码顺序)。其中,Object 上的扩展方法多达 38 个,方法多并不代表代码多,比如类型检测,两行代码就可以搞定好几个方法,而上一篇中说的 _.isEqual 方法,却要百来行去实现。今天是 Object Functions 部分的最后一篇,我们来看看楼主认为的几个没被解读过的但是却有意思的方法的源码。(其实很多方法使用简单,实现也非常简单,有兴趣的同学可以自己扒下源码)

_.pick

首先来看看 _.pick 方法,该方法传入一个对象,然后删选对象的键值对,返回一个对象副本。

直接来看例子:

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, ['name', 'age']);
=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
=> {age: 50}

一目了然,第一个参数 obj 是对象,第二个参数可以是一系列的 key 值,也可以是数组(数组中含 key),也可以是迭代函数,我们根据 key 值,或者迭代函数来过滤 obj 中的键值对,返回新的对象副本。

如果让我来设计,估计会根据参数来判断类型,然后写几个 if-else,每个 if-else 分支里的内容毫无关联。但是 underscore 的写法简直美妙,将几种情况转为了一种。

// 如果第二个参数是函数
if (_.isFunction(oiteratee)) {
  keys = _.allKeys(obj);
  iteratee = optimizeCb(oiteratee, context);
}

首先 if-else 是不可避免的,如果传入的第二个参数是 function,那么就是传入迭代函数了,根据 context(this)返回新的迭代函数(optimizeCb 我以后会讲,就是规定了迭代函数中的 this 指向,不是很重要,这里可以选择性忽略)。

如果第二个参数不是函数,则后面的 keys 可能是数组,也可能是连续的几个并列的参数。这里我们要用到 underscore 中另一个重要的内部方法,flatten,它的作用是将嵌套的数组展开,这个方法我以后会分析,这里知道它的作用就可以了。

else {
  // 如果第二个参数不是函数
  // 则后面的 keys 可能是数组
  // 也可能是连续的几个并列的参数
  keys = flatten(arguments, false, false, 1);

  // 也转为 predicate 函数判断形式
  // 将指定 key 转化为 predicate 函数
  iteratee = function(value, key, obj) { return key in obj; };
  obj = Object(obj);
}

也转为和传入迭代函数一样的形式,就可以用一个方法判断了,而且 keys 变量在两种情况下的意义是不同的,真的非常巧妙。这点令我思考良多,很多时候的代码冗余,其实大概是自己代码能力太差了吧,打死我也想不到这样做。

_.create

_.create 方法非常简单,根据你给的原型(prototype),以及一些 own properties,构造新的对象返回。

举个简单的例子:

var Person = function() {};

Person.prototype = {
  show: function() {
    alert(this.name);
  }
};

var me = _.create(Person.prototype, {name: 'hanzichi'});

console.log(me);

// Object {name: "hanzichi"}
//   name: "hanzichi"
//   __proto__: Object
//     show: function()

其实 me 变量就是一个拥有 name 作为 own properties,且用 Person 函数构造的对象。

如果浏览器支持 ES5,我们可以用 Object.create()

var Person = function() {};

Person.prototype = {
  show: function() {
    alert(this.name);
  }
};

var me = Object.create(Person.prototype);

_.extendOwn(me, {name: 'hanzichi'});

console.log(me);

如果不支持 ES5,我们可以新定义一个构造函数,将该构造函数的 prototype 赋值为已知的 prototype 变量,然后用 new 运算符来获取实例:

var Person = function() {};

Person.prototype = {
  show: function() {
    alert(this.name);
  }
};

var _Person = function() {};

_Person.prototype = Person.prototype;

var me = new _Person();

_.extendOwn(me, {name: 'hanzichi'});

console.log(me);

undercore 的实现思路也大抵如此。

_.tap

本来打算把 _.tap 讲掉,突然觉得跟链式调用一起讲比较好,挖个坑。

小结

关于 Objects Function 部分的源码剖析就到这了,具体这部分代码可以参考 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L901-L1269。虽然说看完了这部分代码,但是要真正理解消化还是需要时间的,我只能说自己理解了 90% 左右,欢迎探讨交流。

接下去应该会着手看 Array 扩展方法相关代码,继续为大家整理有意思的东西,各种奇淫怪巧,敬请期待。

【跟着子迟品 underscore】Object Functions 相关源码拾遗 & 小结的更多相关文章

  1. 【跟着子迟品 underscore】Array Functions 相关源码拾遗 & 小结

    Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. 阅读一些著名框架类库的源码,就好像和一个个大师对 ...

  2. 【跟着子迟品 underscore】如何优雅地写一个『在数组中寻找指定元素』的方法

    Why underscore (觉得这部分眼熟的可以直接跳到下一段了...) 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. ...

  3. 【跟着子迟品 underscore】JavaScript 中如何判断两个元素是否 "相同"

    Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. 阅读一些著名框架类库的源码,就好像和一个个大师对 ...

  4. 【跟着子迟品 underscore】JavaScript 数组展开以及重要的内部方法 flatten

    Why underscore (觉得这一段眼熟的童鞋可以直接跳到正文了...) 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. ...

  5. 【跟着子迟品 underscore】for ... in 存在的浏览器兼容问题你造吗

    Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. 阅读一些著名框架类库的源码,就好像和一个个大师对 ...

  6. 【跟着子迟品 underscore】常用类型判断以及一些有用的工具方法

    Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. 阅读一些著名框架类库的源码,就好像和一个个大师对 ...

  7. 【跟着子迟品underscore】从用 `void 0` 代替 `undefined` 说起

    Why underscore 最近开始看 underscore源码,并将 underscore源码解读 放在了我的 2016计划 中. 阅读一些著名框架类库的源码,就好像和一个个大师对话,你会学到很多 ...

  8. Volley 图片加载相关源码解析

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47721631: 本文出自:[张鸿洋的博客] 一 概述 最近在完善图片加载方面的 ...

  9. MFC界面相关源码

    这是这4篇MFC界面的相关源码.建议学习Visual C++的看看这2本微软官方出的教材. [MFC Windows程序设计(第2版,修订版)](美)Jeff Prosise著 [Windows程序设 ...

随机推荐

  1. EasyUI弹出窗口实例

    效果体验:http://hovertree.com/texiao/jeasyui/1.htm 源代码下载:HovertreeJEasyUI HTML文件代码: <!DOCTYPE html> ...

  2. js去掉字符串的空格

    //去左空格; function ltrim(s){ return s.replace(/(^s*)/g, ""); } //去右空格; function rtrim(s){ re ...

  3. 时空地图 TimeGIS.com 中生成等值线

    在我的地图软件TimeGIS中加入了等值线生成的功能: 等值线的生成使用了wCoutour库, 代码根据这里的例子修改,http://www.06climate.com/view/1244.html ...

  4. Android—自定义控件实现ListView下拉刷新

    这篇博客为大家介绍一个android常见的功能——ListView下拉刷新(参考自他人博客,网址忘记了,阅读他的代码自己理解注释的,希望能帮助到大家): 首先下拉未松手时候手机显示这样的界面: 下面的 ...

  5. 谈谈iOS app的线上性能监测

    在移动端开发者中最重要的KPI应该是崩溃率.当崩溃率稳定下来后,工作的重心就应该转移到性能优化上.那么问题来了,如果你的项目也没有接入任何性能监测SDK,没有量化的指标来衡量,那你说你优化了性能领导信 ...

  6. sqlserver下调试sql语句

    现在版本的sqlServer已经支持调试功能了,但是在使用的时候用到的却很少(毕竟print习惯了..) 这里做一个笔记,简单的说明一下在sqlserver下调试的方法: declare @i int ...

  7. UITabBarController 更改tabbariteam上的选中图片

    首先遵守“ UITabBarControllerDelegate ”协议 再在- (void)viewDidLoad {}方法中设置代理“ self.tabBarController.delegate ...

  8. AFN3.0封装

    总结了一下AFN3.0封装,也借鉴了其他人总结的,整理如下,希望多交流,互相进步 // // XJYSessionManager.h// // Created by XJY on 16/10/17. ...

  9. SQLServer中的页如何影响数据库性能 (转)

    无论是哪一个数据库,如果要对数据库的性能进行优化,那么必须要了解数据库内部的存储结构.否则的话,很多数据库的优化工作无法展开.对于对于数据库管理员来说,虽然学习数据库的内存存储结构比较单调,但是却是我 ...

  10. Linux SendMail发送邮件失败诊断案例(二)

    Linux上Sendmail经常由于一些配置问题,导致邮件发送失败,下面整理.收集了一些邮件发送失败.异常的案例. 案例1:在新服务器上测试sendmail发送邮件时,发现邮件发送不成功,检查/var ...