我正在使用 JavaScript 并且语句出现问题
console.log.bind(console)
请告诉我这个声明实际上是做什么的。我已经应用了几次,但它没有做任何事情。
我正在使用 JavaScript 并且语句出现问题
console.log.bind(console)
请告诉我这个声明实际上是做什么的。我已经应用了几次,但它没有做任何事情。
在JavaScript中,this
函数调用中被确定如何被调用的函数(正常功能,见*下文)。如果它作为检索对象属性的表达式的一部分被foo.bar()
调用(例如,bar()
作为从 获取它的属性检索操作的一部分调用foo
),this
则设置为在调用函数期间该属性来自的对象。
假设您想要更短的 形式console.log
,例如f
。你可以这样做:
var f = console.log; // <== Suspect!
...但是如果log
函数在调用期间依赖于this
引用console
对象,那么调用f("Message here")
将不起作用,因为this
不会引用console
.
Function#bind
仅适用于这种情况:它允许您创建一个新函数,该函数在调用时将调用原始函数并this
设置为您提供的值。所以
var f = console.log.bind(console); // Still suspect, for a different reason
...理论上,应该给你一个函数,f
,你可以调用它来登录到控制台。
除了:主机提供的函数console.log
(和alert
和getElementById
)不需要是“真正的”JavaScript 函数(尽管在现代浏览器上它们往往是,或者至少非常接近),并且不需要具有它们的所有功能,包括bind
。因此,如果您在该行上遇到错误,则可能是您在该行上使用的引擎不支持bind
该console.log
功能。
那么什么是“主机提供的功能”?规范中未明确定义为JavaScript 的一部分的任何函数,该语言。再说一次,在浏览器上,浏览器相关的功能,比如alert
或console.log
等等。
我可以想到该线路可能会给您带来麻烦的两个原因:
上图:您使用的 JavaScript 引擎无法实现console.log
真正的功能。
您在关闭开发工具的情况下在 IE 上使用上面的行。在 IE 上,当开发工具未打开时,console
对象未定义,因此该行将抛出ReferenceError
.
如果最终目标是获得一个您可以调用的函数,例如f("Message here")
, for 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;
}
});
关于这件事的快速更新,您似乎不再需要将控制台绑定到自己了。
Chromium 开始对console
对象进行一些深入的更改,该对象现在已经绑定到自身。https://chromium.googlesource.com/chromium/src.git/+/807ec9550e8a31517966636e6a5b506474ab4ea9
似乎所有其他浏览器都遵循了这条路径(在最新版本的 Firefox 和 Node 中进行了测试)。
我想,如果您需要与旧浏览器兼容,您仍然需要手动绑定控制台,但出于调试目的,您现在可以省略.bind(console)
:)
TJ Crowder 的回答帮助我解释并解决了我在重定向console.log
输出时遇到的问题,但他对“无函数#apply”案例的解决方案似乎对许多用例有任意限制。
我像这样重写了他的代码,它更简洁,功能更强大:
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
用空格分隔参数,所以我也在这里复制了它。对此的主要限制是它不处理作为对象的参数。如果需要,您可以将这些字符串化。
正如其他答案中所述,它将console.error
函数作为错误处理程序,并bind(console)
使其console
用作this
其主体内的值。否则,this
将设置为全局对象(window
在浏览器中)并且调用将失败。在这里解释得很好。
通常您可以在Promise
错误处理中看到这一点(例如,从 Angular 2 快速入门):
System.import("unmarshaller/Unmarshaller.js").then(null, console.error.bind(console));
题外话部分:
您可能希望创建自己的处理程序来预处理错误。在上面的例子中,在控制台console.error
打印丑陋Error
,因为SystemJS
只告诉“错误加载 Unmarshaller.js”。另一个错误隐藏在originalErr
.
制作一个自定义处理程序来解包:
function handleError(e) {
if (e.originalErr)
throw e.originalErr;
throw e;
}
System.import("unmarshaller/Unmarshaller.js").then(null, handleError);
不需要.bind()
,并且会给你Error
最初抛出的,比如:
错误:给定的对象没有指定“w:winduptype”并且没有给出目标类:
[{"w:winduptype":["FileResource","ArchiveModel:","WarArchiveModel"], ...