function sleepPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise")
}, 1000)
})
}
sleepPromise() // 这里没有分号
(function () {
console.log("hhh")
})()
为啥调用 sleepPromise()的时候不加分号,就会跑不起来,加了分号就可以了
PS C:\Users\lala\Downloads> node c.js
C:\Users\lala\Downloads\c.js:11
(function () {
^
TypeError: sleepPromise(...) is not a function
at Object.<anonymous> (C:\Users\lala\Downloads\c.js:11:5)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
加了分号之后
function sleepPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("promise")
}, 1000)
})
}
sleepPromise(); // 这里有分号
(function () {
console.log("hhh")
})()
PS C:\Users\lala\Downloads> node c.js
hhh
promise
我会 C ,但是不会 JavaScript ,求指教,感谢!
1
Baymaxbowen 2022-05-26 10:32:54 +08:00 via iPhone
下面自执行函数的问题
|
2
renmu123 2022-05-26 10:34:37 +08:00 via Android
大概是因为被解析成这样了 sleepPromise()(function...)()
function..被当成了函数 sleeppromise 的参数,sleeppromise 又不是函数所以加报错了 |
3
noe132 2022-05-26 10:35:44 +08:00
a()
(b)() 其实是 a()(b)() a(); (b)() 才是 a();(b)() 这是自动分号插入的机制。括号开头的行会有这个问题。 |
4
wangxiang 2022-05-26 10:36:27 +08:00
论写分号的重要性
|
5
shintendo 2022-05-26 10:36:34 +08:00
搜索关键词:javascript ASI
|
6
ipwx 2022-05-26 10:40:54 +08:00
|
7
horseInBlack 2022-05-26 10:42:21 +08:00
和 promise 没关系,这样写也就会报错
function testFunction(){ console.log('test') } testFunction() (function () { console.log("hhh") })() 报的是 Uncaught TypeError: testFunction(...) is not a function 也就是说 JS 认为 testFunction()返回了一个函数,然后这个函数执行的参数是 function () { console.log("hhh") })( 而不是预期的作为立即执行函数执行 加上分号以后 JS 就知道那句话结束了,不会连在一起执行 所以写代码的时候可以配合自动格式化工具,团队的话可以共用一套规则 理论上来说加上分号减少了 JS 分析分词的步骤效率更高,减少歧义,而且自动执行的事也不费什么事 |
8
TomatoYuyuko 2022-05-26 10:42:55 +08:00
首先编译的时候浏览器会帮你补分号,然后识别你的代码,你的这块代码是:sleepPromise()(function () {console.log("hhh")})(),浏览器看你这么写麻了,他也不知道该怎么断句了,因为有歧义,所以要加
|
9
daimubai 2022-05-26 10:53:03 +08:00
在大多数情况下,换行意味着一个分号。但是“大多数情况”并不意味着“总是”!
JavaScript 无法确定是否真的需要自动插入分号的情况 alert("Hello") [1, 2].forEach(alert); 这种情况也会报错。 来源 https://zh.javascript.info/ |
10
Shy07 2022-05-26 10:53:20 +08:00
除了 ( ,还有 [ 和 `,这三个符号作为行首,建议前面加分号
可以参考这个: https://standardjs.com/rules-zhcn.html#%E5%85%B3%E4%BA%8E%E5%88%86%E5%8F%B7 |
11
shakukansp 2022-05-26 10:55:10 +08:00
举个例子
const fn = () => { return function () {} } fn()() 什么意思 fn()(function () { console.log("hhh") })什么意思 fn();()什么意思 fn();(function () { console.log("hhh") })什么意思 自己想想 |
12
Justin13 2022-05-26 10:55:59 +08:00 via Android
不会走,就想跑,老老实实加分号不好么
|
13
fenglala OP 看懂了,感谢大家的回复!
我搞了个让不加分号也能跑起来的例子,虽然实际代码中想表达的不是这个意思,但是让我理解了: function returnFunction() { console.log('function return function return function') return () => { console.log('function return function') return () => { console.log('function') } } } returnFunction() (function () { console.log("hhh") })() |
14
Leviathann 2022-05-26 11:00:59 +08:00 3
立即执行函数前面必须加分号
|
15
molvqingtai 2022-05-26 11:02:27 +08:00
原因楼上都说了,建议使用 eslint 或 prettier ,如果配置无分号的风格,会自动在有歧义的语句上加上分号
|
16
MegrezZhu 2022-05-26 11:04:45 +08:00
所以说分号是多么重要……
|
17
july1995 2022-05-26 11:09:48 +08:00 via Android
14 楼加 1 。 立即执行函数前需要加分号。 具体为啥 老师讲了,没记住,就记住了一个结论了。
|
18
Pastsong 2022-05-26 11:10:27 +08:00
+(function () {})()
前面写个+也是可以的,如果你真的很讨厌分号 |
19
cheneydog 2022-05-26 11:15:33 +08:00
学到了
|
20
libook 2022-05-26 11:21:48 +08:00
https://262.ecma-international.org/5.1/#sec-7.9
官方文档里面说明了自动补充分号的思路,你需要在省略分号的同时,确保代码不会产生歧义,自己做的话可能会有些心智负担,除非你用 StandardJS (注意这只是个工具名称,并不真的是 JS 的 Standard )之类的 Linter ,可以帮你自动规避不写分号会产生歧义的情况。 但我个人推荐能写分号的地方都写分号,特别是可能会涉及到代码 minification 的情况,你源代码执行的时候可能自动补充分号是正常的,但 minify 之后很可能就会出现问题。 分号的存在就是为了避免歧义的情况,因为 JS 不靠缩进和换行来表示表达式的终止或层级关系,有些情况下无法避免写分号,刻意不写分号的意义就不那么大了。 |
21
wangtian2020 2022-05-26 15:09:07 +08:00
sleepPromise()(function () {console.log("hhh")})()
sleepPromise()(/* something */)() 如果你用 prettier 格式化一下,他就会变成这个样子 很容易看出问题所在。根本原因是 JavaScript 语法的冲突 |
22
ryougifujino 2022-05-26 15:17:18 +08:00
以前我也是坚定的分号党,其实无分号反而更简洁,后来成为了无分号党。只需要稍微注意一下就行了。简单来说就是“一行开头是括号或者方括号的时候加上分号就可以了”
参考: JavaScript 语句后应该加分号么? - 尤雨溪的回答 - 知乎 https://www.zhihu.com/question/20298345/answer/49551142 |
23
ryougifujino 2022-05-26 15:31:14 +08:00
@ryougifujino #22 append 一下,还得加一个字符串模板开头。https://zhuanlan.zhihu.com/p/24612490
|
24
tutou 2022-05-26 16:40:09 +08:00
所以一般 js 插件自执行函数自己会加个分号
|
25
weiwoxinyou 2022-05-26 20:16:22 +08:00
@fenglala op 的这个例子不是很符合你的原意,这个例子之所以能运行是因为符合了编译器的解析规则,题干中的代码本质上是未插入分号导致了
f() (fx())() 被解析成了 f()(fx())(), 在编译器解析你的代码时,从左向右读取,也就是说编译器的解析顺序是 f() => // 1 f()(fx()) => // 2 f()(fx())() // 3 在第一步中,你的函数本正确执行了,但是在第二步中,编译器认为第一步的结果是一个函数,后面括号内的是函数传递的参数,但是由于第一步运行完没有返回函数,因此第一步的返回值被定义为空,显然空值并不是函数,于是产生报错,产生报错后,错误向外层抛出,而顶层调用函数名叫 sleepPromise ,于是,该报错为 sleepPromise is not a function. op 的例子之所以能执行,是因为你返回了一个函数,这个函数里面可以被递归调用,递归返回的也是一个函数,刚好满足了被编译器解析的对一个函数进行 3 次调用的规则,本质上是将返回的匿名函数作为参数传递给了调用者,JS 里面与这种调用很相似调用的叫函数柯里化 |
26
fenglala OP @weiwoxinyou 谢谢你的详细讲解!又学到一个之前都没听说过的新东西 函数柯里化
|