这个陈述有什么作用? console.log.bind(控制台)

时间:2015-02-23 07:27:24

标签: javascript

我正在使用JavaScript并且语句

出现问题
console.log.bind(console)

请告诉我这个陈述实际上做了什么。我已经应用了几次,但没有做任何事情。

4 个答案:

答案 0 :(得分:77)

在JavaScript中,函数调用中的this如何调用函数决定(对于普通函数,请参阅下面的*)。如果它作为检索对象属性的表达式的一部分被调用(例如,foo.bar()调用bar()作为从foo获取它的属性检索操作的一部分,则设置this在调用函数期间,属性所来自的对象。

假设您需要console.log的缩写形式,例如f。你可以这样做:

var f = console.log; // <== Suspect!

...但如果log函数在调用期间依赖于this引用console对象,则调用f("Message here")将无效,因为{{ 1}}不会引用this

console适用于这种情况:它允许您创建一个新函数,在调用时,将调用原始函数,并将Function#bind设置为您提供的值。所以

this
理论上,

... 应该为您提供一个函数var f = console.log.bind(console); // Still suspect, for a different reason ,您可以调用它来登录控制台。

除外:主机提供的功能如f(以及console.logalert)不需要是“真正的”JavaScript功能(尽管在现代浏览器往往是,或者至少非常接近,并且不需要具有所有功能,包括getElementById。因此,如果您在该行上收到错误,那么您使用该行的引擎可能不支持bind函数上的bind

那么“主机提供的功能”是什么?任何未在规范中明确定义为 JavaScript (语言)一部分的函数。同样,在浏览器上使用与console.logalert等浏览器相关的功能。

我可以想到线路可能给你带来麻烦的两个原因:

  1. 上述内容:您正在使用的JavaScript引擎不会使console.log成为真正的功能。

  2. 您正在IE上使用上面的行并关闭了Dev Tools。在IE上,当dev工具未打开时,console.log对象未定义,因此该行将抛出console

  3. 如果最终目标是获得一个功能,您可以致电ReferenceErrorf("Message here")console.log,以下是处理上述#1和#2的方法:

    function f(item) {
        if (typeof console != "undefined" && console.log) {
            console.log(item);
        }
    }
    

    只允许您提供一个项目,而console.log允许您提供多个项目(console.log("this", "that", "and the other")),但如果console.log可能不是真正的JavaScript功能,那么它可能没有Function#apply,这使得包装起来非常困难。

    现在,如果您不关心获取相同的输出,只要您能看到其中的内容,就可以从console.log("this", "that", "and the other")获取,只需使用console.log(arguments);arguments是传递给函数的所有参数的内置标识符。但是如果你想复制确切的输出,你最终会做这样的事情:

    function f() {
        var a = arguments;
    
        if (typeof console != "undefined" && console.log) {
            if (console.log.apply) {
                // It has Function#apply, use it
                console.log.apply(console, arguments);
            } else {
                // Ugh, no Function#apply
                switch (a.length) {
                    case 0: console.log(); break;
                    case 1: console.log(a[0]); break;
                    case 2: console.log(a[0], a[1]); break;
                    case 3: console.log(a[0], a[1], a[2]); break;
                    case 4: console.log(a[0], a[1], a[2], a[3]); break;
                    case 5: console.log(a[0], a[1], a[2], a[3], a[4]); break;
                    default:
                        throw "f() only supports up to 5 arguments";
                }
            }
        }
    }
    

    ......这太丑了。


    * ES5添加了绑定函数,这些函数通过绑定附加了this值:

    // Normal function
    function foo() {
        console.log(this.name);
    }
    
    // Create a bound function:
    var f = foo.bind(someObject);
    

    如果您致电f并不重要,它会在foo设置为this的情况下致电someObject

    * ES2015(又名ES6)添加了箭头功能。使用箭头函数,this 根据函数的调用方式设置;相反,该函数从创建它的上下文继承this

    // Whatever `this` is here...
    var f = () => {                             // <== Creates an arrow function
        // Is what `this` will be here
    };
    

    当您在对象方法中执行Array#forEach之类的操作时,箭头函数非常方便:

    this.counter = 0;
    this.someArray.forEach(entry => {
        if (entry.has(/* some relevant something */)) {
            ++this.counter;
        }
    });
    

答案 1 :(得分:5)

T.J。 Crowder的回答帮助我解释并解决了重定向console.log输出时遇到的问题,但他的解决方案是#34; no Function#apply&#34;案件似乎是对许多用例的任意限制。

我重写了他的代码,这个代码更清洁,更实用:

function f() {
    var a = arguments;

    if (typeof console != "undefined" && console.log) {
        if (console.log.apply) {
            // It has Function#apply, use it
            console.log.apply(console, arguments);
        } else {
            // Ugh, no Function#apply
            var output = '';
            for (i=0;i<arguments.length;i++) {
                output += arguments[i] + ' ';
            }
            console.log(output);
        }
    }
}

console.log用空格分隔参数,所以我也在这里复制了。这方面的主要限制是它不处理作为对象的参数。如果需要,您可以将这些字符串化。

答案 2 :(得分:2)

关于此问题的快速更新,您似乎不再需要将控制台绑定到自身。

Chromium开始在console对象上进行一些深层次的更改,现在已经绑定了它。 https://chromium.googlesource.com/chromium/src.git/+/807ec9550e8a31517966636e6a5b506474ab4ea9

似乎所有其他浏览器都遵循此路径(在最新版本的Firefox和Node中测试过)。

我想,如果您需要与旧浏览器兼容,您仍然需要手动绑定控制台,但出于调试目的,您现在可以省略.bind(console):)

答案 3 :(得分:0)

我敢于推测,这是许多人可能想要的:

通常你可以在Promise错误处理中看到这一点(例如,从Angular 2快速入门):

System.import("unmarshaller/Unmarshaller.js").then(null, console.error.bind(console));

正如其他答案中所述,它将console.error函数作为错误处理程序,而bind(console)使其使用console作为其中this的值&# 39;身体。否则,this将被设置为全局对象(浏览器中为window),并且调用将失败。很好地解释了here

offtopic部分:

您可能想要创建自己的处理程序来预处理错误。在上面的示例中,console.error在控制台中打印丑陋的Error,因为SystemJS仅告诉&#34;加载Unmarshaller.js&#34; 时出错。另一个错误隐藏在originalErr

制作一个自定义处理程序来解包:

function handleError(e) {
    if (e.originalErr)
        throw e.originalErr;
    throw e;
}

System.import("unmarshaller/Unmarshaller.js").then(null, handleError);

不需要.bind(),并会为您提供最初抛出的Error,例如:

  

错误:给定对象没有指定&#34; w:winduptype&#34;并且没有给出目标类:
    [{&#34; w:winduptype&#34;:[&#34; FileResource&#34;,&#34; ArchiveModel:&#34;,&#34; WarArchiveModel&#34;],...