// 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. 100-days: sixteen

    Title: The world's most expensive cities 生活成本最高的城市 For the first time in its 30-year history, the Wo ...

  2. C/S和B/S架构

    1.C/S架构(Client/Server结构,熟知的客户机和服务器结构),它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统 ...

  3. Eclipse常用快捷键(用到想到随时更新)

    原始链接:https://jingyan.baidu.com/article/fedf073771323235ac8977f1.html Shift+Enter在当前行的下一行插入空行(这时鼠标可以在 ...

  4. 4412 uboot启动分析

    感谢sea1105, https://blog.csdn.net/sea1105/article/details/52142772 在学习过程中,由于tiny4412资料太过于少,因此参考210的视屏 ...

  5. django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call

    Error info: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, ...

  6. cmd输入appium-doctor,运行时提示'node'不是内部或外部的命令

    一.提示'node'不是内部或外部命令,先按照下面步骤操作: 1.设置APPIUM_HOME系统变量,值为当前appium安装目录,例如:D:\software_install\Appium 2.设置 ...

  7. Log4Net web.config配置

     1 .[assembly: log4net.Config.XmlConfigurator(ConfigFile = "web.config", Watch = true)]  写 ...

  8. python04 列表 元祖 字典

    1.list 有序,元素可以被修改 li=[1,2,2,"am","123"] 列表中的元素可以是数字,字符串,列表等等 支持切片,切片结果为列表  li[3] ...

  9. boost 编写finger服务

    本篇是模仿PYTHON TWISTED写一个FINGER示例. 从最简单的链接到通过接收字符串返回不同的内容 1 最简单的链接 #include <ctime> #include < ...

  10. Android app中存储文件的路径

    // 获得缓存文件路径,磁盘空间不足或清除缓存时数据会被删掉,一般存放一些临时文件 // /data/data/<application package>/cache目录 File cac ...