
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 立即执行函数前面必须加分号 |
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 谢谢你的详细讲解!又学到一个之前都没听说过的新东西 函数柯里化 |