ECMAScript仕様輪読会 #27
前回: ECMAScript仕様輪読会 #26
Scrapboxの招待リンク: https://scrapbox.io/projects/esspec/invitations/85b96c9fa718ce5185e307196ed8fb53
connpass: https://esspec.connpass.com/
Discord: https://discord.gg/59S3y6weQj
Twitter hashtag: #esspec
便利ツール
esspec-memo: https://tars0x9752.github.io/esspec-memo/esspec.html
Scrapbox Codeblock Generator: https://vzvu3k6k.github.io/scrapbox-codeblock/
TC39 Terminology: https://github.com/tc39/how-we-work/blob/main/terminology.md
自己紹介 (近況報告)
syumai
Twitter: https://twitter.com/__syumai GitHub: https://github.com/syumai
年末年始、例のアレ🦠で体調を崩して寝込んでました
ドラム、脚が動くようになりいい感じになってきました
スラムダンクを箱買いして読んでます
来週Serverless系のイベントで登壇します
https://serverless-frontend.connpass.com/event/271894/
https://github.com/syumai/workers/ の話をする予定です
Jun Yasumura / harupiyo Jun Yasumura.icon
CSSの知識をアップデート中
tars0x9752 (たーず / naoki aoyama) tars0x9752.icon
自分も年末年始体調崩して寝込んでいた
スノーボードシーズンインした
動画制作入門している
yebis0942yebis0942.icon
2023/1/17 所用あって1時間ほど遅刻しそうです。すみません…
noyannoyan.icon
dotfiles作りに目覚めました
冪等で宣言的な管理をするために試行錯誤
https://zenn.dev/ryo_kawamata/articles/introduce-chezmoi
前回のあらすじ
ESMeta便利でしたね
Syntax-Directed Operationがどれにマッチするのか明確に分かるのが助かる
今回の範囲
Runtime Semantics: ClassDefinitionEvaluation のステップ実行 (8) の続きから
code:js
// class A と B
class A {
x = 1;
constructor() {
this.p = 1;
}
hello() {
return "hello";
}
}
class B extends A {
x = 2;
}
classEnv → env をもとに作られた declarative environment record
Declarative Environment Record
classEnv
code:javascript
TYPE = DeclarativeEnvironmentRecord {
"CreateImmutableBinding" -> clo<DeclarativeEnvironmentRecord.CreateImmutableBinding>
"CreateMutableBinding" -> clo<DeclarativeEnvironmentRecord.CreateMutableBinding>
"DeleteBinding" -> clo<DeclarativeEnvironmentRecord.DeleteBinding>
"GetBindingValue" -> clo<DeclarativeEnvironmentRecord.GetBindingValue>
"HasBinding" -> clo<DeclarativeEnvironmentRecord.HasBinding>
"HasSuperBinding" -> clo<DeclarativeEnvironmentRecord.HasSuperBinding>
"HasThisBinding" -> clo<DeclarativeEnvironmentRecord.HasThisBinding>
"InitializeBinding" -> clo<DeclarativeEnvironmentRecord.InitializeBinding>
"OuterEnv" -> #1380
"SetMutableBinding" -> clo<DeclarativeEnvironmentRecord.SetMutableBinding>
"SubMap" -> #1470
"WithBaseObject" -> clo<DeclarativeEnvironmentRecord.WithBaseObject>
}
submap
code:javascript
TYPE = SubMap {
"B" -> #1472
}
env
code:javascript
TYPE = GlobalEnvironmentRecord {
"CanDeclareGlobalFunction" -> clo<GlobalEnvironmentRecord.CanDeclareGlobalFunction>
"CanDeclareGlobalVar" -> clo<GlobalEnvironmentRecord.CanDeclareGlobalVar>
"CreateGlobalFunctionBinding" -> clo<GlobalEnvironmentRecord.CreateGlobalFunctionBinding>
"CreateGlobalVarBinding" -> clo<GlobalEnvironmentRecord.CreateGlobalVarBinding>
"CreateImmutableBinding" -> clo<GlobalEnvironmentRecord.CreateImmutableBinding>
"CreateMutableBinding" -> clo<GlobalEnvironmentRecord.CreateMutableBinding>
"DeclarativeRecord" -> #1378
"DeleteBinding" -> clo<GlobalEnvironmentRecord.DeleteBinding>
"GetBindingValue" -> clo<GlobalEnvironmentRecord.GetBindingValue>
"GetThisBinding" -> clo<GlobalEnvironmentRecord.GetThisBinding>
"GlobalThisValue" -> #1374
"HasBinding" -> clo<GlobalEnvironmentRecord.HasBinding>
"HasLexicalDeclaration" -> clo<GlobalEnvironmentRecord.HasLexicalDeclaration>
"HasRestrictedGlobalProperty" -> clo<GlobalEnvironmentRecord.HasRestrictedGlobalProperty>
"HasSuperBinding" -> clo<GlobalEnvironmentRecord.HasSuperBinding>
"HasThisBinding" -> clo<GlobalEnvironmentRecord.HasThisBinding>
"HasVarDeclaration" -> clo<GlobalEnvironmentRecord.HasVarDeclaration>
"InitializeBinding" -> clo<GlobalEnvironmentRecord.InitializeBinding>
"ObjectRecord" -> #1376
"OuterEnv" -> null
"SetMutableBinding" -> clo<GlobalEnvironmentRecord.SetMutableBinding>
"SubMap" -> #1379
"VarNames" -> #1381
"WithBaseObject" -> clo<GlobalEnvironmentRecord.WithBaseObject>
}
ダメそうな例
code:javascript
class A extends A {
}
new A();
/*
class A extends A {
^
ReferenceError: Cannot access 'A' before initialization
*/
自身のclass名をextends出来ないようにするために、classEnvのEnvironment Recordを作って使用している
code:js
TYPE = OrdinaryObject {
"DefineOwnProperty" -> clo<OrdinaryObject.DefineOwnProperty>
"Delete" -> clo<OrdinaryObject.Delete>
"Extensible" -> true
"Get" -> clo<OrdinaryObject.Get>
"GetOwnProperty" -> clo<OrdinaryObject.GetOwnProperty>
"GetPrototypeOf" -> clo<OrdinaryObject.GetPrototypeOf>
"HasProperty" -> clo<OrdinaryObject.HasProperty>
"IsExtensible" -> clo<OrdinaryObject.IsExtensible>
"OwnPropertyKeys" -> clo<OrdinaryObject.OwnPropertyKeys>
"PreventExtensions" -> clo<OrdinaryObject.PreventExtensions>
"PrivateElements" -> #1420
"Prototype" -> #INTRINSICS.Object.prototype
"Set" -> clo<OrdinaryObject.Set>
"SetPrototypeOf" -> clo<OrdinaryObject.SetPrototypeOf>
"SubMap" -> #1419
}
superclass
code:js
TYPE = ECMAScriptFunctionObject {
"Call" -> clo<ECMAScriptFunctionObject.Call>
"ClassFieldInitializerName" -> ~empty~
"Construct" -> clo<ECMAScriptFunctionObject.Construct>
"ConstructorKind" -> ~base~
"DefineOwnProperty" -> clo<OrdinaryObject.DefineOwnProperty>
"Delete" -> clo<OrdinaryObject.Delete>
"ECMAScriptCode" -> |FunctionBody|FF<0>
"Environment" -> #1408
"Extensible" -> true
"Fields" -> #1442
"FormalParameters" -> |UniqueFormalParameters|FF<0>
"Get" -> clo<OrdinaryObject.Get>
"GetOwnProperty" -> clo<OrdinaryObject.GetOwnProperty>
"GetPrototypeOf" -> clo<OrdinaryObject.GetPrototypeOf>
"HasProperty" -> clo<OrdinaryObject.HasProperty>
"HomeObject" -> #1421
"IsClassConstructor" -> true
"IsExtensible" -> clo<OrdinaryObject.IsExtensible>
"OwnPropertyKeys" -> clo<OrdinaryObject.OwnPropertyKeys>
"PreventExtensions" -> clo<OrdinaryObject.PreventExtensions>
"PrivateElements" -> #1426
"PrivateEnvironment" -> #1412
"PrivateMethods" -> #1440
"Prototype" -> #INTRINSICS.Function.prototype
"Realm" -> #REALM
"ScriptOrModule" -> #1386
"Set" -> clo<OrdinaryObject.Set>
"SetPrototypeOf" -> clo<OrdinaryObject.SetPrototypeOf>
"SourceText" -> "class A { x = 1 ; constructor ( ) { this . p = 1 ; } hello ( ) { return "hello" ; } }"
"Strict" -> true
"SubMap" -> #1425
"ThisMode" -> ~strict~
}
NewTargetの動作
code:js
class A {
constructor() {
console.log("A", new.target);
}
}
new A();
class B extends A {
constructor() {
super(); // superがないと例外が発生する
console.log("B", new.target);
}
}
new B();
function F() {
console.log("F", new.target);
}
new F();
/*
A class A
A class B extends A
B class B extends A
F Function: F
*/
14. If constructor is empty, then
ClassBodyが存在しない場合にはデフォルトのコンストラクタを定義するという処理
active function objectという用語の意味が分からずスキップ
RealmとかEnvironmentとかの用語らしい
次回はEnvironmentとかを読みましょう
15. Else,
ClassBodyが存在する場合の処理
Runtime Semantics: DefineMethod
MakeMethod
homeObject
どんなときにabrupt completionを起こすのか
code:js
function thrower() { throw "error" }
class A {
thrower()() {} // Step1 の Evaluation of ClassElementName で例外を起こす例
}
ClassElementNameにはComputedPropertyNameが使えるので、名前を決定するときに処理を実行できる
c. Perform MakeClassConstructor(F).
F.[[IsClassConstructor]] to trueをするだけ
d. Perform SetFunctionName(F, className).
Function F (コンストラクタ) のnameプロパティにclassNameをセットする
code:js
class A {}
const a = new A();
a.constuctor.name // => 'A'
[[InitialName]]とは?
SetFunctionNameの第3引数 (prefix) が使われるケース
code:js
obj = {
get v() { return "I'm a getter method." } // このときprefixはget
};
desc = Object.getOwnPropertyDescriptor(obj, "v");
console.log(desc.get.name); // "get v"
16. Perform MakeConstructor(F, false, proto).
Step 14に相当することをやっているのか?
IsConstructor と MakeClassConstructor
MakeClassConstructor(F)を実行してもIsConstructor(F)がtrueになるとは限らない
MakeClassConstructor(F): F.[[IsClassConstructor]] = trueを実行する
IsConstructor(F): Fが[[Construct]] internal methodを持っていればtrueを返す
今回のまとめと次回予告
クラス定義を読むのは大変だった
このまま読み続けるのはつらそうなので、クラス定義は一旦ここで終了
次回は気を取り直してExecutable Code and Execution Contextsから
Environment Recordsとかを読んでいく