浅谈 underscore 内部方法 group 的设计原理
前言
真是天一热什么事都不想干,这个月只产出了一篇文章,赶紧写一篇压压惊!
前文(https://github.com/hanzichi/underscore-analysis/issues/15)说到楼主开始解读 underscore.js 中的 Collection Functions 部分,看了一遍这部分的源码,很多方法都是一看便懂,不需要楼主过分解读。本文来聊聊内部方法 group 的设计,这会是 Collection Functions 部分的第二篇文章,也是最后一篇文章,关于这部分其他方法的实现,可以看我的 全文源码注释。
_.groupBy & _.indexBy & _.countBy
group 是 underscore.js 中的一个内部方法,顾名思义,为了分组而用。有三个 API 用到了这个方法,分别是 _.groupBy,_.indexBy,_.countBy。
来看看这三个 API 的作用。
_.groupBy,可以对一个数组的元素进行分组,如何分组?可以将元素传入一个迭代函数,根据迭代后的值进行分组,也可以传入一个字符串表示元素属性,根据该属性值进行分组。
_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
=> {1: [1.3], 2: [2.1, 2.4]}
_.groupBy(['one', 'two', 'three'], 'length');
=> {3: ["one", "two"], 5: ["three"]}
可以看到,返回的结果是一个对象,key 为经过迭代函数迭代后的值,或者属性值,value 为一个数组,保存迭代结果或者属性值一样的元素。
再来看 _.indexBy。
var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.indexBy(stooges, 'age');
=> {
"40": {name: 'moe', age: 40},
"50": {name: 'larry', age: 50},
"60": {name: 'curly', age: 60}
}
跟 _.groupBy 差不多,不同的是,_.indexBy 的结果,每个 key 值对应的是一个元素(传入 _.indexBy 方法的数组中的元素),而不是一个数组(Just like groupBy, but for when you know your keys are unique.)。如果原来数组中,有两个元素,经过迭代后(或者元素属性值)相同,那么在结果对象中,后者会覆盖前者。(所以最好确认数组中的元素经过迭代后的值没有相同的,或者属性值没有相同的)
var tmp = _.indexBy(['one', 'two', 'three'], 'length');
=> Object {3: "two", 5: "three"}
最后来看 _.countBy。还是返回一个结果对象,它的 key 值意思还是和 _.groupBy 以及 _.indexBy 相同,而 value 值为迭代结果(或者属性值)是该 key 值的元素的个数。
_.countBy([1, 2, 3, 4, 5], function(num) {
return num % 2 == 0 ? 'even': 'odd';
});
=> {odd: 3, even: 2}
group
这三个 API 功能相近,难道要写三个独立的方法?如果独立写,大概会是这样。
_.groupBy = function(obj, iteratee, context) {
// 返回结果是一个对象
var result = {};
// 根据 iteratee 值确定迭代函数
iteratee = cb(iteratee, context);
// 遍历元素
_.each(obj, function(value, index) {
// 经过迭代,获取结果值,存为 key
var key = iteratee(value, index, obj);
// TODO
// ...
});
// 返回结果对象
return result;
};
_.indexBy = function(obj, iteratee, context) {
// 返回结果是一个对象
var result = {};
// 根据 iteratee 值确定迭代函数
iteratee = cb(iteratee, context);
// 遍历元素
_.each(obj, function(value, index) {
// 经过迭代,获取结果值,存为 key
var key = iteratee(value, index, obj);
// TODO
// ...
});
// 返回结果对象
return result;
};
_.countBy = function(obj, iteratee, context) {
// 返回结果是一个对象
var result = {};
// 根据 iteratee 值确定迭代函数
iteratee = cb(iteratee, context);
// 遍历元素
_.each(obj, function(value, index) {
// 经过迭代,获取结果值,存为 key
var key = iteratee(value, index, obj);
// TODO
// ...
});
// 返回结果对象
return result;
};
大堆功能相似的代码,简直不能忍!每当这个时候,就要想到闭包,函数嵌套函数!
首先定义个函数 group,返回一个函数,为以上三个方法能调用的函数。听起来有点拗口,其实就是用 group 做个中间层,上代码体会下。
var group = function() {
return function(obj, iteratee, context) {
// 返回结果是一个对象
var result = {};
// 根据 iteratee 值确定迭代函数
iteratee = cb(iteratee, context);
// 遍历元素
_.each(obj, function(value, index) {
// 经过迭代,获取结果值,存为 key
var key = iteratee(value, index, obj);
// TODO
// ...
});
// 返回结果对象
return result;
};
};
_.groupBy = group();
_.indexBy = group();
_.countBy = group();
其实三个方法主要的操作,就是对上面的 group 中 result 对象的操作,我们可以传入一个方法,利用该方法对 result 对象进行操作。
以 _.groupBy 方法为例:
var group = function(behavior) {
return function(obj, iteratee, context) {
// 返回结果是一个对象
var result = {};
// 根据 iteratee 值确定迭代函数
iteratee = cb(iteratee, context);
// 遍历元素
_.each(obj, function(value, index) {
// 经过迭代,获取结果值,存为 key
var key = iteratee(value, index, obj);
// operate
behavior(result, value, key);
});
// 返回结果对象
return result;
};
};
var behavior = function(result, value, key) {
if (_.has(result, key))
result[key].push(value);
else result[key] = [value];
}
_.groupBy = group(behavior);
将对象当做参数传入函数,能在函数内改变对象值,正是利用了这个特点。而 _.indexBy 和 _.countBy,无非是改一下 behavior 函数的事了。
酱油了一篇解读,下文开始讲扩展函数了,其实最开始有解读 underscore 的欲望,正是因为函数部分的节流和去抖。
浅谈 underscore 内部方法 group 的设计原理的更多相关文章
- Unity iOS打开AppStore评星页面,浅谈Application.OpenURL()方法。
http://fairwoodgame.com/blog/?p=38 Unity iOS打开AppStore评星页面,浅谈Application.OpenURL()方法. Posted in Uni ...
- Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...
- 浅谈iOS中MVVM的架构设计与团队协作
说到架构设计和团队协作,这个对App的开发还是比较重要的.即使作为一个专业的搬砖者,前提是你这砖搬完放在哪?不只是Code有框架,其他的东西都是有框架的,比如桥梁等等神马的~在这儿就不往外扯了.一个好 ...
- IOS中 浅谈iOS中MVVM的架构设计与团队协作
今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
- 浅谈iOS中MVVM的架构设计与团队协作【转载】
今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
- 数据层的多租户浅谈(SAAS多租户数据库设计)
在上一篇“浅析多租户在 Java 平台和某些 PaaS 上的实现”中我们谈到了应用层面的多租户架构,涉及到 PaaS.JVM.OS 等,与之相应的是数据层也有多租户的支持. 数据层的多租户综述 多租户 ...
- [转载]数据层的多租户浅谈(SAAS多租户数据库设计)
原文:http://www.ibm.com/developerworks/cn/java/j-lo-dataMultitenant/index.html 在上一篇“浅析多租户在 Java 平台和某些 ...
- 浅谈MatrixOne如何用Go语言设计与实现高性能哈希表
目录 MatrixOne数据库是什么? 哈希表数据结构基础 哈希表基本设计与对性能的影响 碰撞处理 链地址法 开放寻址法 Max load factor Growth factor 空闲桶探测方法 一 ...
- 浅谈我对DDD领域驱动设计的理解
从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...
随机推荐
- jquery右键菜单
点击这里体验效果 如果要屏蔽页面原来的右键菜单,请设置disable_native_context_menu:true 以下是源代码: <!DOCTYPE html> <html&g ...
- webstorm+react+webpack-demo
序言:通过这个小例子你也许.大概.可能会掌握以下几点 1.webstorm如何使用命令行 2.如何使用webpack的loaders把json格式的文件转化为javascript文件 3.如何使用不同 ...
- 关于C#消息调度(作业日志)
在Windows定时作业中,其实有多种关于作业调度形式,比如Windows Services 和 Windows Form 都可以做到,各有各的好处.现在来介绍下使用插件的形式进行定时作业. 1.用q ...
- Android开发学习——android体系结构
Android的体系结构采用了分层架构的思想, 从上层到底层共包括四层,分别是应用程序程序层.应用框架层.系统库和Android运行时和Linux内核. 一 应用程序层 该层提供一些核心应用程序包,例 ...
- sqlserver下调试sql语句
现在版本的sqlServer已经支持调试功能了,但是在使用的时候用到的却很少(毕竟print习惯了..) 这里做一个笔记,简单的说明一下在sqlserver下调试的方法: declare @i int ...
- ButterKnife 8.2.1 大圣归来
零.前言 ButterKnife是一个视图注入的框架,主要帮我们解决无脑的findViewById.设置监听事件等等体力劳动. 一.引入 好消息是ButterKnife终于使用apt生成代码了,首先在 ...
- iOS--xuer(registration)
这个登录页面包含了自适应屏幕的大小,数字用户登录键盘是数字键盘.隐藏键盘.隐藏密码等等. ViewController.h #import <UIKit/UIKit.h> #import ...
- jxl导入导出实例
1 package com.tgb.test; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.util.Ar ...
- C# 6.0新特性
因为在博客中给出的代码大多数都使用了C#6.0的新特性,如果各位对C#6.0还不了解,可以简单的看一下这篇随笔.o( ̄▽ ̄)d 先来看一个Point类 public class Point { pub ...
- sql增删改查-转载
一.增:有2种方法 1.使用insert插入单行数据: 语法:insert [into] <表名> [列名] values <列值> 例:insert into Strdent ...