前言
这篇主要是功能函数。
// 功能函数 // ------------------ // 决定以构造函数还是以普通函数的形式调用 var executeBound = function (sourceFunc, boundFunc, context, callingContext, args) { // 如果 callingContext 是 boundFunc 的实例,则返回 sourceFunc 的执行结果(当普通函数调用) if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); // 如果前端的条件不满足,则是以构造函数的形式调用 // 创建一个原型(prototype)指向 sourceFunc.prototype 的对象,类似继承 var self = baseCreate(sourceFunc.prototype); // 保存 sourceFunc 函数(上下文绑定了 self) 的执行结果 var result = sourceFunc.apply(self, args); // 如果 result 是对象,则直接返回 result if (_.isObject(result)) return result; // 如果是以构造函数的形式调用,并且 sourceFunc 的执行结果不是对象,则返回 self 实例 return self; }; // 绑定上下文 _.bind = restArguments(function (func, context, args) { // 如果不是函数,抛出异常 if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); var bound = restArguments(function (callArgs) { // 如果经 _.bind() 方法绑定后的函数通过了 new 创建了一个实例,那么此时 // this 则为 bound 函数的实例,executeBound 方法内部就是通过这个来判断是否是 new 调用 return executeBound(func, bound, context, this, args.concat(callArgs)); }); // 返回 bound 函数 return bound; }); // 返回一个把函数跟参数绑定后的新函数 _.partial = restArguments(function (func, boundArgs) { var placeholder = _.partial.placeholder; var bound = function () { // 保存 _.partial 调用时传入的参数个数(不包含第一个参数) var position = 0, length = boundArgs.length; // 创建一个长度为 length 的数组 var args = Array(length); // 遍历预置的参数 for (var i = 0; i < length; i++) { // 如果 bondArgs === placeholder 则返回 arguments 中对应位置的参数 // 这里可以让你更灵活的调整参数位置 args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; } // 遍历调用新函数时传入的参数 arguments // 把预置参数和调用函数时传入的参数(剩余的参数)组成一个数组 args while (position < arguments.length) args.push(arguments[position++]); // 返回 executeBound // _.partial 这个方法没有绑定上下文的作用 return executeBound(func, bound, this, this, args); }; return bound; }); // 把 _ 挂载到 _.partial.placeholder 上 _.partial.placeholder = _; // 批量上下文绑定 _.bindAll = restArguments(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 = function (func, hasher) { var memoize = function (key) { // 缓存 cache var cache = memoize.cache; // 计算出 cache 中的 key 值(如果有传 hasher 则取 hasher 执行结果 否则取 key) 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; }; // 延迟执行函数跟(只是对 setTimeout 进行了封装) _.delay = restArguments(function (func, wait, args) { return setTimeout(function () { return func.apply(null, args); }, wait); }); // 下个事件循环再执行函数,底层还是利用了 setTimeout 实现 _.defer = _.partial(_.delay, _, 1); // 节流 _.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(); // 如果 previous 为 0,并且 options.leading 为 false if (!previous && options.leading === false) previous = now; // 算出剩余时间 var remaining = wait - (now - previous); context = this; args = arguments; // 如果 remaining 小于等于零,说明到了执行时间 // 或者 remaining 大于 wait,说明系统时间被修改了 if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } // 保存当前时间作为上一次时间 previous = now; // 执行函数 result = func.apply(context, args); // 如果 timeout 存在,重置 timeout,context,args 为 null if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { // 如果 timeout 不存在,并且 options.trailing 不为 false 时 timeout = setTimeout(later, remaining); } return result; }; // 取消节流执行函数 throttled.cancel = function () { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; }; // 防抖 _.debounce = function (func, wait, immediate) { var timeout, result; var later = function (context, args) { timeout = null; // 如果有传 args 说明是调用了 _.delay() if (args) result = func.apply(context, args); }; var debounced = restArguments(function (args) { // 清空定时器 if (timeout) clearTimeout(timeout); // 是否马上执行一次 if (immediate) { var callNow = !timeout; // wait 毫秒之后执行 timeout = setTimeout(later, wait); // 如果 timeout 为 null,说明为首次 if (callNow) result = func.apply(this, args); } else { // wait 毫秒之后执行 timeout = _.delay(later, wait, this, args); } return result; }); // 取消防抖执行函数 debounced.cancel = function () { clearTimeout(timeout); timeout = null; }; return debounced; }; // 把函数 func 作为 wrapper 函数的第一个参数 _.wrap = function (func, wrapper) { return _.partial(wrapper, func); }; // 返回一个 predicate 取反的函数. _.negate = function (predicate) { return function () { return !predicate.apply(this, arguments); }; }; // 返回复合函数,上一个函数结果作为下一个函数的参数(注意:从函数数组中的最后一个开始遍历) _.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; }; }; // 运行指定次数(times)后才执行 func _.after = function (times, func) { return function () { if (--times < 1) { return func.apply(this, arguments); } }; }; // 返回一个有限制调用次数(times - 1 次)的函数 _.before = function (times, func) { var memo; return function () { if (--times > 0) { memo = func.apply(this, arguments); } if (times <= 1) func = null; return memo; }; }; // 返回一个只会执行一次的函数 _.once = _.partial(_.before, 2); // 对外暴露 restArguments 方法 _.restArguments = restArguments;