【问题标题】:Why does a semicolon seem to be necessary here?为什么这里似乎需要分号?
【发布时间】:2017-06-13 19:42:48
【问题描述】:

在我捆绑了 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...

工作正常。问题是,这不是我的代码。我无法轻松地在捆绑脚本的上游添加分号。

  1. 为什么这个分号看起来很有必要?
  2. 如何在不更改源代码的情况下解决此问题?

编辑

看起来问题(在 cmets 中指出)是原始代码被解释为:

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 包装在括号中。有没有办法改变这种行为?

【问题讨论】:

  • 这似乎是 js 缩小的问题,其中这些行在不使用分号的情况下将})(window 连接在一起,因此使用分号,即使在 js 缩小之后,这两行也将});(window 分开。

标签: javascript syntax webpack


【解决方案1】:

臃肿??

这是一种奇怪的情况,因为您不会期望看到单个表达式用括号括起来。 (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 }()); 

【讨论】:

    【解决方案2】:

    1.为什么这个分号看起来很有必要?

    如果不加分号,JavaScript 会理解它需要获取表达式var headers = Object.keys(headersObj).map(...) 的返回值——这是一个数组——然后调用它,传递window 作为参数。它将引发错误,因为您的数组不是函数。它基本上是在做这样的事情:

    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 描述了您在“不使用分号进行编码时唯一真正的陷阱”部分中遇到的相同问题。

    【讨论】:

      猜你喜欢
      • 2010-12-15
      • 1970-01-01
      • 2012-06-03
      • 1970-01-01
      • 2021-08-27
      • 2017-09-08
      • 2019-01-16
      • 2021-10-22
      相关资源
      最近更新 更多