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
趁着今天是工作日的末了一天,把源码解读部份 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 扩大要领相干代码,继承为人人整顿有意义的东西,种种奇淫怪巧,敬请期待。