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 —— 函数对象 #65

Open
lizhongzhen11 opened this issue Jan 9, 2020 · 0 comments
Open

重学js —— 函数对象 #65

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

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Jan 9, 2020

函数对象

ECMAScript函数对象封装了在词汇环境中关闭的参数化ECMAScript代码,并支持对该代码的动态评估。ECMAScript 函数对象 是普通对像,和其他普通对象一样有相同的内置插槽和内部方法。ECMAScript 函数对象 代码可能是 严格模式 也可能是 非严格模式

如果ECMAScript 函数对象 的代码是 严格模式,那么该函数称为 strict function。如果是 非严格模式,该函数称为 non-strict function

以下列出函数对象拥有的额外内置插槽

内置插槽 类型 描述
[[Environment]] 词法环境 函数关闭的词法环境。当计算函数代码时用作外部环境
[[FormalParameters]] Parse Node 定义函数形式参数列表的源文本的根解析节点。
[[ECMAScriptCode]] Parse Node 定义函数体的源文本的根解析节点。
[[ConstructorKind]] base 或 derived 函数是否源自 class 构造器
[[Realm]] 领域记录 用于函数创建以及提供计算该函数使用的所有内在对象的领域
[[ScriptOrModule]] Script RecordModule Record 创建函数的脚本或模块。
[[ThisMode]] lexical / strict / global 定义如何在函数的形参和代码体中解释 this 引用。lexical 这里指 this,代表词法包围函数的 this 值。strict 指使用的 this 值和函数调用时提供的一致。global 指将 undefinedthis 值解释为对 全局对象 的引用。
[[Strict]] Boolean 如果它是个 strict function,值为 true;如果是个 non-strict function,值为 false
[[HomeObject]] Object 如果函数使用 super,则该对象的 [[GetPrototypeOf]] 提供了 super 属性开始查找的对象。
[[SourceText]] String 定义该函数的 源文本
[[IsClassConstructor]] Boolean 该函数是不是 class 构造器。(如果值为 true,调用该函数的 [[Call]] 会立即抛出类型错误!)

所有的ECMAScript函数对象都有一个叫做 [[Call]] 的内部方法。此外如果有 [[Construct]] 内部方法的ECMAScript函数也是构造器!

[[Call]] ( thisArgument, argumentsList )

假设函数对象 F

argumentsList 是一个由ECMAScript语言值组成的 List和日常开发中接触到的arguments很像。

  1. 断言:F函数对象
  2. 如果 F.[[IsClassConstructor]]true,抛类型错误
  3. 定义 callerContext运行时上下文
  4. 定义 calleeContextPrepareForOrdinaryCall ( F, undefined ) 结果
  5. 断言:calleeContext 是当前的 运行时上下文
  6. 执行 OrdinaryCallBindThis(F, calleeContext, thisArgument)
  7. 定义 resultOrdinaryCallEvaluateBody(F, argumentsList) 结果
  8. 执行上下文栈 中移除 calleeContext 并且恢复 callerContext 作为 运行时上下文
  9. 如果 result.[[Type]]return,返回 NormalCompletion(result.[[Value]]) 结果
  10. 执行 ReturnIfAbrupt(result)
  11. 返回 NormalCompletion(undefined) 结果

注意:在第8步中,当 calleeContext执行上下文栈 中移除时,如果它被挂起并保留以供以后由可访问的生成器对象恢复,则不能将其销毁。

OrdinaryCallBindThis ( F, calleeContext, thisArgument ) —— 函数绑定this

  1. 定义 thisModeF.[[ThisMode]]
  2. 如果 thisModelexical,返回 NormalCompletion(undefined) 结果 (即 Completion{ [[Type]]: normal, [[Value]]: undefined, [[Target]]: empty }
  3. 定义 calleeRealmF.[[Realm]]
  4. 定义 localEnvcalleeContext 的词法环境
  5. 如果 thisModestrict,定义 thisValuethisArgument
  6. 否则,
    1. 如果 thisArgumentundefinednull
      1. 定义 globalEnvcalleeRealm.[[GlobalEnv]]
      2. 定义 globalEnvRecglobalEnv环境记录
      3. 断言:globalEnvRec 是全局 环境记录
      4. 定义 thisValueglobalEnvRec.[[GlobalThisValue]]
    2. 否则,
      1. 定义 thisValue! ToObject(thisArgument) 结果
      2. 注意:ToObject 使用 calleeRealm 生成包装器对象
  7. 定义 envReclocalEnv环境记录
  8. 断言:envRec函数环境记录
  9. 断言:下一步永远不会返回一个 abrupt completion 因为 envRec.[[ThisBindingStatus]] 未初始化!
  10. 返回 envRec.BindThisValue(thisValue) 结果

省去

[[Construct]] ( argumentsList, newTarget )

假设函数对象 FargumentsList 可能是一个空 List

  1. 断言:F 是ECMAScript 函数对象
  2. 断言:newTarget 是对象
  3. 定义 callerContext运行时上下文
  4. 定义 kindF.[[ConstructorKind]]
  5. 如果 kindbase
    1. 定义 thisArgument? OrdinaryCreateFromConstructor(newTarget, "%Object.prototype%") 结果
  6. 定义 calleeContextPrepareForOrdinaryCall(F, newTarget)结果
  7. 断言:calleeContext 是当前的 运行时上下文
  8. 如果 kindbase,执行 OrdinaryCallBindThis(F, calleeContext, thisArgument)
  9. 定义 constructorEnvcalleeContext 的词法环境
  10. 定义 envRecconstructorEnv环境记录
  11. 定义 resultOrdinaryCallEvaluateBody(F, argumentsList) 结果
  12. 从 c 中移除 calleeContext 并且重新存储 callerContext 作为 运行时上下文
  13. 如果 result.[[Type]]return
    1. 如果 result.[[Value]] 是对象,返回 NormalCompletion(result.[[Value]]) 结果
    2. 如果 kindbase,返回 NormalCompletion(thisArgument) 结果
    3. 如果 result.[[Value]] 不是 undefined,抛出类型错误
  14. 否则,执行 ReturnIfAbrupt(result)
  15. 返回 ? envRec.GetThisBinding() 结果

OrdinaryFunctionCreate ( functionPrototype, ParameterList, Body, thisMode, Scope ) —— 普通函数创建过程

  • ParameterList 是一个指定的 解析节点 参数列表
  • body 是一个 正文解析节点
  • thisModelexical-this 或者 non-lexical-this
  • Scope 指定词法环境
  1. 断言:functionPrototype 是对象
  2. 定义 F 为新创建的ECMAScript 函数对象,拥有规范中列出的 内置插槽
  3. F 的基本内部方法设置为规范中中指定的 默认普通对象定义
  4. 设置 F.[[Call]] 为规范中定义的 [[Call]] ( thisArgument, argumentsList )
  5. 设置 F.[[Prototype]]functionPrototype
  6. 设置 F.[[Extensible]]true
  7. 设置 F.[[FormalParameters]]ParameterList
  8. 设置 F.[[ECMAScriptCode]]Body
  9. 如果源文本和 Body 匹配且是 严格模式代码,定义 Stricttrue;否则设置 Strictfalse
  10. 设置 F.[[Strict]]Strict
  11. 如果 thisModelexical-this,设置 F.[[ThisMode]]lexical
  12. 否则如果 Stricttrue,设置 F.[[ThisMode]]strict
  13. 否则,设置 F.[[ThisMode]]global
  14. 设置 F.[[IsClassConstructor]]false
  15. 设置 F.[[Environment]]Scope
  16. 设置 F.[[ScriptOrModule]]GetActiveScriptOrModule ( ) 结果
  17. 设置 F.[[Realm]]当前领域记录
  18. 定义 LenParameterList 的预期参数数量
  19. 执行 ! SetFunctionLength(F, len)
  20. 返回 F

AddRestrictedFunctionProperties ( F, realm )

给函数对象添加 callerarguments 属性。

SetFunctionName ( F, name [ , prefix ] )

  • F 为函数
  • nameSymbolString
  • prefixString,可选
  1. 断言:F 是个可扩展对象且没有 "name" 属性,
  2. 断言:nameSymbolString 类型
  3. 断言:如果 prefix 存在,则是 String 类型
  4. 如果 nameSymbol 类型,
    1. 定义 descriptionname[[Description]]
    2. 如果 cundefined,设置 name 为空字符串
    3. 否则,设置 name 为由 "["description 以及 "]" 连接成的 字符串
  5. 如果 prefix 存在,
    1. 设置 name 为由 prefixunicode编码 0x0020对应的SPACE(空格) 以及 name 原有值连接成的字符串
  6. 返回 ! DefinePropertyOrThrow(F, "name", PropertyDescriptor { [[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }) 结果

SetFunctionLength ( F, length )

  1. 断言:F 是可扩展的对象且没有 "length" 属性
  2. 断言:lengthNumber
  3. 断言:! IsNonNegativeInteger(length)truelength >= 0 且是整数)
  4. 返回 ! DefinePropertyOrThrow(F, "length", PropertyDescriptor { [[Value]]: length, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true })

FunctionDeclarationInstantiation ( func, argumentsList )

注意:为了计算ECMAScript函数而建立的 执行上下文 中,一个新的 函数环境记录 被创建,在该环境记录中实例化每个形式参数的绑定。函数体内的每个声明也被实例化。如果函数的形式参数不包含默认初始值,函数体声明也会在该环境记录中作为参数被实例化。如果参数初始化时存在默认值,那么会为函数体声明创建第二条环境记录。形式参数和函数初始化为 FunctionDeclarationInstantiation 一部分。计算函数体期间初始化所有其它绑定。

B.3.3 提供了该算法的扩展,必须向后兼容 只实现了ECMAScript 2015之前的 ECMAScript版本 的 浏览器。

参数初始化程序可能包含 直接的eval 表达式。这些evals的顶级声明仅在eval代码里可见。14.1.19 中描述了为此类声明创建的环境。

太长了,具体看规范吧。

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