🚀

【ts/js】文字列(プリミティブ)とStringオブジェクト

2022/12/22に公開

はじめに

TypeScriptのStringとstringの違いや、それらにまつわる不思議な挙動について調べてみたのでそれのまとめ的な内容になっているはずです。よろしくお願いします。

文字列なのかオブジェクトなのか

stringは文字列を扱うデータ型、Stringはオブジェクトになっていて、文字の並びを表したり操作するために使用される。

そこで、以下のコードを見てほしい。(動作環境はrepl.it)

const printStr = "I want to eat cookie".replace("cookie", "ra-men")
console.log(printStr)

そして以下が結果である。

I want to eat ra-men

プリミティブな値のはずがインスタンスメソッドを使えてしまっている。
ここを深ぼっていきたい。

以下のコードを実行してみる。

const printStr : String = new String("abcd");
console.log(printStr);
console.log(typeof(printStr));
console.log(printStr.valueOf())

結果

[String: 'abcd']
object
abcd

このように出てきました。内部に文字列持っているように見えます。(持ってなきゃどこにデータが言ったんだって話ですが。)ないぶに持っているであろうデータはValueOf()で取り出すことができます。
このように、プリミティブな値(ここでいう文字列)を包み込んだオブジェクトをラッパーオブジェクトと呼ぶそうです。そこでこのコードを思い出してください。

const printStr = "I want to eat cookie".replace("cookie", "ra-men")
console.log(printStr)

このコードでは何が起きているかというと、JavaScriptにはプリミティブの値から自動でラッパーオブジェクトに変換する機能があります。どんな時に自動変換が働くかというと、対応するラッパーオブジェクトのインスタンスメソッドにアクセスしようとしたとき自動変換が働きます。具体例は上のコードを見てください。

最後に

基本的にはプリミティブ型のほうを使うことを公式が推奨しています。(無理にラッパーオブジェクトのほうを使う人もほとんどいなさそうだが...)
理由は以下の3点で

  • 必要に応じて、プリミティブ型の文字列は自動的にラッパーオブジェクトに変換されるため
  • new String("string")のようにラッパーオブジェクトのインスタンスを扱う利点がないため
  • ラッパーオブジェクトをtypeof演算子で評価した結果が、プリミティブ型ではなく"object"となり混乱を生むため

と公式に書かれています。ラッパーオブジェクトは意識しなくてもいいよって旨の話だと思うんですが、なぜ言語の内部実装っぽいものが見えるのかが非常に不思議です。

おまけ

valueOf()という関数の命名、動詞でもなければどんな操作をするのか正直関数名だけでは想像がつかないのになぜこんな命名なのでしょうか?
これ、「string value of」のように厳密に文法を守っているわけではないですが一つの英文のようになっています。「~の文字列の値」と読めて、stringの部分が変数名に置き換わる感じです。
似たような命名でindexOf()とかもそうで、こっちのほうが英文っぽいです。index of "ramen"でラーメンのインデックスという意味にとれます。

参考文献

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String
https://jsprimer.net/basic/wrapper-object/

Discussion