3

私は、JavaScript クラスまたはオブジェクトをログに記録できるようにする jQuery プラグインに取り組んでいます。アイデアは、オブジェクト内の各関数、または関数のプロトタイプをオーバーライドすることです。

(function($)
{
    "use strict";

    $.log = function(object, logger)
    {
        if (!$.isFunction(logger))
        {
            logger = function(name, args)
            {
                console.log(name + "(" + $.makeArray(args).join(", ") + ")");
            };
        }

        var s = $.isFunction(object) ? object.prototype : object;

        for (name in s)
        {
            var fn = s[name];

            if ($.isFunction(fn))
            {
                s[name] = (function(name, fn)
                {
                    return function()
                    {
                        logger(name, arguments);
                        return fn.apply(this, arguments);
                    };
                })(name, fn);
            }
        }
    };
})(jQuery);

これは、個々のプラグインをログに記録するために機能するようです。たとえば$.log($.ui.tabs);、タブ プロトタイプ内のすべての関数呼び出しをログに記録します。

しかし、すべての jQuery をログに記録しようとすると$.log($);、参照エラーが発生します。なぜこのエラーが発生するのかわかりません。どちらか、または引数が渡​​されることに関係があるという印象を受けていますthisが、よくわかりません。

編集:オーバーライドされた関数が常に返されるため、もう少し考えてみます。

問題をデモするためにフィドルを作成しました:http://jsfiddle.net/Sj6xN/4/

編集:

これは私が最終的に完成したコードで、これまでのところ完全に機能しています:

(function($)
{
    "use strict";

    var Logger = function(options)
    {
        this.options = $.extend(this.defaults, options);
    };

    Logger.prototype = {
        defaults:
        {
            inherited: false,
            deep: false,
            logWriter: function(name, args)
            {
                console.log("CALL: " + name + "(" + $.makeArray(args).join(", ") + ")");
            }
        },
        augment: function(object)
        {
            var self = this;

            // Make sure this object is not already augmented
            if (object.__isAugmented__)
            {
                return;
            }

            // Set 'isAugmented' to prevent recursion
            object.__isAugmented__ = true;

            // Loop through the object
            for (var name in object)
            {
                var originalFunction = object[name];

                // If it's a function and the function is not inherited or 'inherited' is enabled augment it
                if ($.isFunction(originalFunction) && (object.hasOwnProperty(name) || self.options.inherited))
                {
                    // Wrap in self executing function so references to 'name' and 'orginalFunction' are maintained
                    object[name] = (function(name, originalFunction)
                    {
                        // If the function has a prototype and 'deep' is enabled augment that as well
                        if (self.options.deep && originalFunction.prototype)
                        {
                            self.augment(originalFunction.prototype);
                        }

                        var augmentedFunction = function()
                        {
                            // Execute log writer
                            self.options.logWriter(name, arguments);

                            // Call original function
                            return originalFunction.apply(this, arguments);
                        };

                        // Inherit prototype of original function
                        augmentedFunction.prototype = originalFunction.prototype;

                        // Return the augmented function
                        return augmentedFunction;
                    })(name, originalFunction);
                }
                // If it's a plain object and 'deep' is enabled augment that as well
                else if (self.options.deep && $.isPlainObject(originalFunction))
                {
                    self.augment(originalFunction);
                }
            }
        }
    };

    $.log = function(object, options)
    {
        var logger = new Logger(options);

        // If the object is a function use it's prototype, otherwise assume a plain object
        object = $.isFunction(object) ? object.prototype : object;

        // Augment
        logger.augment(object);
    };
})(jQuery);

次のように使用できます。

$.log(<object or function> [,
{
    inherited: <bool>,
    deep: <bool>,
    logWriter: <function(name, args)>
}]);
4

1 に答える 1

2

エラーをよく見てください。

Uncaught ReferenceError: name is not defined

名前を定義しておらず、厳密モードであるため、定義せずに変数を使用することはできません(通常、定義するとグローバル変数になりますが、厳密モードでは使用できません)。したがって、var name前に書くと、このエラーは発生しなくなります。

tabメソッドがないために別のエラーがありますが。もう1つのエラーはtabs、オブジェクトのメソッドではないことを示しています。これは、関数をラップするときにプロトタイプを継承しなかったため、関数をnewで呼び出すと、プロトタイプ関数がないためです(tabsそのうちの1つです) 。

修正されたコードは次のとおりです:http://jsfiddle.net/Sj6xN/8/

于 2012-07-28T02:34:04.270 に答える