zoukankan      html  css  js  c++  java
  • QWrap简介之:FunctionH 针对function的Helper

    正如《序》里所说,很多同学是由于对函数变换(泛函)感兴趣,从而来了解QWrap的,例如,从月影的博客三言两语说清QWrap核心模式精髓而来的。
    FunctionH的代码,也就那么几十行。不过,如果不理解思路,可能会因为“函数变换”的概念有点难于理解,而放弃对QWrap的围观。
    本文粗略的介绍一下FunctionH的思路。
    FuncitonH,就是什对function的Helper。
    javascript中,直观的感觉,Function有好几种,如:静态函数(Funciton)、类(Class)、方法(method),它们都是Function,他们最大的区别,可能就是this所指。
    而this是“一个函数,在被调用时所属的对象”,即:它就像是arguments一样,是一个运行属性,也即:这种分类方式是按函数的预期使用场合来分的。
    目前,与函数相关的,QWrap有两个Helper:FunctionH与ClassH,似乎还缺一个MethodH。----是的,的确还缺一个,不过因为还没有考虑成熟,所以暂缺。
    ClassH则是针对Class类型的Function的Helper。
    FunctionH则是针对静态函数类型的Helper。---(部分方法也因为有标准可循,所以也可以针对method,例如:bind)

    对于还没了解闭包的同学,请忽略以下内容。
    对于想看代码的同学,请先看功能说明,想想自己会怎么实现,再看代码是怎么实现的。如果直接看代码,可能会有点头痛,因为“自己实现某个功能”通常比“看别人是怎么实现某个功能”要简单得多。

    针对function的函数可能会有很多,包括函数变换与应用。
    可以先看一下prototype框架里与此相关的一段:
    View Code
    Object.extend(Function.prototype, (function() {
    var slice = Array.prototype.slice;

    function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
    }

    function merge(array, args) {
    array
    = slice.call(array, 0);
    return update(array, args);
    }

    function argumentNames() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
    .replace(
    /\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
    .replace(
    /\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
    }

    function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
    var __method = this, args = slice.call(arguments, 1);
    return function() {
    var a = merge(args, arguments);
    return __method.apply(context, a);
    }
    }

    function bindAsEventListener(context) {
    var __method = this, args = slice.call(arguments, 1);
    return function(event) {
    var a = update([event || window.event], args);
    return __method.apply(context, a);
    }
    }

    function curry() {
    if (!arguments.length) return this;
    var __method = this, args = slice.call(arguments, 0);
    return function() {
    var a = merge(args, arguments);
    return __method.apply(this, a);
    }
    }

    function delay(timeout) {
    var __method = this, args = slice.call(arguments, 1);
    timeout
    = timeout * 1000;
    return window.setTimeout(function() {
    return __method.apply(__method, args);
    }, timeout);
    }

    function defer() {
    var args = update([0.01], arguments);
    return this.delay.apply(this, args);
    }

    function wrap(wrapper) {
    var __method = this;
    return function() {
    var a = update([__method.bind(this)], arguments);
    return wrapper.apply(this, a);
    }
    }

    function methodize() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
    var a = update([this], arguments);
    return __method.apply(null, a);
    };
    }

    return {
    argumentNames: argumentNames,
    bind: bind,
    bindAsEventListener: bindAsEventListener,
    curry: curry,
    delay: delay,
    defer: defer,
    wrap: wrap,
    methodize: methodize
    }
    })());

    可能是历史原因,prototype的这段看起来有点乱,大略作一个粗评:
        argumentNames,//获取argumentNames,如函数是经转换过,或是代码被压缩过,都会导致这个取出来的不符要求。
        bind,//固化变换:可能是历史原因,没有按标准实现
        bindAsEventListener,//
        curry,//科里化变换:如函数是经转换过,都会导致curry化的不确定性
        delay,//延时执行
        defer,//延时执行
        wrap,//让我有点迷糊的变换:将本函数当参数传给wraper
        methodize//方法化变换:将静态函数变成对象方法

    而QW.FunctionH,代码如下:
    View Code
    /**
    * @class FunctionH 核心对象Function的扩展
    * @singleton
    * @namespace QW
    * @helper
    */
    (
    function() {

    var FunctionH = {
    /**
    * 函数包装器 methodize,对函数进行methodize化,使其的第一个参数为this,或this[attr]。
    * @method methodize
    * @static
    * @param {function} func要方法化的函数
    * @param {string} attr (Optional) 属性
    * @return {function} 已方法化的函数
    */
    methodize:
    function(func, attr) {
    if (attr) {
    return function() {
    return func.apply(null, [this[attr]].concat([].slice.call(arguments)));
    };
    }
    return function() {
    return func.apply(null, [this].concat([].slice.call(arguments)));
    };
    },
    /** 对函数进行集化,使其第一个参数可以是数组
    * @method mul
    * @static
    * @param {function} func
    * @param {bite} opt 操作配置项,缺省表示默认,
    1 表示getFirst将只操作第一个元素,
    2 表示joinLists,如果第一个参数是数组,将操作的结果扁平化返回
    * @return {Object} 已集化的函数
    */
    mul:
    function(func, opt) {
    var getFirst = opt == 1,
    joinLists
    = opt == 2;

    if (getFirst) {
    return function() {
    var list = arguments[0];
    if (!(list instanceof Array)) {
    return func.apply(this, arguments);
    }
    if (list.length) {
    var args = [].slice.call(arguments, 0);
    args[
    0] = list[0];
    return func.apply(this, args);
    }
    };
    }

    return function() {
    var list = arguments[0];
    if (list instanceof Array) {
    var moreArgs = [].slice.call(arguments, 0),
    ret
    = [],
    i
    = 0,
    len
    = list.length,
    r;
    for (; i < len; i++) {
    moreArgs[
    0] = list[i];
    r
    = func.apply(this, moreArgs);
    if (joinLists) {
    if (r) {
    ret
    = ret.concat(r);
    }
    }
    else {
    ret.push(r);
    }
    }
    return ret;
    }
    else {
    return func.apply(this, arguments);
    }
    };
    },
    /**
    * 函数包装变换
    * @method rwrap
    * @static
    * @param {func}
    * @return {Function}
    */
    rwrap:
    function(func, wrapper, idx) {
    idx
    |= 0;
    return function() {
    var ret = func.apply(this, arguments);
    if (idx >= 0) {
    ret
    = arguments[idx];
    }
    return wrapper ? new wrapper(ret) : ret;
    };
    },
    /**
    * 绑定
    * @method bind
    * @via https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
    * @compatibile ECMA-262, 5th (JavaScript 1.8.5)
    * @static
    * @param {func} 要绑定的函数
    * @obj {object} this_obj
    * @param {any} arg1 (Optional) 预先确定的参数
    * @param {any} arg2 (Optional) 预先确定的参数
    * @return {Function}
    */
    bind:
    function(func, obj) {
    var slice = [].slice,
    args
    = slice.call(arguments, 2),
    nop
    = function() {},
    bound
    = function() {
    return func.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
    };

    nop.prototype
    = func.prototype;

    bound.prototype
    = new nop();

    return bound;
    },
    /**
    * 懒惰执行某函数:一直到不得不执行的时候才执行。
    * @method lazyApply
    * @static
    * @param {Function} fun 调用函数
    * @param {Object} thisObj 相当于apply方法的thisObj参数
    * @param {Array} argArray 相当于apply方法的argArray参数
    * @param {int} ims interval毫秒数,即window.setInterval的第二个参数.
    * @param {Function} checker 定期运行的判断函数。<br/>
    对于不同的返回值,得到不同的结果:<br/>
    返回true或1,表示需要立即执行<br/>
    返回-1,表示成功偷懒,不用再执行<br/>
    返回其它值,表示暂时不执行<br/>
    * @return {int} 返回interval的timerId
    */
    lazyApply:
    function(fun, thisObj, argArray, ims, checker) {
    checker
    = checker || function() {return true; };
    var timer = function() {
    var verdict = checker();
    if (verdict == 1) {
    fun.apply(thisObj, argArray
    || []);
    }
    if (verdict == 1 || verdict == -1) {
    clearInterval(timerId);
    }
    },
    timerId
    = setInterval(timer, ims);
    return timerId;
    }
    };


    QW.FunctionH
    = FunctionH;

    }());



    粗略分析:
    methodize: function(func, attr) :
         方法化 对函数进行methodize化,使其的第一个参数为this,或this[attr]。

    mul: function(func, opt)
        对函数进行集化,使其第一个参数可以是数组。如果第一个参数是数组,处理可能有:
          0 getAll 针对每一个都运行,并将结果组成的数组返回
          1 getFirst 只运行第一个运行,并返回结果
          2 joinLists 每一个都运行,并将返回不为空的结果concat后返回。
    rwrap: function(func, wrapper, idx)
        包装变换,运行函数,并将指定内容(结果或针对的对象)包装起来返回
    bind: function(func, obj)
        绑定(固化)this或arguments,参见(ECMA-262, 5th (JavaScript 1.8.5))https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
    lazyApply: function(fun, thisObj, argArray, ims, checker)
        懒惰执行某函数:一直到不得不执行的时候才执行。

    与prototype框架的相关方法对比,可以看到:
    1。QW.FunctionH的helper特征明显,与prototype直接渲染原型不同。
    2。methodize功能相似。不过,QW.FunctionH.methodize加了一个参数“attr”,这会在以后的Wrap模型中起到很重要的作用。
    3。bind功能相似,不过qw遵循某标准,这不能怪prototype,因为prototype走在了标准前面。
    4。QW.FunctionH.rwrap与prototype框架的wrap是不一样的概念。
    5。QW.FunctionH.lazyApply更语义化,并且加了一套checker的逻辑。
    6。QW多了一个mul,这个会在NodeH的变换中起到很重要的作用。

    其实函数变换远不只bind、methodize、mul、rwrap这几个。
    好几个同学看到methodize时就问:“那是不是也应该有个相反的unmethodize,或functionlize”。----是的,理论上可以有,并且也曾出现在qwrap的代码里,后来因为没人用,我们把它拿掉了。
    有时候,需要在“理论完整”与“有用精简”之间权衡取舍。
    另外,QWrap还在js/core与js/dom的目录下加了一个dev的目录http://dev.qwrap.com/resource/js/core/dev/,那里面是一些备用的功能,可以当作参考。
    例如,FunctionH.overload = function(func, func_maps, dispatcher) 可以按参数来进行模式匹配而产生重载的效果。



    

  • 相关阅读:
    Codeforces 1196E. Connected Component on a Chessboard
    Codeforces 1196C. Robot Breakout
    Codeforces 1194E. Count The Rectangles
    Codeforces 1194D. 1-2-K Game
    Codeforces 1194C. From S To T
    Codeforces 1194B. Yet Another Crosses Problem
    Codeforces 1194A. Remove a Progression
    Codeforces 1201E2. Knightmare (hard)
    关于cookie
    关于js的addEventListener 和一些常用事件
  • 原文地址:https://www.cnblogs.com/jkisjk/p/qwrap_helper_FunctionH.html
Copyright © 2011-2022 走看看