概述

很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以就了结研究underscore源码这一心愿吧。

underscore.js源码研究(1)

underscore.js源码研究(2)

underscore.js源码研究(3)

underscore.js源码研究(4)

underscore.js源码研究(5)

underscore.js源码研究(6)

underscore.js源码研究(7)

underscore.js源码研究(8)

参考资料:underscore.js官方注释undersercore 源码分析undersercore 源码分析 segmentfault

链式调用

对于一个对象的方法,我们可以在方法里面return this来使它支持链式调用。如果不修改原方法的源码,我们可以通过下面的函数使它支持链式调用。

//其中obj是一个对象,functions是对象的方法名数组
function chained(obj, functions) {
//由于functions是一个数组,所以可以使用foreach
functions.forEach((funcName) => {
const func = obj[funcName];
//修改原方法
obj[funcName] = function() {
func.apply(this, arguments);
return this;
}
})
}

示例如下:

let speaker = {
haha() {
console.log('haha');
},
yaya() {
console.log('yaya');
},
lala() {
console.log('lala');
}
} chained(speaker, ['haha', 'lala', 'yaya']);
speaker.haha().yaya().haha().lala().yaya();

输出如下:

haha
yaya
haha
lala
yaya

underscore.js里面的链式调用

underscore.js里面的链式调用与上面的稍微有些不同。

它的机制是这样的:

  1. 把underscore.js的方法全部挂载到_下面。
  2. 利用_.function方法遍历所有挂载在_下面的方法,然后挂载到_.prototype下面,这样生成的underscore对象就可以直接调用这些方法了。
  3. 在把方法挂载到_.prototype下面的时候,会利用类似上面的函数对方法进行改写(增加return this)。
  4. 在改写的时候建立一个标识_chain,来标识这个方法能不能链式调用。

下面来具体看看是怎么运作的:

首先,利用下面的函数,可以得到一个数组,这个数组里面全是挂载到_下面的方法名字

_function = _.methods = function(obj) {
var names = [];
for( var key in obj) {
if(_.isFunction(obj[key])) names.push(key);
}
return names.sort();
};

然后我们对每一个方法名字,把它挂载到_.prototype下面

_.mixin = function(obj) {
_.each(_.functions(obj), function(name) {
var func = _[name] = obj[name];
_.prototype[name] = function() {
var args = [this._wrapped];
push.apply(args, arguments);
return chainResult(this, func.apply(_, args));
};
});
};
_.mixin(_);

从上面可以看到,在挂载的时候返回一个chainResult方法处理过的东西。而args就等于原对象+参数1+参数2+...组成的数组,所以func.apply(_, args)就是_[func](原对象,参数1,参数2,...)处理后的结果

再来看看chainResult是怎么样的:

var chainResult = function(instance, obj){
return instance._chain ? _(obj).chain() : obj;
};

它判断如果原对象能够链式调用,那么处理后的结果obj也能够链式调用。怎么让结果也能链式调用呢?答案是使用_.chain方法:

_chain = function(obj) {
var instance = _(obj);
instance._chain = true;
return instance;
}

这个方法和我们最开始的chained方法差不多,但是它会把原对象转化为underscore对象,并且这个对象的_chain属性为真,即它能够被链式调用。

所以如果我们要在underscore.js中实现链式调用的话,直接用chain方法即可,实例如下:

_([1,2]).push(3).push(5) //输出4,并不是我们想要的
_([1,2]).chain().push(3).push(5).value() //输出[1, 2, 3, 5],正是我们想要的

可以看到,我们上面用到了value()函数,它能够中断链式调用,并不返回指针而是返回值,代码如下:

_.prototype.value = function() {
return this._wrapped;
}

等等,_wrapped又是什么?它是生成underscore对象前的原对象,看下面的代码:

var _ = function(obj) {
if(obj instanceof _) return obj;
if(!(this instanceof _)) return new _(obj);
this._wrapped = obj;
}

也就是说,在使用_生成underscore对象的时候,把原对象储存在_wrapped属性里面了,所以_wrapped就是原对象。

underscore.js源码研究(8)的更多相关文章

  1. underscore.js源码研究(7)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  2. underscore.js源码研究(6)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  3. underscore.js源码研究(5)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  4. underscore.js源码研究(4)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  5. underscore.js源码研究(3)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  6. underscore.js源码研究(2)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  7. underscore.js源码研究(1)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  8. underscore.js源码解析(五)—— 完结篇

    最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...

  9. underscore.js 源码

    underscore.js 源码 underscore]JavaScript 中如何判断两个元素是否 "相同" Why underscore 最近开始看 underscore.js ...

随机推荐

  1. vi三种模式的切换

    基础上vi/vim共分为三种模式,分别是命令模式,输入模式和底线命令模式. 一.命令模式 用户刚刚启动vi/vim,便进入了命令模式. 在此状态下敲击键盘动作会被vim识别为命令,而非输入字符.比如我 ...

  2. vbs解析 JSON格式数据

    Function jsonParser(str,jsonKey) Set sc = CreateObject("MSScriptControl.ScriptControl") sc ...

  3. SPRING 集成 activemq 的 topic 模式

    概要 activemq 支持两种模式: 1.队列模式 2. 发布订阅者模式,topic有一个主题可以有多个订阅者.这种情况可以将一个消息,分发到多个消费者. 比如我有这样一个案例,用户需要同步,而且需 ...

  4. js 上传文件

    <input id="file_Up" name="file_Up" type="file" onchange="getFi ...

  5. linux cp操作,每天学习一点

    指令名称:cp(copy)功能介绍:将一个文件复制至另一个文件,或将数个文件复制至另一目录. 语法格式: cp [options] source dest  cp [options] source.. ...

  6. 阿里云oss视频上传不能在线播放,js,javascript,在线播放器,插件

    网页视频播放插件 发现阿里云oss储存,上传了视频不能在线播放. 解决方法:使用插件播放即可解决. <html> <head> <meta charset="u ...

  7. 个人理解的int数组和char数组

    char数组中不论是一维还是二维的,在程序执行时每一块的分离依据都是以提供的起始地址到'\0'为一个处理的字符串.所以关于char[]的函数都是只提供相应起始地址作为形参就可以. char[]互相交换 ...

  8. _编程语言_C语言_C++_时间

    C++ 标准库没有提供日期类型,使用C预压的日期和事件操作. 使用时引入头文件  <ctime> . 四个和事件相关的函数: clock_t // 系统时间和日期表示为某种整数time_t ...

  9. springMvc里的mvc:resources与静态资源的访问

    在进行Spring MVC的配置时,通常我们会配置一个dispatcher servlet用于处理对应的URL.配置如下:   <servlet>   <servlet-name&g ...

  10. 【git】git简单使用教程

    git的简单使用教程: 1.安装git bash客户端 2.打开git bash,cd到需要存储代码的路径下, 执行:git clone -b deploy ssh://git@gitlab.xxxx ...