美文网首页
Underscore源码(4)

Underscore源码(4)

作者: ____雨歇微凉 | 来源:发表于2016-12-09 23:02 被阅读13次
    // Function (ahem) Functions
    // ------------------
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    // 确定是否执行一个函数作为一个构造函数或一个正常的函数与所提供的参数
    // Determines whether to execute a function as a constructor or a normal function with the provided arguments
    // 主要是用来创建一个实例,把sourceFunc 绑定到boundFunc上,并且new出来
    var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
        // instanceof 用于判断一个变量是否某个对象的实例 这里取了否定,所以返回原函数调用所有参数
        if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
        // self 是继承 sorceFunc的新函数,是new出来的一个
        var self = baseCreate(sourceFunc.prototype);
        // 在新函数里调用所有参数
        var result = sourceFunc.apply(self, args);
        // 如果是Obj,则返回自身,否则返回函数
        if (_.isObject(result)) return result;
        return self;
    };
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * bind
     * 绑定函数 function 到对象 object 上
     * source:根源,本源
     * bound:限制,用带子绑住的
     */
    // Create a function bound to a given object (assigning `this`, and arguments,
    // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
    // available.
    _.bind = function(func, context) {
        // 如果原生存在bind,则用原生调用
        if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
        // 如果不是一个函数,则报错
        if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
        // 提取参数
        var args = slice.call(arguments, 2);
        // 返回绑定过的函数
        var bound = function() {
            return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
        };
        return bound;
    };
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * partial
     * 局部应用一个函数填充在任意个数的 arguments,不改变其动态this值。和bind方法很相近。
     * 你可以传递_ 给arguments列表来指定一个不预先填充,但在调用时提供的参数。
     */
    // 把methodNames参数指定的一些方法绑定到object上
    // 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, allowing any combination of arguments to be pre-filled.
    _.partial = function(func) {
        var boundArgs = slice.call(arguments, 1);
        var bound = function() {
            var position = 0, length = boundArgs.length;
            var args = Array(length);
            for (var i = 0; i < length; i++) {
                args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
            }
            // 有几个_就执行几次
            while (position < arguments.length) args.push(arguments[position++]);
    
            // 把参数传递给func,然后缺的参数仍旧是参数
            return executeBound(func, bound, this, this, args);
        };
        return bound;
    };
    
    // 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
     * 循环调用_.bind()
     */
    _.bindAll = function(obj) {
        var i, length = arguments.length, key;
        if (length <= 1) throw new Error('bindAll must be passed function names');
        for (i = 1; i < length; i++) {
            key = arguments[i];
            obj[key] = _.bind(obj[key], obj);
        }
        return obj;
    };
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * memoize
     * Memoizes方法可以缓存某函数的计算结果。
     */
    
    // 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);
            // 如果结果中已经存在这个key,则返回这个key的值,否则计算
            if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
            return cache[address];
        };
        memoize.cache = {};
        return memoize;
    };
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * delay
     * 类似setTimeout,等待wait毫秒后调用function。
     */
    
        // Delays a function for the given number of milliseconds, and then calls
    // it with the arguments supplied.
    _.delay = function(func, wait) {
        // 查看是否有参数
        var args = slice.call(arguments, 2);
        // 返回定时器
        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);
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * throttle
     * 创建并返回一个像节流阀一样的函数,当重复调用函数的时候,至少每隔 wait毫秒调用一次该函数。
     */
    
    // 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 context, args, result;
        var timeout = null;
        var previous = 0;// 以前的
        if (!options) options = {};
        var later = function() {
            // _.now() 用于获取一个当前时间的整数时间戳
            previous = options.leading === false ? 0 : _.now();
            // 关闭定时器,然后执行函数
            timeout = null;
            result = func.apply(context, args);
            // 如果定时器关闭,则参数清空
            if (!timeout) context = args = null;
        };
        return function() {
            var now = _.now();
            // 如果没有传递leading,并且是第一次, 则计时
            if (!previous && options.leading === false) previous = now;
    
            // 每次调用都会计算一下时间戳,如果当前的时间减去旧的时间大于等待时间,就执行,否则就关闭计时器
            // 比如第一次,,now 12:00, pre : 0 -> (remaining > wait) 这就是第一次
            // remaining <= 0 指,等待的时间已经结束了。
            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;
                // 禁用最后一次,如果最后一次为false,就不会到这里
                // !timeout 指函数没有执行
                // options.trailing !== false 不是最后一次
            } else if (!timeout && options.trailing !== false) {
                timeout = setTimeout(later, remaining);
            }
            return result;
        };
    };
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * debounce
     * 将延迟函数的执行(真正的执行)在函数最后一次调用时刻的 wait 毫秒之后.
     */
    // 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.
    _.debounce = function(func, wait, immediate) {
        var timeout, args, context, timestamp, result;
    
        // 每一次都获取一个时间戳,然后计算后一次和前一次的差值,如果小于等待时间就关闭定时器,如果大于,就执行函数。
        var later = function() {
            var last = _.now() - timestamp;
    
            if (last < wait && last >= 0) {
                timeout = setTimeout(later, wait - last);
            } else {
                timeout = null;
                if (!immediate) {
                    result = func.apply(context, args);
                    if (!timeout) context = args = null;
                }
            }
        };
    
        return function() {
            context = this;
            args = arguments;
            timestamp = _.now();
            var callNow = immediate && !timeout;
            if (!timeout) timeout = setTimeout(later, wait);
            if (callNow) {
                result = func.apply(context, args);
                context = args = null;
            }
    
            return result;
        };
    };
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * wrap
     * 将func 当做前一个wrapper的参数
     */
    // 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.
    _.wrap = function(func, wrapper) {
        return _.partial(wrapper, func);
    };
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * negate
     * 返回一个新的predicate函数的否定版本。
     */
    // Returns a negated version of the passed-in predicate.
    _.negate = function(predicate) {
        return function() {
            // 调用条件yuju 返回与它相反的值
            return !predicate.apply(this, arguments);
        };
    };
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * compose
     * 返回函数集 functions 组合后的复合函数, 也就是一个函数执行完之后把返回的结果再作为参数赋给下一个函数来执行.
     */
    
    // Returns a function that is the composition of a list of functions, each
    // consuming the return value of the function that follows.
    _.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;
        };
    };
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * after
     * 创建一个函数, 只有在运行了 count 次之后才有效果.
     */
    
    // Returns a function that will only be executed on and after the Nth call.
    _.after = function(times, func) {
        return function() {
            // 在函数调用了time次之后,调用内部的方法
            if (--times < 1) {
                return func.apply(this, arguments);
            }
        };
    };
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * before
     * 创建一个函数,调用不超过count 次。 当count已经达到时,最后一个函数调用的结果将被记住并返回。
     */
    
    // Returns a function that will only be executed up to (but not including) the Nth call.
    _.before = function(times, func) {
        var memo;
        return function() {
            // 在times大于0的时候一直调用,每一次都改变memo的值,最后一次返回结果
            if (--times > 0) {
                memo = func.apply(this, arguments);
            }
            if (times <= 1) func = null;
            return memo;
        };
    };
    
    /*——————————————————————————————————————————————————————————————————————————*/
    
    /**
     * once
     * 仅调用一次
     */
    
    // 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);
    

    相关文章

      网友评论

          本文标题:Underscore源码(4)

          本文链接:https://www.haomeiwen.com/subject/xoiupttx.html