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. MySQL基础(非常全)

    MySQL基础 一.MySQL概述 1.什么是数据库 ? 答:数据的仓库,如:在ATM的示例中我们创建了一个 db 目录,称其为数据库 2.什么是 MySQL.Oracle.SQLite.Access ...

  2. DevExpress TreeList使用心得

    来自:http://www.cnblogs.com/sndnnlfhvk/archive/2011/05/15/2046920.html 最近做项目新增光纤线路清查功能模块,思路和算法已经想好了,些代 ...

  3. 把自己Github上的代码添加Cocoapods支持

    转载请注明原链接:http://www.cnblogs.com/zhanggui/p/6003481.html 一.前言 这两天被cocoapods折磨的心力憔悴.看cocoapods官网的添加支持, ...

  4. 【原】iOS动态性(五)一种可复用且解耦的用户统计实现(运行时Runtime)

    声明:本文是本人 编程小翁 原创,转载请注明. 为了达到更好的阅读效果,强烈建议跳转到这里查看文章. iOS动态性是我的关于iOS运行时的系列文章,由浅入深,从理论到实践.本文是第5篇.有兴趣可以看看 ...

  5. ORACLE临时表总结

    临时表概念 临时表就是用来暂时保存临时数据(亦或叫中间数据)的一个数据库对象,它和普通表有些类似,然而又有很大区别.它只能存储在临时表空间,而非用户的表空间.ORACLE临时表是会话或事务级别的,只对 ...

  6. Failed to create AppDomain 'xxx'. Exception has been Failed to create AppDomain

    一服务器上的数据库全部被置于紧急模式(EMERGENCY),在错误日志里面能看到大量下面的错误 Failed to create AppDomain "YourSQLDba.dbo[runt ...

  7. ORACLE的SQL JOIN方式小结

    在ORACLE数据库中,表与表之间的SQL JOIN方式有多种(不仅表与表,还可以表与视图.物化视图等联结),官方的解释如下所示 A join is a query that combines row ...

  8. [MySQL] Buffer Pool Adaptive Flush

    Buffer Pool Adaptive Flush 在MySQL的帮助文档中Tuning InnoDB Buffer Pool Flushing提到, innodb_adaptive_flushin ...

  9. 【转载】PHP性能优化干货

    PHP优化对于PHP的优化主要是对php.ini中的相关主要参数进行合理调整和设置,以下我们就来看看php.ini中的一些对性能影响较大的参数应该如何设置. # vi /etc/php.ini (1) ...

  10. 关于一个sql的优化分析

    应用这边新上线了一个查询,正在跑,让我看下状态以及分析下能不能再快点. 如下sql: SELECT x.order_no , order_date+7/24 AS order_date, addres ...