在我的Webpack捆绑的JS应用程序的矿井深处,我找到了这段代码:
var headers = Object.keys(headersObj).map(function (name) {
return [headersObj[name].name, headersObj[name].value]
})
(window).fetch(self._opts.url, // and so on...
这似乎来自于Slack API节点库(在某种程度上)所需的stream-http。
此代码在运行时会抛出此错误:
VM481:672 Uncaught TypeError: Object.keys(...).map(...) is not a function
at module.exports.ClientRequest._onFinish (eval at App (container.js:94), <anonymous>:672:4)
at module.exports.eval (eval at App (container.js:94), <anonymous>:614:9)
at module.exports.EventEmitter.emit (eval at App (container.js:94), <anonymous>:3615:18)
at finishMaybe (eval at App (container.js:94), <anonymous>:4371:15)
at afterWrite (eval at App (container.js:94), <anonymous>:4253:4)
at afterTick (eval at App (container.js:94), <anonymous>:4719:11)
at Item.run (eval at App (container.js:94), <anonymous>:3037:15)
at drainQueue (eval at App (container.js:94), <anonymous>:3007:43)
如果在未定义的变量上运行Object.keys
,则会发生同样的错误。但是,headersObj
已定义,并且是一个对象。
当我将代码更改为:
时
var headers = Object.keys(headersObj).map(function (name) {
return [headersObj[name].name, headersObj[name].value]
}); // <- please note yon semicolon
(window).fetch(self._opts.url, // and so on...
正常运行。问题是,这不是我的代码。我无法轻易地在捆绑脚本的上游添加分号。
看起来问题(在评论中指出)是原始代码被解释为:
var headers = Object.keys(headersObj).map(function (name) {
return [headersObj[name].name, headersObj[name].value]
})(window).fetch(self._opts.url, // and so on...
更明显地是对window
传入的结果(列表,而不是函数)的调用。
window
的实例由Webpack插件生成:
plugins: [
new webpack.DefinePlugin({
global: 'window'
})
],
似乎隐含地将window
包裹在parens中。有没有办法改变这种行为?
答案 0 :(得分:2)
<强> 1。为什么这个分号似乎是必要的?
如果你不添加分号,JavaScript会理解它需要获取表达式var headers = Object.keys(headersObj).map(...)
的返回值 - 这是一个数组 - 然后调用它,传递window
as一个参数。它会抛出一个错误,因为你的数组不是一个函数。它基本上是这样做的:
var headers = (Object.keys(headersObj).map(...))(window).fetch(self._opts.url, // and so on...
<强> 2。如何在不更改源代码的情况下解决此问题?
如果不更改源代码,我无法找到解决方法。您可以在第一行的末尾(如您所指向的那样)或第二行的开头添加分号:
var headers = Object.keys(headersObj).map(...)
;(window).fetch(self._opts.url, // and so on...
文章Semicolons in JavaScript are optional描述了您在“没有分号编码时唯一真正的陷阱”一节中遇到的同样问题。
答案 1 :(得分:0)
这是一个奇怪的情况,因为你不希望看到单个表达式包裹括号。 (window)
与window
相同,但括号是多余的。
显而易见的解决方案是简单地删除多余的括号
var headers = Object.keys(headersObj).map(...)
window.fetch(self._opts.url, // and so on...
添加一个领先的分号只是膨胀。
存在立即调用的匿名函数
的情况(function(){... some code }()); // the Crockford way or
(function(){... some code })();
脚本文件的开头行多少次。如果将这样的脚本文件连接成单个文件以进行发布,如果前面的行没有分号并且作为表达式求值,则会抛出相同的错误。
var a = 0 // this line is an expression (it has a value)
(function(){... some code }()) // throws 0 is not a function
if(a !== b){ } // this line is a statement it does not have a value
(function(){... some code }()) // works
如果您编写公共库或连接自己的库文件,在使用立即调用的匿名函数时,它是第一个表达式,它需要在第一个括号之前放置一个分号以防止挂起表达式(因为想要更好术语)
var a = 0 // the expression stays in context until terminated
;(function(){... some code }()) // safe as the previous expression is no longer in context.
另请注意,立即调用的匿名函数将作为表达式进行求值。
(function(){... some code }())
(function(){... some code }()) // throws "is not a function error..
(function(){... some code })() // alternative form
(function(){... some code }()) // throws "is not a function error...
因此,使用分号明确终止表达式总是好的做法。
// good if guaranteed first line
(function(){... some code }());
(function(){... some code }());
// Best
;(function(){... some code }());
(function(){... some code }());