underscore.js 755 -- 876
来源:互联网 发布:怎么才能在淘宝上卖东西 编辑:程序博客网 时间:2024/06/14 02:05
// 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); 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. _.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. _.partial = restArgs(function(func, boundArgs) { var placeholder = _.partial.placeholder; var bound = function() { var position = 0, length = boundArgs.length; var args = Array(length); for (var i = 0; i < length; i++) { args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; } while (position < arguments.length) args.push(arguments[position++]); return executeBound(func, bound, this, this, args); }; 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. _.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); } }); // Memoize an expensive function by storing its results. _.memoize = function(func, hasher) { var memoize = function(key) { var cache = memoize.cache; var address = '' + (hasher ? hasher.apply(this, arguments) : 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. _.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. _.defer = _.partial(_.delay, _, 1); // 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. _.throttle = function(func, wait, options) { var timeout, context, args, result; var previous = 0; if (!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) { 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); } return result; }; throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; };
_.executeBound
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); var self = baseCreate(sourceFunc.prototype); var result = sourceFunc.apply(self, args); if (_.isObject(result)) return result; return self; };
拆开分析
var executeBound = function (sourceFunc, boundFunc, context, callingContext, args) {} // 传入五个参数 //sourceFunc: 选定所属函数 // boundFunc // context // callingContext // args: 应当为一个数组
函数内部:
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); // 如果没有callingContext或者不属于boundFunc时,直接对应context var self = baseCreate(sourceFunc.prototype); //创造一个空对象,prototype = sourceFunc var result = sourceFunc.apply(self, args); //对应该空函数调用目标函数 if (_.isObject(result)) return result; // 如果是对象,返回result return self; // 返回空对象
_.bind
// Create a function bound to a given object (assigning `this`, and arguments, // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if // available. _.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)); //传入的this为全局,因此自动在executeBound中执行第一项 }); return bound; });
解析网址
_.partial
// 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. _.partial = restArgs(function(func, boundArgs) { var placeholder = _.partial.placeholder; // placeholder为underscore本身 var bound = function() { var position = 0, length = boundArgs.length; var args = Array(length); for (var i = 0; i < length; i++) { args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];// 如果是,则跳过,直接让后面输入的arguments优先调入 } while (position < arguments.length) args.push(arguments[position++]); // 将后面输入的arguments加入 return executeBound(func, bound, this, this, args); }; return bound; });
_.bindAll;
// 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. _.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); } });
对对象中的每个属性都用_.bind,flatten先铺平
_.memoize
// Memoize an expensive function by storing its results. _.memoize = function(func, hasher) { var memoize = function(key) { var cache = memoize.cache; var address = '' + (hasher ? hasher.apply(this, arguments) : key); if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); return cache[address]; }; memoize.cache = {}; return memoize; };
记录复杂函数的结果
_.memoize = function (fund, hasher) { var memorize = function (key) { var cache = memoize.cache; var address = '' + (hasher ? hasher.apply(this, arguments) : key); //是否有哈希算法,无则默认用key if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); // 结果保存 return cache[address]; memoize.cache = {}; }}
即以上操作返回一个能够缓存的函数,假如有递归,可以将每次的递归结果缓存到缓存函数一个名叫cache属性中,追踪实现。
_.delay
// Delays a function for the given number of milliseconds, and then calls // it with the arguments supplied. _.delay = restArgs(function(func, wait, args) { return setTimeout(function() { return func.apply(null, args); }, wait); // setTimeout延迟执行 });
_.defer
// Defers a function, scheduling it to run after the current call stack has // cleared. _.defer = _.partial(_.delay, _, 1); _.partial = restArgs(function(func, boundArgs) { var placeholder = _.partial.placeholder; var bound = function() { var position = 0, length = boundArgs.length; var args = Array(length); for (var i = 0; i < length; i++) { args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; } while (position < arguments.length) args.push(arguments[position++]); return executeBound(func, bound, this, this, args); }; return bound; });
类似于延迟为0的_.defer,为什么这样写就是为了规定仅输入一个函数即可.
_.throttle
// 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. _.throttle = function(func, wait, options) { var timeout, context, args, result; var previous = 0; if (!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) { 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); } return result; }; throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; };
我们在使用throttle的时候
function test() { console.log('point got!')}var moment = $.throttle(test, 5000)moment()moment()moment() No matching processes belonging to you were foundpoint got!(间隔一段时间)point got![Finished in 5.1s]
详情
这个throttle就是指你在一个时间段内如果不停调用该函数的话,如果正好过了那个间隔,你就可以正式调用函数的内容。
接下来我们看看究竟源码是怎么实现的
// unc, wait, options 为传参 var timeout, context, args, result; var previous = 0; if (!options) options = {};
正如所写的那样,有timeout,即时间间隔,args参数,result是结果,context作为this的绑定
先定一个previous为0,即之前的时间。
var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); //调用函数 if (!timeout) context = args = null; };
?这个函数干什么用的?
把timeout设定成0然后还调用一次函数??最后把result的返回值设定为调用函数???没有设定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) { 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); } return result; };
throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled;
我们看到最后return的是一个叫throated的函数,这个函数还含有一个cancel的方法,用来清除timeout和设定previous为0的
var now = _.now(); //获取当前时间 if (!previous && options.leading === false) previous = now; //如果不设定leading属性,我们的previous就为now var remaining = wait - (now - previous); // 不设定leading时很有意思,remaining就是waiting,即等待的总时间 context = this; args = arguments; //传入参数 if (remaining <= 0 || remaining > 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); //不设定leading的第一下我们设个timeout,并且用remaining来设定调用时间 } return result; // 返回结果
哦,现在我们知道了,从一开始,我们就设定一个叫later的函数,这个函数代表最后执行的一次定时,而之前的所有,我们都用previous跟now来表示,我们用取到的now - previous来判断是否在一个时间间隔内,若在,则不调用function,若在,则调用,最后一下如果不设定trailing,则是通过setimeout来实现最后一次调用。
没了
阅读全文
0 0
- underscore.js 755 -- 876
- Underscore.js
- underscore.js
- Underscore.js
- underscore.js
- underscore.js
- underscore.js学习
- [转]Underscore.js用法
- Underscore.js笔记
- Underscore.js-template模板
- underscore.js学习笔记
- underscore.js学习笔记
- Underscore.js 入门
- underscore.js学习笔记
- Underscore.js 1.8.3
- nodejs中的underscore.js
- Underscore.js 入门
- Underscore.js 入门
- 《Netty学习》(二)Hello World
- java多态
- 玲珑杯”ACM比赛 Round #18 C -- 图论你先敲完模板
- android_访问系统联系人
- 架构-LSTM理解总结(1)
- underscore.js 755 -- 876
- LNK2005 __CRT_RTC_INIT already defined in LIBCMTD.lib(_init_.obj)
- java中的Timer TimerTask ScheduledExecutorService
- 使用PySide实现生命游戏
- 1002. A+B for Polynomials (25)
- js与flash交互
- JS关于计时器函数传参
- jquery实时监控textarea文本框中的字符(中文汉字及标点、英文字母及标点、数字)长度
- QT学习源网址转载1---QT多线程参数传递(信号与槽)方法