// Function (ahem) Functions
// ------------------ // Determines whether to execute a function as a constructor
// or a normal function with the provided arguments.
/*
判断一个函数是按照构造函数还是普通函数执行??????????????????????????????????????????????????????????
*/
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
var self = baseCreate(sourceFunc.prototype);// 原型继承sourceFourceFunc.prototype,返回一个空对象
var result = sourceFunc.apply(self, args);//
if (_.isObject(result)) return result;
return self;
}; // Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// available.
/*
绑定函数 function 到对象 object 上, 也就是无论何时调用函数, 函数里的 this 都指向这个 object.任意可选参数 arguments 可以传递给函数 function , 可以填充函数所需要的参数,这也被称为 partial application。
(愚人码头注:partial application翻译成“部分应用”或者“偏函数应用”。partial application可以被描述为一个函数,它接受一定数目的参数,绑定值到一个或多个这些参数,并返回一个新的函数,这个返回函数只接受剩余未绑定值的参数。参见:http://en.wikipedia.org/wiki/Partial_application。感谢@一任风月忆秋年的建议)。
*/
_.bind = restArgs(function(func, context, args) {
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
var bound = restArgs(function(callArgs) {
return executeBound(func, bound, context, this, args.concat(callArgs));
});
return bound;
}); // Partially apply a function by creating a version that has had some of its
// arguments pre-filled, without changing its dynamic `this` context. _ acts
// as a placeholder by default, allowing any combination of arguments to be
// pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
/*
局部应用一个函数填充在任意个数的 arguments,不改变其动态this值。和bind方法很相近。你可以传递_ 给arguments列表来指定一个不预先填充,但在调用时提供的参数。
*/
_.partial = restArgs(function(func, boundArgs) {
var placeholder = _.partial.placeholder;// 不预先填充
var bound = function() {
var position = 0, length = boundArgs.length;// position表示实参中的位置
var args = Array(length);
for (var i = 0; i < length; i++) {// 把之前的boundArgs和后传进来的实参拼起来
args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];// 如果参数为_,则取实参
}
while (position < arguments.length) args.push(arguments[position++]);
return executeBound(func, bound, this, this, args);// 执行func
};
return bound;
}); _.partial.placeholder = _; // Bind a number of an object's methods to that object. Remaining arguments
// are the method names to be bound. Useful for ensuring that all callbacks
// defined on an object belong to it.
/*
把methodNames参数指定的一些方法绑定到object上,这些方法就会在对象的上下文环境中执行。绑定函数用作事件处理函数时非常便利,否则函数被调用时this一点用也没有。methodNames参数是必须的。
*/
_.bindAll = restArgs(function(obj, keys) {
keys = flatten(keys, false, false);// 打开嵌套数组,返回新数组
var index = keys.length;
if (index < 1) throw new Error('bindAll must be passed function names');
while (index--) {
var key = keys[index];
obj[key] = _.bind(obj[key], obj);// 绑定obj[key]到obj中
}
}); // Memoize an expensive function by storing its results.
/*
Memoizes方法可以缓存某函数的计算结果。对于耗时较长的计算是很有帮助的。如果传递了 hasher 参数,就用 hasher 的返回值作为key存储函数的计算结果。hashFunction 默认使用function的第一个参数作为key。memoized值的缓存可作为返回函数的cache属性。
注意此函数的用法,应当赋给一个函数,然后函数再去执行
*/
_.memoize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = '' + (hasher ? hasher.apply(this, arguments) : key);// 计算cache中的存储key
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
return cache[address];
};
memoize.cache = {};
return memoize;
}; // Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
/*
过wait时间后异步执行
*/
_.delay = restArgs(function(func, wait, args) {
return setTimeout(function() {
return func.apply(null, args);
}, wait);
}); // Defers a function, scheduling it to run after the current call stack has
// cleared.
/*
延迟调用func,知道调用栈为空
*/
_.defer = _.partial(_.delay, _, 1);// wait为1ms // Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
/*
创建并返回一个像节流阀一样的函数,当重复调用函数的时候,至少每隔 wait毫秒调用一次该函数。对于想控制一些触发频率较高的事件有帮助。
函数节流原理:
函数节流的原理挺简单的,估计大家都想到了,那就是定时器。当我触发一个时间时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行
*/
_.throttle = function(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
options = options || {}; var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
}; var throttled = function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);// 剩余时间
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {// 如果现在距离上一次执行已经超过了wait,则直接执行
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);// 过remaining后再执行
}
return result;
}; throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
}; return throttled;
}; // Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
/*
返回 function 函数的防反跳版本, 将延迟函数的执行(真正的执行)在函数最后一次调用时刻的 wait 毫秒之后. 对于必须在一些输入(多是一些用户操作)停止到达之后执行的行为有帮助。 例如: 渲染一个Markdown格式的评论预览, 当窗口停止改变大小之后重新计算布局, 等等.
与_.throttle函数区别在于一个是在一定频率内只能执行一次(每个频率段都可以执行);_.debounce是在一定频率的操作后,只执行最后一次(只执行一次)
*/
_.debounce = function(func, wait, immediate) {
var timeout, result; var later = function(context, args) {
timeout = null;
if (args) result = func.apply(context, args);// 执行函数,知道最后一次调用时刻的 wait 毫秒之后
}; var debounced = restArgs(function(args) {
if (timeout) clearTimeout(timeout);// 清除之前wait时间以内的定时器
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(later, wait);
if (callNow) result = func.apply(this, args);
} else {
timeout = _.delay(later, wait, this, args);// 延迟wait执行
} return result;
}); debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
}; return debounced;
}; // Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
/*
使func作为参数传给wrapper,这样一来,wrapper可以控制func的执行
*/
_.wrap = function(func, wrapper) {
return _.partial(wrapper, func);
}; // Returns a negated version of the passed-in predicate.
/*
返回一个新的predicate函数的否定版本
*/
_.negate = function(predicate) {
return function() {
return !predicate.apply(this, arguments);
};
}; // Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
/*
返回函数集 functions 组合后的复合函数, 也就是一个函数执行完之后把返回的结果再作为参数赋给下一个函数来执行. 以此类推. 在数学里, 把函数 f(), g(), 和 h() 组合起来可以得到复合函数 f(g(h()))。
*/
_.compose = function() {
var args = arguments;
var start = args.length - 1;
return function() {
var i = start;
var result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result);//一个小迭代
return result;
};
}; // Returns a function that will only be executed on and after the Nth call.
/*
创建一个函数, 只有在运行了 count 次之后才有效果. 在处理同组异步请求返回结果时, 如果你要确保同组里所有异步请求完成之后才 执行这个函数, 这将非常有用
*/
_.after = function(times, func) {
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
}; // Returns a function that will only be executed up to (but not including) the Nth call.
/*
创建一个函数,调用不超过count 次。 当count已经达到时,最后一个函数调用的结果将被记住并返回
闭包!!!!!!
*/
_.before = function(times, func) {
var memo;
return function() {
if (--times > 0) {
memo = func.apply(this, arguments);
}
if (times <= 1) func = null;
return memo;
};
}; // Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization.
/*
创建一个只能调用一次的函数。
*/
_.once = _.partial(_.before, 2); _.restArgs = restArgs;

underscore.js源码解析【函数】的更多相关文章

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

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

  2. underscore.js源码解析(四)

    没看过前几篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二) underscore.js源码解析(三) underscore.js源码GitHub地 ...

  3. underscore.js源码解析(三)

    最近工作比较忙,做不到每周两篇了,周末赶着写吧,上篇我针对一些方法进行了分析,今天继续. 没看过前两篇的可以猛戳这里: underscore.js源码解析(一) underscore.js源码解析(二 ...

  4. underscore.js源码解析(二)

    前几天我对underscore.js的整体结构做了分析,今天我将针对underscore封装的方法进行具体的分析,代码的一些解释都写在了注释里,那么废话不多说进入今天的正文. 没看过上一篇的可以猛戳这 ...

  5. underscore.js源码解析(一)

    一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读 ...

  6. underscore.js源码解析【'_'对象定义及内部函数】

    (function() { // Baseline setup // -------------- // Establish the root object, `window` (`self`) in ...

  7. underscore.js源码解析【对象】

    // Object Functions // ---------------- // Keys in IE < 9 that won't be iterated by `for key in . ...

  8. underscore.js源码解析【数组】

    // Array Functions // --------------- // Get the first element of an array. Passing **n** will retur ...

  9. underscore.js源码解析【集合】

    // Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `f ...

随机推荐

  1. python 数据库操作类

    #安装PyMySQL:pip3 install PyMySQL   #!/usr/bin/python3   #coding=utf-8   #数据库操作类     from  datetime  i ...

  2. Hadoop学习之路(二十三)MapReduce中的shuffle详解

    概述 1.MapReduce 中,mapper 阶段处理的数据如何传递给 reducer 阶段,是 MapReduce 框架中 最关键的一个流程,这个流程就叫 Shuffle 2.Shuffle: 数 ...

  3. PDF 转 PNG JPG 操作

    # gs   gs -dSAFER -dBATCH -dNOPAUSE -r300 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sDEVICE=pnggray - ...

  4. python发送邮箱

    一.Python发送邮件 import smtplib from email.mime.text import MIMEText def send(email_to,title,content): m ...

  5. MYSQL性能查看(多指标)

    网上有很多的文章教怎么配置MySQL服务器,但考虑到服务器硬件配置的不同,具体应用的差别,那些文章的做法只能作为初步设置参考,我们需要根据自己的情况进行配置优化,好的做法是MySQL服务器稳定运行了一 ...

  6. Memcache cpu占用过高

    分析应该是memcache的内存大小还是默认配置,已经满足不了当前的大数据量的需要了,大量的新缓存需要进入,同时大量的旧缓存又需要被淘汰出来,一进一出导致CPU占用过多.进入注册表,找到:HKEY_L ...

  7. 第35章:MongoDB-集群--Master Slave(主从复制)

    ①主从复制 最基本的设置方式就是建立一个主节点和一个或多个从节点,每个从节点要知道主节点的地址.采用双机备份后主节点挂掉了后从节点可以接替主机继续服务,所以这种模式比单节点的高可用性要好很多. ②注意 ...

  8. UVaLive 4064 Magnetic Train Tracks (极角排序)

    题意:给定 n 个不三点共线的点,然后问你能组成多少锐角或者直角三角形. 析:可以反过来求,求有多少个钝角三角形,然后再用总的减去,直接求肯定会超时,但是可以枚举每个点,以该点为钝角的那个顶点,然后再 ...

  9. uniGUI动态建立Form及释放

    uniGUI动态建立Form及释放 (2015-10-01 14:51:12) 转载▼   分类: uniGUI 用uniGUI开发的项目中,难免要遇到动态建立一个Form,再释放掉,与传统Delph ...

  10. [BOT]自定义ViewPagerStripIndicator

    效果图 app中下面这样的控件很常见,像默认的TabHost表现上不够灵活,下面就简单写一个可以结合ViewPager切换内容显示,提供底部"滑动条"指示所显示页签的效果. 这里控 ...