如何访问拥有Function.prototype扩展的函数?

时间:2012-11-21 18:30:17

标签: javascript prototype

我正在尝试创建一个函数扩展来去抖动任何函数(如果函数快速连续多次调用,只执行一次,最佳返回缓存值)。

我打算在UI框架中使用它,但我希望它是可移植的。我到目前为止的代码如下:

Function.prototype.debounce = function()
{
    var originalFunction = this; //this should be 'clickButton' in the example implementation
    var originalArguments = arguments;

    function debouncedFunction()
    {
        var originalContext = this;
        return originalFunction.apply(originalContext,originalArguments)
    }

    if(this.__DEBOUNCEDVALUE === undefined)
    {
        this.__DEBOUNCEDVALUE = debouncedFunction();
        if(this.__DEBOUNCEDVALUE === undefined)
            this.__DEBOUNCEDVALUE = null;
        setTimeout(function(){originalFunction.__DEBOUNCEDVALUE = undefined},1000);
    }

    return this;
}

接下来,我定义了一个通用函数“clickButton”,它看起来像这样:

function clickButton()
{
    document.getElementById('log').innerHTML += "<br/>Clicked "+arguments[1];
    return "some value";
}

当我致电clickButton.debounce(3,4)时,它有效。它每秒只记录一次文档,但每次调用它都会返回。

但是,当我通过监听器(buttons[i].addEventListener('click',clickButton.debounce))调用它时,originalFunction变量设置为按钮,而不是函数。不是什么大惊喜。如何在此示例中从去抖动中获得对clickButton的引用?

编辑: 我尝试过切换到使用defineProperty,这允许我在访问时保存上下文和功能。不幸的是,这并不适用于所有情况(将它放入Sencha Touch中的tap处理程序会导致在Window范围内调用函数)。这更接近,但仍然是不可接受的。

Object.defineProperty(Function.prototype,'debounce',{get: function()
    {
        var originalFunction = this;
        var execute = function()
        {
            if(originalFunction.__DEBOUNCEDVALUE === undefined)
            {
                originalFunction.__DEBOUNCEDVALUE = originalFunction.apply(this,arguments);
                if(originalFunction.__DEBOUNCEDVALUE === undefined)
                    originalFunction.__DEBOUNCEDVALUE = null;
                setTimeout(function()
                    {
                        originalFunction.__DEBOUNCEDVALUE = undefined;
                        console.log("Reset");
                    },5000);
            }
            else
                console.log("Return cached value");

            return originalFunction.__DEBOUNCEDVALUE;
        }
        return execute;

    }});

1 个答案:

答案 0 :(得分:2)

这只能通过将函数对象绑定到debounce的某种方法来完成。

一种方法是使用.bind

buttons[i].addEventListener('click',clickButton.debounce.bind(clickButton)),

另一种方法是传递一个关闭clickButton的匿名函数。

buttons[i].addEventListener('click',function(e) {
    return clickButton.debounce.apply(clickButton, arguments);

        // The following would suffice for this example:
    // return clickButton.debounce(e);
}),

但是除了这些技术之外,debounce在传递给addEventListener时对它所引用的对象没有记忆。