作者回复: Yes! 满分答案👍
作者回复: 😃👍
作者回复: 是的。不过,这算是题解。中心还是模块装载执行和标识符绑定全过程来着😄
标识符和值绑定是“声明”语法处理的核心,而六种声明是js静态语法的核心。而静态语法,也就是这一整篇“语言如何构建”的核心了🤓
作者回复: 对哒!赞+2
作者回复: 有点特殊,但就处理逻辑(以及目的)上来说,也并不算是特例。
其实“函数定义(Function Definition)”这个概念出现得比较奇怪。
仔细分析一下就明白了,你想,“函数声明(Function Declaration)”是静态语义的,它在执行期的结果是empty,所以它必须是具名的才能导出,因为“声明(6种)”的目的都是具名,而export原则上只能“导出一个名字”。所以,由于“函数定义(Function Definition)”没有名字,所以它不能按函数声明来处理。
然后,由于“函数表达式(Function Expression)”是动态语义的,有执行语义(也就是执行结果返回不是empty),得到一个运行期概念上的“闭包”。但这并不是最关键处,最关键的地方在于函数表达式没名字——即使是具名的函数表达式,它的名字也只能闭包内有影响。由于它没有名字一个可供导出的名字,所以也不能直接直接用作export的对象。
那么到底在概念上该怎么说这个东西呢?ECMAScript在这里就加了这么一层概念,叫“函数声明(Function Declaration)”,一方面它是有静态语义的,它声明了某个东西;另一方面,它的名字又是迟绑定的,需要到了执行期根据“name = FunctionExpression”中的`name`来确认。
在这种情况下,其实“函数定义(Function Definition)”就是“函数表达式”的一层概念封装:它又有在外层(或被关联的对象)中的名字,它又是表达式;它的执行结果又是闭包,又是实例。
所以箭头函数看起来是特例,但用在导出语法的“这个位置”时,概念上却仍然是“封装了一层的‘箭头函数表达式’”,仍然还是“函数定义”。
作者回复: 正好,刚写完“Y”同学的留言,你不妨看看,应该正好能回答你的疑问。
(万恶的极客时间没有提供分留言链接的功能,产品同学要打手板心5次 🤔)
作者回复: 是的。这个“执行期”在用户代码之前。
作者回复: ```
// t.mjs
console.log("here =>", typeof f);
import f from './f.mjs';
// f.mjs
export default function() {}
console.log('NOW');
// test
> node --experimental-modules t.mjs
NOW
here => function
```
想想,
1. 为什么`here`为什么是function呢?import语句还没有到呢。
2. 为什么`NOW`在`here`之前?这是哪个时候的执行过程?
作者回复: 不知道你的引擎的情况,我这里显示会是default。
```
// f.mjs
export default function() {}
// t.mjs
import f from './f.mjs';
console.log(f.name);
// test
> node --experimental-modules t.mjs
default
```
作者回复: 是的。这样没问题。除了缺一咪咪的严谨之外,你的理解是对的。^^.
作者回复: 这个问题请参考一下在评论区给Marvin的回复就好了。^^.
作者回复: 这是因为类似于:
obj = {
f: function() {
},
...
}
这样位置中的匿名函数,在ECMAScript中都是称为“匿名函数定义”,而不是“匿名函数表达式”。所有在语法上记为“x = functionExpression”的,在处理上都与一般表达式有不同,这是一个非常非常小的细节,但在引擎层面,加入了好大一段逻辑呢。
真正的匿名函数表达式,是下面这样的:
> (1 + function() {})
就是:把它直接用在一个表达式计算过程中,而不是把它用来赋值(或绑定,或引用)给另一个东西。这种情况下,它才是按匿名函数表达式来处理的。
这几讲都是讲JavaScript的静态语言特性的,所以“词法分析以及对应的引擎处理”是要点,在词法分析阶段,关键在于“不能为它(函数、函数表达式、函数定义等等)创建闭包”。因为在静态处理阶段,还没有“闭包”这个概念,所以好多东西处理起来跟我们平常的理解不同,这就是根由了。
作者回复: 第一个也不是“(具名)函数表达式”。因为如果它是表达式(expression),那么它的执行结果就是一个实例,而实例是无法导出的。只有它是一个“函数定义”,它才能在“静态语法分析之后、代码执行之前”被导出。
作者回复: 这个细述起来有点复杂,因为有好些细节的地方都能被称为“顶层的(代码)”。简而言之,你把一个.js文件中所有在全局的声明语句去掉,剩下的就是顶层代码了。
顶层这个概念其实挺重要的,因为tc39现在有一份提案在推,就是top-level await。这个在引擎实现的层面上,以及应用的层面上都挺关键的。
作者回复: 呵呵,其实真讲JavaScript的地方并不特别的多。就好象讲数据结构总需要一门基础语言一样,那个基础语言其实不重要,重要的是数据结构。
除了简单的语法和一些惯例之外,这门课真在讲“JavaScipt怎么用”的地方并不多。^^.
作者回复: “并没有执行表达式”
+1