2

为什么 jquery 代码(https://github.com/jquery/jquery/blob/master/src/callbacks.js)不使用原型作为方法?

我问这个是因为专家建议出于性能原因使用原​​型作为方法(因为函数只创建一次)。

来自 jquery 代码的代码片段,

self = {
            // Add a callback or a collection of callbacks to the list
            add: function() {
                if ( list ) {
                    // First, we save the current length
                    var start = list.length;
                    (function add( args ) {
                        jQuery.each( args, function( _, arg ) {
                            var type = jQuery.type( arg );
                            if ( type === "function" ) {
                                if ( !options.unique || !self.has( arg ) ) {
                                    list.push( arg );
                                }
                            } else if ( arg && arg.length && type !== "string" ) {
                                // Inspect recursively
                                add( arg );
                            }
                        });
                    })( arguments );
                    // Do we need to add the callbacks to the
                    // current firing batch?
                    if ( firing ) {
                        firingLength = list.length;
                    // With memory, if we're not firing then
                    // we should call right away
                    } else if ( memory ) {
                        firingStart = start;
                        fire( memory );
                    }
                }
                return this;
            },
            // Remove a callback from the list
            remove: function() {
                if ( list ) {
                    jQuery.each( arguments, function( _, arg ) {
                        var index;
                        while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                            list.splice( index, 1 );
                            // Handle firing indexes
                            if ( firing ) {
                                if ( index <= firingLength ) {
                                    firingLength--;
                                }
                                if ( index <= firingIndex ) {
                                    firingIndex--;
                                }
                            }
                        }
                    });
                }
                return this;
            },

我的问题是为什么所有方法都不是成为自我对象原型的单独对象的一部分?

4

2 回答 2

3

在此处使用这些特定函数允许在闭包中嵌入特定变量(例如list),同时保持它们的私有性。

以标准方式使用基于原型的对象会使这些属性公开。

选择时的经验法则可能是变量连贯性的必要性。当直接的变量更改可能使对象处于无效状态时,它可能看起来更具有保护性。例如,在这里,减少列表长度可能会使索引无效。

于 2013-01-11T14:24:49.810 回答
1

使用原型时,您只能访问对象的特权/​​公共成员。

正如我从代码中看到的,jQuery 没有将任何选项设置为回调对象的公共/特权成员,它们使用闭包来访问回调实例中的选项。如果他们初始化原型中的方法,他们将无法访问选项对象。

这是一个替代示例:

使用原型

function Callback(opt) {
    var options = opt;
}

Callback.prototype.execute = function () {
   console.log(typeof options);   //undefined
}

不使用原型

function Callback(opt) {
    var options = opt;
    this.execute = function () {
       console.log(typeof options);   //object
    }
}

我不能确定 jQuery 的考虑因素,但这里有几个假设:

  1. 在我看来,他们不想提供对回调对象内部使用的所有内容的公共访问。

  2. 使用新的。我还没有看到 jQuery 要求客户端使用newAPI 提供的初始化对象。

可以通过以下方式避免新的:

function Callbacks() {
    if (this === window) {
        return new Callbacks();
    }
}

Callbacks.prototype.method = function () {
    //implementation
}

var c = Callbacks(); 

但是很少有性能开销:

  • 这是由于递归调用的开销return new Callbacks()
  • 另一个是因为使用new. 在jsperf中,您可以看到通常对象字面量比new.
  • 而最后一个来自原型链的遍历:

    如果我使用:c.method();首先 JS 解释器将查看cfor invoking的属性method。当然它不会在那里找到它,所以它也必须在c的原型中查找。

于 2013-01-11T14:37:15.063 回答