JavaScript面向对象编程:日志记录的实现

6

我已经编写了以下代码,使用面向对象编程在单独的js文件logger.js中实现日志记录。

var console;

function Logger() {
    init();
}

var init = function() {
    if(!window.console){ 
        console = {
            log: function(message){},
            info: function(message){},
            warn: function(message){},
            error: function(message){}
        }; 
    } else {
        console = window.console;
    }
};

Logger.prototype.log = function(message) {
    console.log(message);    
}

Logger.prototype.logInfo = function(message) {
    console.info(message);
}

Logger.prototype.logWarn = function(message) {
    console.warn(message);
}

Logger.prototype.logError = function(message) {
    console.error(message);
}

我正在另一个js文件site.js中使用它:

var logger = new Logger(); //global variable

var getComponentById = function(id) {
    var component = null;

    if(id) {
        try {
            component = AdfPage.PAGE.findComponentByAbsoluteId(id);
        }catch(e){
            logger.logError(e);
        }
    }

    return component;
}

我想知道:

  • 如果我已经按照JavaScript面向对象编程的规范实现了Logger类,那么它是否能处理浏览器没有控制台的情况?
  • 如何使init()方法无法从其他JavaScript文件或方法中访问?我的意思是如何将其设置为private

任何指针都对我有很大帮助。

更新

从另一个SO线程中,我找到了有关私有方法的信息,并改变了我的方法:

function Logger() {
    init();
}

Logger.prototype = (function() {
    var console;

    var init = function() {
        if(!window.console){ 
            this.console = {
                log: function(message){},
                info: function(message){},
                warn: function(message){},
                error: function(message){}
            }; 
        } else {
            this.console = window.console;
        }
    };

    return {
        constructor: Logger,

        log: function(message) {
            this.console.log(message);    
        },

        logInfo: function(message) {
            this.console.info(message);
        },

        logWarn: function(message) {
            this.console.warn(message);
        },

        logError: function(message) {
            this.console.error(message);
        }
    };
})();

但是在这种情况下,我遇到了一个错误,即init未定义。

在一个单独的JS文件中...听起来你是说你实际上要通过JS将日志条目提交到JS文件中。 - Ryan
1
将所有“console”的实例重命名为其他名称,例如“console2”,以测试浏览器行为是否未定义。 - Thalaivar
1个回答

3

回答你的问题:

  • 你的类实现方式有点奇怪。使用闭包访问console变量,把它作为Logger的属性更合理。
  • 如果浏览器没有控制台,你不会得到错误(但记录器将无法正常工作)。
  • 为了使你的初始化函数私有化,你可以将其包装在IIFE(立即调用的函数表达式)中。

我拿你的代码稍作修改,得到了下面这段代码:

// Create the Logger function with an IIFE, this keeps all of the private
// variables out of the global scope, the only thing in the global scope
// is the function returned by the IIFE.
var Logger = (function (w) {
    var Logger,
        DummyConsole;

    DummyConsole = function () {
        this.log = function (message) {
            alert(message);
        };
        this.info = function (message) {
            // Implement however you want.
        };
        this.warn = function (message) {
            // ... 
        };
        this.error= function (message) {
            // ...
        };
    };

    Logger = function () {
        if (!w.console) {
            this.console = new DummyConsole();
        } else {
            this.console = w.console;
        }
    };

    Logger.prototype.log = function(message) {
        this.console.log(message);    
    };

    Logger.prototype.logInfo = function(message) {
        this.console.info(message);
    };

    Logger.prototype.logWarn = function(message) {
        this.console.warn(message);
    };

    Logger.prototype.logError = function(message) {
        this.console.error(message);
    };

    return Logger;
}(window));

// create a logger instance to check that the Logger class logs to the console.
var a = new Logger();
a.log("hello");

// Remove the console.
window.console = null;

// Create a new logger checking that it falls back to the dummy console implementation.
var b = new Logger();

// An (annoying) alert is shown.
b.log("Hi");

这段代码可以在JSFiddle上找到,链接如下:http://jsfiddle.net/mtufW/


谢谢Rob,我有一个疑问。你使用了this.console,但是这个console字段没有在任何地方声明。我已经看过工作示例了。我想知道这个console是如何工作的? - Tapas Bose
窗口对象被传递到函数中。请检查以下代码:Logger = function () { if (!w.console) { this.console = new DummyConsole(); } else { this.console = w.console; } }; - Thalaivar
是的,我之前看过这段代码。我的担忧是,如果你使用 this.console,那么在类作用域中应该定义了 var console;。但实际上并没有,尽管代码运行良好。我的问题是为什么?我们不需要在某个地方声明 var console 吗? - Tapas Bose
2
你正在定义 consolethis 对象上。在构造函数的上下文中,它是新创建的对象。类似于 var a = {}; a.someProp = "hello";。你不需要 var someProp,因为你正在定义它在一个对象上。 - RobH
还有一个小疑问,我每次使用Logger时都必须实例化它吗?还是我可以在我的site.js中定义它一次作为全局变量,并根据需要从任何方法中访问它?我看到你的示例中实例化了两次,原因是在第二个实例之前你设置了window.console=null吗? - Tapas Bose
1
@TapasBose - 是的,你说得对:你只需要定义一次,第二次只是为了证明如果控制台不可用,它将使用内部实现。 - RobH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接