2016-02-25 47 views
3

我想创建我自己的console.log版本,使用'咖喱'功能,并包括显示或不显示日志的可能性。 (激发了SecretsOfTheJavascriptNinja)使用闭包|创建我自己的console.log版本Javascript

因此,我使用闭包来实现这样的功能:

Function.prototype.conditionalCurry = function() { 
    var fn = this; 
    var args = Array.prototype.slice.call(arguments); 
    var show = args[0]; 
    args = args.slice(1, args.length); 

    return function() { 
     if (show) { 
      return fn.apply(this, args.concat( 
       Array.prototype.slice.call(arguments))); 
     } 
     else return; 
    }; 
}; 

当我在它工作的终端中使用节点测试的代码:

var newLog = console.log.conditionalCurry(true, 'Always visible|'); 
newLog('log visible'); // gives on the console: Always visible| log visible 

newLog = console.log.conditionalCurry(false, 'never visible|'); 
newLog('log visible'); // gives nothing, it works! 

但是,当我测试代码在Chrome 48.0.2564.109和Firefox 44.0.2上出现了问题,我认为在这两种情况下都是一样的。

据我所知,当我在终端中使用节点时,以某种方式将传递给函数conditionalCurry的上下文'this'是一个匿名函数,但在浏览器的情况下'this'显示为一个函数'日志“,我相信这是破坏代码。

任何想法如何在浏览器中实现此功能?

Fiddle

在此先感谢!


随着BERGI的解决方案,现在它的工作原理:Fiddle

+3

使用'console.log.bind(控制台).conditionalCurry(...)' – Bergi

+0

感谢@Bergi它的作品开箱! 让我看看我是否明白。控制台对象的方法log()需要访问控制台的上下文来工作,他们自己的关闭是什么。 因此,当我在console.log上调用conditionalCurry时,获取并存储在fn变量中的上下文是log()函数中的一个变量。 那么当我调用newLog时,它不能打印任何东西,因为。日志无法访问通常具有的闭包,导致我的fn变量引用了log()上下文,而不是控制台上下文...我很接近?谢谢! – Javingka

+0

“*原因.log无法访问通常具有*的闭包 - ”不,闭包变量在这里并不重要(无论如何,您都可以从外面混淆它们)。只有['this' context](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)是预期的一个 - 一个'Console'实例是非常重要的。 – Bergi

回答

0

这是执行上下文的问题。由于您将咖喱函数附加到“函数原型”,因此“this”关键字将引用您正在调用它的函数。在这种情况下,console.log中的'日志'。

我不会修改的原型,只是做一个咖喱辅助函数:)

function curry(fn, ctx) { 
    var slice = Array.prototype.slice.call; 

    return function f() { 
    var x = slice(arguments); 
    // If we have enough arguments, call the function 
    // You can get the arity with the 'length' property 
    if (x.length >= fn.length) return fn.apply(ctx, x); 
    // If not, collect more arguments 
    return function() { 
     var y = slice(arguments); 
     return f.apply(null, x.concat(y)); 
    } 
    } 
} 

// Trivial example 
var curriedSum = curry(function(a, b, c) { 
    return a + b + c; 
}); 

// this now works 
curriedSum(1, 2, 3); 
curriedSum(1)(2, 3); 
curriedsum(1)(2)(3); 



// for your use case 
var curriedLog = curry(function(show, prefix, msg) { 
    if (! show) return; 

    return console.log(prefix + msg); 
}); 

// Use like so 
var neverLogs = curriedLog(false); 
neverLog('Some Prefix|', 'some message') // never logs 

var logWithPrefix = curriedLog(true, 'This is my prefix|'); 
logWithPrefix('wassup') // logs 'this is my prefix| wassup' 

如果您需要强制“这个”关键字是一个特定对象,通过该对象作为第二个参数。

curry(fn, context); 
+1

“咖喱”功能如何解决上下文中的问题?你能说明它是如何适用于OP的用例(而不是那种不重要的,不依赖于上下文的总和函数)? – Bergi

+0

我更新了它作为第二个参数的上下文。我的第二句解释了为什么OP的背景是错误的。 –

+0

是的,你的解释很好,但你的解决方案不适合。而且还不是真的,imo。 – Bergi

1

我会厌倦了修改现有语言功能的原型,如Function。看起来你确实需要重新使用这些日志记录工具的实例,所以你可以定义该实例并以“古典”的意义来使用它。

例如,让我们创建一个名为“Logger”的“类”(只是使用语言不可知的术语)。记录器的实例将能够被配置为显示前缀消息,有条件地将消息发送到日志,并且还以半传统方式使用日志。

function Logger(display,prefix){ 
 
    this.display = display == [][0] ? true : display; 
 
    this.prefix = prefix; 
 
} 
 
Logger.prototype.log = function(){ 
 
    if(this.display){ 
 
    [].splice.apply(arguments,[0,0,this.prefix]) 
 
    console.log.apply(console,arguments); 
 
    }else{ 
 
    console.log(this.prefix); 
 
    } 
 
    return this; 
 
};  
 
Logger.prototype.show = function(truthy){ 
 
    this.display = !!truthy; 
 
    return this; 
 
}; 
 
Logger.prototype.note = function(msg){ 
 
    this.prefix = msg; 
 
    return this; 
 
}; 
 

 
var newLog = new Logger(true,'always |'); 
 
newLog.log('show me');//always | show me 
 

 
newLog.note('never show').show(false); 
 
newLog.log('show me now');//never show

+0

感谢@Travis,这不是直接回答我的问题,但给了我一个很好的方法来解决一般问题。 – Javingka