Closed18

「JavaScript 第7版」を読む(6章~7章:オブジェクトと配列)

suzuki-navisuzuki-navi

プロトタイプを使ったオブジェクトの生成

const obj = Object.create({x: "Hello"});

console.log(obj); // {}
console.log(obj.x); // Hello

console.log("x" in obj); // true
console.log(obj.hasOwnProperty("x")); // false
// 以下の2行は同じ
const obj = Object.create(Object.prototype);
const obj = {};
suzuki-navisuzuki-navi

オブジェクトのキーの識別には文字列か数字かの区別がないのか。

const obj = {
    "0": "Hello",
}

console.log(obj);      // { '0': 'Hello' }
console.log(obj[0]);   // Hello
console.log(obj["0"]); // Hello
const obj = {
    0: "Hello",
}

console.log(obj);      // { '0': 'Hello' }
console.log(obj[0]);   // Hello
console.log(obj["0"]); // Hello
const obj = {}
obj[0] = "Hello";

console.log(obj);      // { '0': 'Hello' }
console.log(obj[0]);   // Hello
console.log(obj["0"]); // Hello
suzuki-navisuzuki-navi

プロパティの列挙順序は、以下の3グループの順に、それぞれソートされる。

  • 0以上の整数(の文字列)
    • 小さい数字から順に
  • それ以外の文字列(負や小数点付きの数字のような文字列も含む)
    • オブジェクトに追加された順に
  • Symbol
    • オブジェクトに追加された順に

ただし、for/inループでの列挙順序は厳密な仕様がない。とはいえ、ほとんどの処理系ではこの列挙順序に従っている。

suzuki-navisuzuki-navi

Object.assign は列挙可能なプロパティを上書きコピーする。

const obj1 = {
    x: 1,
    y: 2,
}
const obj2 = {
    y: 20,
    z: 30,
}
console.log(Object.assign({w: "Hello", x: "World"}, obj1, obj2));
// { w: 'Hello', x: 1, y: 20, z: 30 }

console.log({...{w: "Hello", x: "World"}, ...obj1, ...obj2});
// { w: 'Hello', x: 1, y: 20, z: 30 }
suzuki-navisuzuki-navi

valueOfメソッドは数値型に変換するメソッド。toStringが文字列への変換であることに対応する。比較演算子で比較する際に呼び出される。

suzuki-navisuzuki-navi

こんな書き方ができる。

const keyName = "a";

const obj = {
    [keyName]: 1,
}

console.log(obj); // { a: 1 }

[]の中には変数名だけでなく、任意の式が書ける。

suzuki-navisuzuki-navi

アクセッサ(ゲッターとセッター)

const obj = {
    propField: 1,
    get prop() {
        return this.propField;
    },
    set prop(value) {
        this.propField = value;
    },
}

console.log(obj.prop); // 1
console.log(Object.keys(obj)); // [ 'propField', 'prop' ]
suzuki-navisuzuki-navi

JavaScriptのいわゆる配列はオブジェクトの特別の形式。

ES6で「型付き配列」が導入されたが。型付き配列は固定長なのに対して、いわゆる配列は可変長であり、疎な配列も可能。

suzuki-navisuzuki-navi

疎な配列

// 疎な配列
const arr = [1, , 2, ];

console.log(arr);        // [ 1, <1 empty item>, 2 ]
console.log(arr.length); // 3
// 疎な配列
const arr = [1, , 2, , ];

console.log(arr);        // [ 1, <1 empty item>, 2, <1 empty item> ]
console.log(arr.length); // 4
suzuki-navisuzuki-navi

Setを使うと重複を削除できる。

文字列も反復可能なので、次のように書ける。

console.log([...new Set("Hello World")]); // [ 'H', 'e', 'l', 'o', ' ', 'W', 'r', 'd' ]
suzuki-navisuzuki-navi

Array.from は配列のような見た目のオブジェクトから本当の配列を作れる。

console.log(Array.from({
    length: 3,
    0: 'a',
    2: 'c',
}));
// [ 'a', undefined, 'c' ]
suzuki-navisuzuki-navi

非負の整数のインデックスで要素を更新すればlengthも必要に応じて更新される。非負の整数であれば文字列でも許容される。

const arr = [1, 2, 3, 4, 5];

console.log(arr.length); // 5

arr[10] = "Hello";
console.log(arr); // [ 1, 2, 3, 4, 5, <5 empty items>, 'Hello' ]
console.log(arr.length); // 11

arr["11"] = "World";
console.log(arr); // [ 1, 2, 3, 4, 5, <5 empty items>, 'Hello', 'World' ]
console.log(arr.length); // 12

arr["-1"] = "minus";
console.log(arr); // [ 1, 2, 3, 4, 5, <5 empty items>, 'Hello', 'World', '-1': 'minus' ]
console.log(arr.length); // 12 のまま変わらない
suzuki-navisuzuki-navi

配列の高階関数のメソッド

Scalaに翻訳すると私にはわかりやすいので、表で対応をまとめる。

JavaScript Scalaで対応するもの
forEach foreach
map map
filter filter
find find
findIndex indexWhere
every forall
some exists
reduce reduceLeft, foldLeft
reduceRight reduceRight, foldRight
sort sorted, sortWith
flat flatten
flatMap flatMap
indexOf indexOf
lastIndexOf lastIndexOf

reduceは関数だけを引数として渡せば、ScalaのreduceLeft相当になる。2つ目の引数として初期値を渡せば、ScalaのfoldLeft相当になる。recudeRightも同様。

JavaScriptのsort関数はScalaと違い配列自体を書き換える。引数を渡さなければデフォルトのソート順、関数を引数として渡せばその関数を使ってソートされる。引数の関数のシグニチャはScalaとは異なる。

indexOf, lastIndexOf は要素の比較の際には == ではなく === が使われる。

※表の最後のほうは高階関数ではない

suzuki-navisuzuki-navi
に追加 を取得して削除
先頭 unshift shift
最後 push pop

pushunshiftは複数を同時に追加することができる。

const arr = [1, 2, 3];
arr.push("Hello", "World");
console.log(arr); // [ 1, 2, 3, 'Hello', 'World' ]
const arr = [1, 2, 3];
const arr2 = ["Hello", "World"];
arr.push(...arr2);
console.log(arr); // [ 1, 2, 3, 'Hello', 'World' ]

unshiftは直観と順番が逆かもしれない。

const arr = [1, 2, 3];
arr.unshift("Hello", "World");
console.log(arr); // [ 'Hello', 'World', 1, 2, 3 ]
suzuki-navisuzuki-navi

文字列はUTF-16コードの配列のようにふるまう。ただしイミュータブル。

suzuki-navisuzuki-navi

ソートに関して

const arr = [3, 2, 5, 1, 4];
arr.sort();
console.log(arr); // [1, 2, 3, 4, 5]
const arr = [3, 2, 5, 1, 4];
arr.sort((a, b) => b - a);
console.log(arr); // [ 5, 4, 3, 2, 1 ]
このスクラップは2023/07/15にクローズされました