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

shu*_*ham 54 javascript

我使用JavaScript并在语句中遇到问题

console.log.bind(console)
Run Code Online (Sandbox Code Playgroud)

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

T.J*_*der 82

在JavaScript中,this函数调用中被确定如何被调用的函数(正常功能,见*下文).如果它作为检索对象属性的表达式的一部分被foo.bar()调用(例如,调用bar()作为从中获取它的属性检索操作的一部分foo),this则将其设置为在调用函数期间属性所来自的对象.

假设你想要一个较短的形式console.log,比如f.你可以这样做:

var f = console.log; // <== Suspect!
Run Code Online (Sandbox Code Playgroud)

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

Function#bind就是这种情况:它允许你创建一个新函数,当被调用时,它将调用原始this设置为你给出的值.所以

var f = console.log.bind(console); // Still suspect, for a different reason
Run Code Online (Sandbox Code Playgroud)

... 理论上,应该为您提供一个函数,f您可以调用它来登录控制台.

:像主机提供的功能console.log(和alertgetElementById)不必须是"真正"的JavaScript函数(虽然在现代的浏览器,他们往往是,或至少非常接近),并且不要求有所有功能,包容bind.因此,如果您在该行上收到错误,那么您使用该行的引擎可能不支持bindconsole.log功能.

那么什么是"主机提供的功能"?未在规范中明确定义为JavaScript的一部分的任何函数,即语言.再次,在浏览器上,与浏览器相关的功能如同alert等等console.log.

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

  1. 以上:您使用的JavaScript引擎无法发挥console.log作用.

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

如果最终目标是让你可以打电话,说一个函数f("Message here"),对console.log,这里是你如何能做到这一点对付上述两种#1和#2:

function f(item) {
    if (typeof console != "undefined" && console.log) {
        console.log(item);
    }
}
Run Code Online (Sandbox Code Playgroud)

这只允许你给一个项目,而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";
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

......那太难看了.


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

// Normal function
function foo() {
    console.log(this.name);
}

// Create a bound function:
var f = foo.bind(someObject);
Run Code Online (Sandbox Code Playgroud)

你怎么打电话都没关系f,它会foothisset来调用someObject.

*ES2015(又名ES6)增加了箭头功能.随着箭头的功能,this不是通过这个函数是如何调用的设置; 相反,该函数继承this自创建它的上下文:

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

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

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

  • @geoidesic:它直接回答了这个问题:*"所以`var f = console.log.bind(console);`理论上应该给你一个函数`f`,你可以调用它来登录控制台. "*它也解释了为什么它会这样做,为什么你需要这样做而不仅仅是`var f = console.log`(这是'this`进入它的地方),以及它是如何工作或取决于主机实施. (5认同)

ato*_*mrc 9

关于这件事的快速更新,似乎您不再需要将控制台绑定到自己了。

Chromium 开始对console对象进行一些深入的更改,该对象现在已经绑定到自身。https://chromium.googlesource.com/chromium/src.git/+/807ec9550e8a31517966636e6a5b506474ab4ea9

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

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


Mor*_*red 5

TJ Crowder的回答帮助我解释并解决了重定向console.log输出的问题,但他对"无函数#应用"案例的解决方案似乎是对许多用例的任意限制.

我重写了这样的代码,它更干净,更实用:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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