Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重学js —— Scripts #89

Open
lizhongzhen11 opened this issue Mar 14, 2020 · 0 comments
Open

重学js —— Scripts #89

lizhongzhen11 opened this issue Mar 14, 2020 · 0 comments
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Mar 14, 2020

Scripts

<script>
var a;
let b;
const c = 'c';
// ...
</script>

Script Records

脚本记录封装了有关正在求值的脚本信息。脚本记录包含 下表 字段

字段名 值类型 含义
[[Realm]] 领域记录 / undefined 创建此脚本的 领域。如果未赋值的话,那么就是 undefined
[[Environment]] 词法环境 / undefined 包含此脚本顶级绑定的 词法环境。当脚本实例化时会对该字段赋值。
[[ECMAScriptCode]] 一个 解析节点 使用 Script 作为 目标符号 解析该脚本其 源文本 结果。
[[HostDefined]] 任何都行,默认值是 undefined 保留给需要将其他信息与脚本关联的主机环境使用的字段。

ParseScript ( sourceText, realm, hostDefined )

基于将 sourceText 解析为 Script 的结果创建脚本记录。

  1. 断言:sourceText 是ECMAScript 源文本
  2. 使用 Script 作为 目标符号 解析 sourceText 并且分析任何早期错误条件的解析结果。如果解析成功且没发现早期错误,定义 body 为解析树的结果。否则,定义 body 为一个或多个 SyntaxError 对象的 List,这些对象表示解析错误和/或早期错误。解析和 早期错误 检测可以以依赖于实现的方式进行交织。如果存在多个解析错误和 早期错误,list中错误对象的数量和顺序与实现有关,但至少存在一个。
  3. 如果 body 是错误 List,返回 body
  4. 返回脚本记录 { [[Realm]]: realm, [[Environment]]: undefined, [[ECMAScriptCode]]: body, [[HostDefined]]: hostDefined }

ScriptEvaluation ( scriptRecord )

  1. 定义 globalEnvscriptRecord.[[Realm]].[[GlobalEnv]]
  2. 定义 scriptContext 为一个新的ECMAScript代码 执行上下文
  3. scriptContextFunction 赋值为 null
  4. scriptContextRealm 设为 scriptRecord.[[Realm]]
  5. scriptContextScriptOrModule 设为 scriptRecord
  6. scriptContextVariableEnvironment 设为 globalEnv
  7. scriptContextLexicalEnvironment 设为 globalEnv
  8. 暂停 当前的 运行时执行上下文
  9. scriptContext push到 执行上下文栈 顶;scriptContext 现在是 运行时执行上下文
  10. 定义 scriptBodyscriptRecord.[[ECMAScriptCode]]
  11. 定义 resultGlobalDeclarationInstantiation(scriptBody, globalEnv)
  12. 如果 result.[[Type]]normal
    1. result 设为 scriptBody 的求值结果
  13. 如果 result.[[Type]]normalresult.[[Value]]empty
    1. result 设为 NormalCompletion(undefined)
  14. 暂停 scriptContext 且将其从 执行上下文栈 中移除
  15. 断言:执行上下文栈 不为空
  16. 执行上下文栈 顶的上下文恢复为 运行时执行上下文
  17. 返回 Completion(result)

GlobalDeclarationInstantiation ( script, env )

当为了求值脚本而建立 执行上下文 时,当前 全局环境 下的声明会实例化。代码中声明的每个全局绑定都被实例化。

参数 script 是正在建立的 执行上下文ScriptBodyenv 是将要在其中创建绑定的全局词法环境。

  1. 定义 envRecenv环境记录
  2. 断言:envRec全局环境记录
  3. 定义 lexNamesscriptLexicallyDeclaredNames
  4. 定义 varNamesscriptVarDeclaredNames
  5. 遍历 lexNames 中的每个 name,(PS:这里指用 letconst 声明的变量名,如果环境中已经有相同的变量名,那么抛异常)
    1. 如果 envRec.HasVarDeclaration(name) 为 true,抛 SyntaxError 异常
    2. 如果 envRec.HasLexicalDeclaration(name) 为 true,抛 SyntaxError 异常
    3. 定义 hasRestrictedGlobal? envRec.HasRestrictedGlobalProperty(name)
    4. 如果 hasRestrictedGlobaltrue,抛 SyntaxError 异常
  6. 遍历 varNames 中的每个 name,(PS:这里特指用 var 声明的变量名)
    1. 如果 envRec.HasLexicalDeclaration(name) 为 true,抛 SyntaxError 异常
  7. 定义 varDeclarationsscriptVarScopedDeclarations
  8. 定义 functionsToInitialize 为一个新的空 List
  9. 定义 declaredFunctionNames 为一个新的空 List
  10. 遍历 varDeclarations 中的每个元素 d(别名),倒序排列,
    1. 如果 d 既不是 VariableDeclaration 又不是 ForBinding 更不是 BindingIdentifier
      1. 断言:dFunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclaration 中的一种
      2. 注意:如果存在多个相同名字的函数声明,会使用最后一个声明
      3. 定义 fndBoundNames 唯一元素
      4. 如果 fn 不是 declaredFunctionNames 中的元素,
        1. 定义 fnDefinable? envRec.CanDeclareGlobalFunction(fn)
        2. 如果 fnDefinablefalse,抛 SyntaxError 异常
        3. fn 加入到 declaredFunctionNames
        4. 插入 d 作为 functionsToInitialize 第一个元素
  11. 定义 declaredVarNames 为一个新的空 List
  12. 遍历 varDeclarations 中的每个元素 d(别名),
    1. 如果 dVariableDeclarationForBindingBindingIdentifier 中的一种,
      1. 遍历 dBoundNames 中每个字符串 vn
        1. 如果 vn 不是 declaredFunctionNames 中的元素,
          1. 定义 vnDefinable? envRec.CanDeclareGlobalVar(vn)
          2. 如果 vnDefinablefalse,抛 SyntaxError 异常
          3. 如果 vn 不是 declaredVarNames 中的元素,
            1. vn 添加进 declaredVarNames
  13. 注意:如果 全局对象普通对象,则在此算法步骤之后不会发生异常终止。但是,如果全局对象Proxy怪异对象,在以下某些步骤中,它可能表现出导致异常终止的行为。
  14. 注意:附件 B.3.3.2 在此处增加了额外的步骤
  15. 定义 lexDeclarationsscriptLexicallyScopedDeclarations
  16. 遍历 lexDeclarations 中每个元素 d
    1. 注意:词法声明变量仅在此处实例化但不会初始化
    2. 遍历 dBoundNames 中每个元素 dn
      1. 如果 dconst 声明,
        1. 执行 ? envRec.CreateImmutableBinding(dn, true)
      2. 否则,
        1. 执行 ? envRec.CreateMutableBinding(dn, false)
  17. 遍历 functionsToInitialize 中的每个 解析节点 f
    1. 定义 fnfBoundNames 唯一元素
    2. 定义 fofInstantiateFunctionObject,参数为 env
    3. 执行 ? envRec.CreateGlobalFunctionBinding(fn, fo, false)
  18. 按顺序遍历 declaredVarNames 中每个字符串 vn
    1. 执行 ? envRec.CreateGlobalVarBinding(vn, false)
  19. 返回 NormalCompletion(empty)

与显式 var 或函数声明不同,直接在全局对象上创建的属性会导致全局绑定,而这些绑定可能会被 let / const / class 声明遮盖。

2020-07-16 补充

如何在 <script></script> 标签中使用 import/export ?

<script type="module">
export const test = 'test'
</script>

见 winter 《重学前端》中 在script标签写export为什么会抛错? 一章。

2020-07-18 补充

今天看 《JavaScript 20 年》中文版 时突然意识到初入门时就知道但目前差点忘了的知识 —— HTML 网页都可能包含多个 <script> 元素。脚本之间通常共享同一个全局对象。由脚本创建的全局变量和函数,对所有后续脚本均可见。

<script>
  var a = 1;
</script>
<script>
  console.log(a); // 1
</script>

我都差点忘了这回事了。。。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant