Sibainu Relax Room

柴犬と過ごす

JavaScript JSON.stringify()について

俺も11歳になっているが、今年も頑張るぞという顔している柴犬です。

概要

クライアントの PC、Android から WEBサーバーと通信するときにJSON文字列を使っています。

そのときJSON文字列を作成する上で JSON.stringify メソッドを使い Object オブジェクトの変換を行います。

JSON.stringify と Mapオブジェクトの関係について私の思い違いで、かなりハマりましたので記録します。

Mapオブジェクトは、連想配列(ハッシュ)を管理するためのオブジェクトとありましたので、下の例でいうと

JSON.stringify(testMap) で {"pro1":"aaaaa", "pro2":"bbbbb", "pro3":"ccccc"} が返される。

という思い込み(Pythonの連想配列の表現と誤解)があり、これ前提で考えていたので全く前に進めませんでした。

実際何が返されているのか確かめてみると

実行してみます。

となり、空のオブジェクトを告げる文字列が返されています。

独学するものにとって貴重な本です。他の本なら省略されているところを丁寧に説明しています。

私の基本書です。

JSON.stringify を調べる

JSON.stringify() は値をそれを表す JSON 表記(文字列)に変換したものを返します。

次のMDNのホームページを見てみると

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

次のようなことが書いてあります。

JSON.stringify() メソッドは、ある JavaScript のオブジェクトや値を JSON 文字列に変換します。

とあり,「ある JavaScript のオブジェクトや値」ですので、すべてではなく条件付きのようです。

変換できるもの

Boolean、Number、String および BigInt の各オブジェクトは、文字列化の際に慣習的な変換セマンティクスに従い、対応するプリミティブ値に変換されます。

有効な JSON 値ではないものは、オブジェクトの中の場合は省略されたり、配列の中の場合は null に変換されたりします。

Infinity および NaN の数値は、null の値と同様に、すべて null と見なされます。

配列は配列として文字列化されます。

その他のオブジェクト

シンボル (Symbol) がキーとなっているプロパティはすべて無視されます。

値が toJSON() メソッドを持っている場合は、toJSON() メソッドが返す値が文字列化します。
  ・オブジェクトがプロパティの値の場合は、プロパティ名
  ・配列の要素の場合は、配列の添字を表す文字列 など

列挙可能なプロパティのみが文字列化されます。Map、Set、WeakMap、WeakSet などは “{}” に変換されます。

使用例

使用例1

実行結果1

使用例2

実行結果2

copy

console.log("1:   " + JSON.stringify({})); 

console.log("2:   " + JSON.stringify(true)); 

console.log("3:   " + JSON.stringify("test"));

console.log("4:   " + JSON.stringify([1, "true", true]));

console.log("5:   " + JSON.stringify([NaN, null, Infinity]));

console.log("6:   " + JSON.stringify({ a: 8 }));

console.log("7:   " + JSON.stringify(new Date(2024, 1, 10, 12, 3, 10)));

console.log("8:   " + JSON.stringify({ a: 3, b: 12 }));

console.log("9:   " + JSON.stringify([new Number(10), 
                                      new String("true"), 
                                      new Boolean(true)]));

let x = ["test", "nothing"];
x["wow"] = "bauuuu";
console.log("10:   " + JSON.stringify(x));

console.log("11:   " + JSON.stringify({ x: [15, undefined, 
                                            function () {}, Symbol("")] }));

console.log("12:   " + JSON.stringify([
  new Set([11]),
  new Map([[21, 32]]),
  new WeakSet([{ x: 4 }]),
  new WeakMap([[{ y: 7 }, 8]]),
]));

console.log("13:   " + JSON.stringify([new Int8Array([1]), 
                                       new Int16Array([1]), 
                                       new Int32Array([1])]));

console.log("14:   " + JSON.stringify([
  new Uint8Array([1]),
  new Uint8ClampedArray([1]),
  new Uint16Array([1]),
  new Uint32Array([1]),
]));

console.log("15:   " + JSON.stringify([new Float32Array([1]), 
                                       new Float64Array([1])]));

console.log("16:   " + JSON.stringify({
  a: 15,
  b: 26,
  toJSON() {
    return this.a + this.b;
  },
}));

console.log("17:   " + JSON.stringify({a: undefined, 
                                       b: Object, 
                                       c: Symbol("") }));

console.log("18:   " + JSON.stringify({ [Symbol("test")]: "test" }));

console.log("19:   " + JSON.stringify({ [Symbol.for("test")]: "test" }, 
                                        [Symbol.for("test")]));

console.log("20:   " + JSON.stringify({ [Symbol.for("test")]: "test" }, 
  (k, v) => {
    if (typeof k === "symbol") {
      return "a symbol";
  }
}));

console.log("21:   " + JSON.stringify(
  Object.create(null, {
    a: { value: "a", enumerable: false },
    b: { value: "b", enumerable: true },
  }),
));

解決策

列挙可能なプロパティのみが文字列化されますので、MapオブジェクトがObjectオブジェクトに変換できないか調べてみます。

Object.fromEntries() メソッドがありました。

次のMDNのホームページを見てみると

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries

Object.fromEntries() メソッドは、キーと値の組み合わせのリストをオブジェクトに変換します。
とあります。

これを使って実行してみます。

実行結果

問題なく返されています。

Objectオブジェクトについて

次のObjectオブジェクトで Object.fromEntries を使わずにいろいろ実行してみます。

実行の結果

意図した結果となっています。

配列の表現は、言語によって違うので基本書を最初から読み直して取り掛からないといけないということが身に沁みました。

今回はこれまでとします。