ECMAScript仕様輪読会 #22
前回: ECMAScript仕様輪読会 #21
Scrapboxの招待リンク: https://scrapbox.io/projects/esspec/invitations/85b96c9fa718ce5185e307196ed8fb53
connpass: https://esspec.connpass.com/
Discord: https://discord.gg/59S3y6weQj
Twitter hashtag: #esspec
YouTube: https://youtu.be/gew7MMjku4w
https://jsconf.jp/2022/ 10/30 CFP締切
自己紹介 (近況報告)
syumai
Twitter: https://twitter.com/__syumai GitHub: https://github.com/syumai
GoとTSやってます
先々週末Go Con mini Sendaiと言うイベントで仙台に行きます
Jun Yasumura / harupiyo Jun Yasumura.icon
英語のcanonical(https://ejje.weblio.jp/content/canonical 正典の、教会法に基づく、規準的な、標準的な )が、どうしても音楽のカノン(輪唱するやつ)のイメージに引きずられてしまう→音楽のカノンも実は教会法に基づく規範の、という意味だった→納得感
tars0x9752 (たーず / naoki aoyama) tars0x9752.icon
噂の trpc でハローワールド
ついでにちょっとしたコントリビュートした
rspc でもハローワールド
rust 版の trpc 的なやつ
サーバーは Rust
クライアントは TS
rust なにもわからん
yebis0942yebis0942.icon
TypeScript入門しつつあります
Array.prototype.filterで値の型を絞り込めたと思ったら絞り込めてないとか
code:ts
array.filter(i => i.type === "hoge") // i.type === "hoge"の型だけ絞り込めると思ったら絞り込めてない
マイクの接触が怪しいかも
前回のあらすじ
canonical numeric stringの謎
code:js
const a = 1
a'-0' // expected: 1, actual: undefined
Integer-Indexed Exotic Objects は Typed Array についての仕様だった
code:js
const ua = new Uint8Array(2); // Typed Array
ua0 = 1;
ua0 // 1
ua'-0' = 2
ua'-0' // undefined
こちらは期待通りの挙動をしている
Testing and Comparison Operations
RequireObjectCoercible: ToObjectできるかどうか判定するやつ
IsArray, IsCallable, IsConstructor, IsExtensible, IsIntegralNumber, IsPropertyKey などなど
IsRegExp
今日の範囲
IsStringWellFormedUnicode
文字列をUTF-16のコードポイントシーケンスとして解釈して、well formed なUTF-16シーケンスになってるか判定する
well formed?
Well-formed: A Unicode code unit sequence that purports to be in a Unicode encoding form is called well-formed if and only if it does follow the specification of that Unicode encoding form
Unicode 仕様にしたがっていれば well formed っぽい?
SV がでてきた
たぶん String Value
生成規則中の文字列を String Value にする static semantics
どこで使われているのか
ModuleExportNameがIsStringWellFormedUnicodeでfalseであればSyntax Error
具体的にどういうコードだとそうなるのか
サロゲートペア
𩸽 とか
not well formed?
0xD800-0xDFFF は pairs の中でしか登場してはいけないらしい?
https://stackoverflow.com/questions/13689815/what-is-a-well-formed-utf-16-string
こういうやつかもyebis0942.icon
code:a.mjs
import { "\uD800" as a } from "lib" // unicode sequenceで不正なModuleExportNameを作る
code:result
$ node a.mjs
file:///tmp/a/a.mjs:3
import { "\uD800" as a } from "lib"
^^^^^^^^
SyntaxError: Invalid module export name: contains unpaired surrogate
SameValue
If Type(x) is different from Type(y)
ECMAScript language valueの型の同一性はどのように定義されているのか?
yebis0942.icon定義見つからず。nominal type的に同一性を見ているのだろうか。
IsStrictlyEqualとの違い: NaN, +0, -0の扱いが違う
SameValue: NaN == NaN, +0 == -0 (Number::sameValue)
IsStrictlyEqual: NaN != NaN, +0 != -0 (Number::equal)
試してみる
code:js
NaN == NaN // false
Object.is(NaN, NaN) // true (Object.isはSameValueを即呼んでいる)
IsLooselyEqualも型が同じならIsStrictlyEqualを呼んでいる
SameValue はどこで使われているか
めちゃめちゃ使われている
Object.is など
Object.isは引数をオブジェクトに変換しない(Objectのメソッドなのに)
SameValueZero
SameValueと同じ。ただし+0𝔽と-0𝔽を同一視する。
どこで使われているのか
Set, Mapのキーの比較
配列の長さ的なものの比較
実験してみる
code:js
s = new Set
s.add(-0); s.add(0) // -0と0は同一視される
s.size // 1
code:js
m = new Map()
m.set(0, "a"); m.set(-0, "b") // -0と0は同一視される
m.get(0) // b
SameValueNonNumber
すでに見たので略
IsLessThan
引数: x, y, LeftFirst (boolean)
返り値は以下のいずれか
normal completion record<Boolean | undefined>
throw completion
LeftFirst
xとyのどちらを先に評価するか
ToPrimitiveに副作用があるのでどっちを優先するか決める必要があるっぽい
getterを使えばxやyの値を参照した時点で副作用発生させることも可能そうyebis0942.icon
yebis0942.iconLeftFirstが指定されずに呼ばれてるケースありそう
Math.max, Math.min
追記:x < y だけじゃなくて x > y みたいなコードに対しても isLessThan が使われてるっぽくてそのときに leftFirst が指定されたりしてた
code:js
// <と>のどちらでも評価順が適切になっていることを確認する
{
const o = {};
for (const key of "a", "b") {
Object.defineProperty(o, key, {
get: () => {
console.log(evaluated: ${key});
return 0;
}
})
}
o.a < o.b; // evaluated: a, evaluated: b
o.b > o.a; // evaluated: b, evaluated: a (LeftFirstがなければ a -> bの順で評価されてしまう)
}
string 同士の場合は辞書順で比較っぽい
どっちも同じ文字列なら false
code:js
"abc" < "abcd"
// true
"abc" < "abc"
// false
"abc" < "abb"
// false
"abc" < "abd"
// true
Code pointとCode unitの違い
https://developer.mozilla.org/en-US/docs/Glossary/Code_unit
https://jsprimer.net/basic/string-unicode/
参考:
Unicode照合アルゴリズム - Wikipedia
http://www.unicode.org/reports/tr10/
言語によって文字の順序が違う例
スウェーデン語では z < ö
ドイツ語では ö < z
tars0x9752.iconなるほど~
isLessThan は Unicode 仕様書とは異なる(Unicode 仕様書はもっと複雑)
BigInt と String
String を BigInt に変換して比較
なお, String から BigInt への変換を失敗したら undefined
code:js
100000000000000000n <
"100000000000000001"
// true
"100000000000000000" <
100000000000000001n
// true
Number 同士
Number:lessThan
(無限大同士の比較もここ)
BigInt 同士
BigInt:lessThan
どちらかが NaN
undefined
BigInt と Number
Mathematical Value として比較
code:js
({}).toString()
// 'object Object'
({}) < 'object Object'
// false
({}) < 'object Object1'
// true
({}) < '[object Object'
// false
undefined < undefined // NaN
// false
undefined < 1
// false
undefined < -1
// false
undefined < "abc"
// false
undefined < Infinity
// false
null < 1
// true
null < -1
// false
null < null
// false
null < true
// true
null < "1"
// true
null < "-1"
// false
Number("")
// 0
null < ""
// false
const s = Symbol("a")
// undefined
s < "b"
// VM2539:1 Uncaught TypeError
function A() {}
// undefined
new A
// A {}
A.prototype.toString = () => "42";
// () => "42"
const a = new A();
// undefined
a.toString();
// '42'
a < 43
// true
a < 41
// false
code:js
"0101" < "100"
// true
"0101" < 100
// false
"0101" + "100"
// '0101100'
"0101" + 100
// '0101100'
lexicographical order
辞書式順序
https://ja.wikipedia.org/wiki/辞書式順序
canonically
標準的に
余談コーナー
IsLessThanはメソッド分割してほしかったyebis0942.icon
toString()は文字列以外を返してもOKなのか?
code:js
o = ({ toString() { return 42 } })
o < 50 // true
OKっぽい…
次回: IsLooselyEqual から