ECMAScript仕様輪読会 #23
前回: ECMAScript仕様輪読会 #22
Scrapboxの招待リンク: https://scrapbox.io/projects/esspec/invitations/85b96c9fa718ce5185e307196ed8fb53
connpass: https://esspec.connpass.com/
Discord: https://discord.gg/59S3y6weQj
Twitter hashtag: #esspec
https://jsconf.jp/2022/ 10/30 CFP締切
自己紹介 (近況報告)
syumai
Twitter: https://twitter.com/__syumai GitHub: https://github.com/syumai
jsconf CFP出せませんでした
Jun Yasumura / harupiyo Jun Yasumura.icon
英語のcanonical(https://ejje.weblio.jp/content/canonical 正典の、教会法に基づく、規準的な、標準的な )が、どうしても音楽のカノン(輪唱するやつ)のイメージに引きずられてしまう→音楽のカノンも実は教会法に基づく規範の、という意味だった→納得感
tars0x9752 (たーず / naoki aoyama) tars0x9752.icon
https://github.com/tc39/proposal-is-usv-string
JSConf CFP だせず
result-monad というちょっとしたライブラリを作り始めた
yebis0942yebis0942.icon
JSConf LT CFPを出しました!
週末はAWS Lambda + API Gateway + Cloudfrontしてました
サーバーレスの雑APIをスロットリングしつつ適当にキャッシュさせたかった
「VPCってやつで送信元IPアドレスを制限できるのか?」→「Lambdaではできない」
未知の難しさがある
皆既月食を見る ~ 19:43
宇宙の神秘だったyebis0942.icon
休憩 ~21:05
部分食きれいだった
前回のあらすじ
IsStringWellFormedUnicode
これをJSの世界からも直接呼べる用にするプロポーザルがあった
https://github.com/tc39/proposal-is-usv-string
SameValue
SameValueZero
SamValue のなかで使われてるやつ
IsLessThan
ながいやつ
leftFirst: x < y だけじゃなくて x > y みたいなコードに対しても isLessThan が使われてるっぽくてそのときに leftFirst が使われていた
今回: IsLooselyEqual から
IsLooselyEqual
==で使われる「ゆるい比較」
normal completion (Boolean)またはthrow completionを返す
x と y の型が異なる時に使われる
x と y の型が一緒の時は IsStrictlyEqual のほうが使われる!
IsHTMLDDA は loosely equal の世界では null undefined と同じ扱い
code:==.js
null == undefined // true
undefined == null // true
// IsHTMLDDA
document.all == undefined // true
document.all == null // true
// Number vs String
1 == '1' // true
'1' == 1 // true
1 == 'a' // false => Number('a') が NaN のため false
// Boolean
'true' == true // false
1 == true // true
true == '1' // true (ToNumber(true) == ToNumber('1'))
true == ' 1 ' // true (stringに対するToNumberの処理時に、空白が除去されるので、1と1の比較になる)
true == ' 1.0 ' // true (同上)
true == ' 1e0 ' // true (同上)
false == '0' // true
// BigInt
true == 1n // true (true => 1 で 1 と 1n の Mathematical Value の比較になるので true)
false == 0n // true (false => 0 で 0 と 0n の Mathematical Value の比較になるので true)
// Object
true == {} // ToNumber(true) vs ToPrimitive({}) "object Object" => NaN => false
'object Object' == {} // true
string と number の場合は string を ToNumber して比較
Step 5, 6, 7, 8は変換後にIsLooselyEqualを呼んでいる
が、いずれの場合もType(x)とType(y)は等しいので、IsStrictlyEqualを呼んでいいのでは?
If x is either a String, a Number, a BigInt, or a Symbol
xがnull, undefined, Booleanのケースは除外されている
finiteの定義は?
Number typeの値から +∞𝔽と-∞𝔽(とおそらくNaN)を除外したもの
NaNは含まれるのか?
https://tc39.es/ecma262/#sec-ecmascript-language-types-number-type
code:js
Number.isFinite(NaN) // false
Infinity == 0n // false
Infinity == 1n // false
NaN == 0n // false
NaN == 1n // false
0 == 0n // true
1 == 1n // true
Infinity == Infinityは?
trueになる
どちらもNumberなのでIsStrictlyEqualに送られる
IsStrictEqualはNumber::equal(x, y)を呼ぶ
ここではInfinityに対する特別な処理はないので、単に同値と判定されてtrue
code:js
x + 1 === x - 1 // x === ±Infinityならtrue
NaN == NaNは?
falseになる
TypeScript 4.9ではval !== NaNのような比較に「Number.isNaN を使ってチェックしてください」と警告を出してくれる
https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-rc/#checks-for-equality-on-nan
IsStrictlyEqual
=== 用の abstract operation
SameValue アルゴリズムとは 符号付きゼロ と NaN の扱いについて異なる
IsStrictlyEqual では NaN は問答無用で false, +0 と -0 でも true
SamValue では NaN 同士は true, +0 と -0 は false
code:js
NaN === NaN
// false
+0 === -0
// true
Object.is(NaN, NaN)
// true
Object.is(+0, -0)
// false
MakeBasicObject
すべてのオブジェクトを作る際の共通ステップを抜き出した abstract operation
exotic も ordinaly もどちらもこれを使う
exotic object を作るときは、まず MakeBasicObject でベースとなるオブジェクトを作ってそこから internal methods を上書きしたりして exotic object を作る。また、これらの操作は ArrayCreate や BoundFunctionCreate などに隠蔽されている。
Get
オブジェクトの特定のプロパティの値を取得するのに使う
細かいですけど、Step1で? (ReturnIfAbrupt) を使う必要はない気がしますねyebis0942.icon
GetV
オブジェクトの特定のプロパティの値を取得するのに使う
オブジェクトではない値を受け取る可能性がある
疑問
O.[[Get]](P, V)の最後の引数はOではいけないのか?
OrdinaryGetのReceiverにobjectではなくprimitiveが与えられたら挙動は変わるのか?
PropertyDestructuringAssignmentEvaluation
code:js
const { constructor } = 1; // 1がToObjectされてNumberオブジェクトになり、constructorがアクセス可能になる
ちなみに
code:js
(1).constructor
この場合はGetVとは違う経路でToObjectされていた気がする…?
Numberのコンストラクタ関数: newを付けるかどうかで振る舞いが変わる
https://tc39.es/ecma262/#sec-number-constructor
creates and initializes a new Number object when called as a constructor.
performs a type conversion when called as a function rather than as a constructor.
code:js
typeof new Number(1) // 'object': Numberオブジェクトを作る
typeof Number(1) // 'number': Number型の値を返す
Set
オブジェクトの特定のプロパティに値をセットするのに使う
失敗時にTypeError例外を出すかどうかを引数によって制御できる
O.[[Set]](P, V, O)がfalseを返すのはどんな場合?
Ordinary objectの[[Set]]の動作を追ってみる
たとえばプロパティがWritableでない場合
例外を出すのはどんな場合?
Object.assign
https://tc39.es/ecma262/#sec-object.assign
code:js
const o = {};
Object.defineProperty(o, "p", { writable: false });
Object.assign(o, { q: 1 }); // ok
Object.assign(o, { p: 1 }); // throw
CreateDataProperty
オブジェクトにプロパティを生やす
プロパティの性質はobj.a = valueと同じ
プロパティがconfigurableでないかextensibleでない場合には失敗してfalseを返す
CreateMethodProperty
ordinary objectにプロパティを生やす
プロパティの属性はビルトインメソッドやクラス宣言構文で定義されたメソッドと同じ
ClassDefinitionEvaluationでしか使われていない
If it does exist, DefinePropertyOrThrow is guaranteed to complete normally.
これがguaranteedである根拠というのがよくわからないyebis0942.icon
Normally, the property will not already exist.
ここでwill使うんですね tars0x9752.icon
どういう気持ちのwillなのかよくわからない気持ちですyebis0942.icon
CreateDataPropertyOrThrow
CreateDataPropertyのラッパーになっている
falseが返されたらTypeError例外を出す
プロパティをセットする問題が起きようがない場合にはCreateDataProperty、そうでなければOrThrowを呼んでいるように思える
CreateNonEnumerableDataPropertyOrThrow
Errorのmessageのプロパティをセットするのに使われている
code:js
const obj = { message: 1 };
for (const key in obj) {
console.log(key); // message
}
class E {
constructor() {
this.message = "hello";
}
}
const e = new E();
for (const key in e) {
console.log(key); // message
}
const err = new Error("hoge");
err.message // 'hoge'
for (const key in err) {
console.log(key); // 何も出ない
}
このセクションのabstract operationが多すぎ問題
全部読んでも覚えていられないので、気になるものだけ読んでいく形でいきたい
名前とreferenceだけ確認していく