文字列は文字列リテラルからプリミティブとして、または String() コンストラクターを使用してオブジェクトとして生成することができます。
js
const string1 = "文字列プリミティブ";
const string2 = 'これも文字列プリミティブ';
const string3 = `別な文字列プリミティブ`;
js
const string4 = new String("文字列オブジェクト");
文字列プリミティブと文字列オブジェクトは多くの動作を共有していますが、その他に重要な相違点と注意点があります。
下記の「文字列プリミティブと String オブジェクト」を参照してください。
文字列リテラルは単一引用符または二重引用符を使用して指定することができ、どちらでも同様に扱われますが、逆引用符文字 ` を使用することもできます。最後の形はテンプレートリテラルを指定しています。この形式では式を補完することができます。文字列リテラルの構文については、字句文法を参照してください。
文字列内の個々の文字へのアクセス方法には、2 通りの方法があります。そのひとつは charAt() メソッドです。
js
"ねこ".charAt(1); // "こ" が返される
他にも、文字列を配列風のオブジェクトとして扱い、個々の文字を数値インデックスに対応させる方法もあります。
ブラケット記法を使用した文字アクセスでは、これらのプロパティに値を設定したり削除したりすることはできません。関連するプロパティを書き込んだり設定したりすることもできません。(より詳細な情報は Object.defineProperty() を参照してください。)
文字列を比較するには小なり / 大なり演算子を用います。
js
const a = "a";
const b = "b";
if (a < b) {
// true
console.log(`${a} は ${b} より小さい`);
} else if (a > b) {
console.log(`${a} は ${b} より大きい`);
} else {
console.log(`${a} と ${b} は等しい`);
}
なお、すべての比較演算子は、=== および == を含め、文字列を大文字小文字を区別して比較します。文字列の大文字小文字を区別せずに比較する一般的な方法は、両方の文字列を同じ種類(大文字または小文字)に変換してから比較することです。
js
function areEqualCaseInsensitive(str1, str2) {
return str1.toUpperCase() === str2.toUpperCase();
}
toUpperCase() と toLowerCase() のどちらで変換するかはほとんど自由ですが、ラテン文字以外に広げると、どちらが完全に堅牢なとは言えません。例えば、ドイツ語の小文字 ß と ss は toUpperCase() によってどちらも SS に変換されますが、トルコ語の文字 ı は toLocaleLowerCase("tr") を使用しない限り、 toLowerCase() によって I と等しくない文字として誤って報告されてしまいます。
js
const areEqualInUpperCase = (str1, str2) =>
str1.toUpperCase() === str2.toUpperCase();
const areEqualInLowerCase = (str1, str2) =>
str1.toLowerCase() === str2.toLowerCase();
areEqualInUpperCase("ß", "ss"); // true; should be false
areEqualInLowerCase("ı", "I"); // false; should be true
ロケールを意識して大文字と小文字を区別せずに比較するための堅牢な解決策は、Intl.Collator API を使用するか、文字列の localeCompare() メソッド(インターフェイスは同じです)を sensitivity オプションで "accent" または "base" に設定します。
js
const areEqual = (str1, str2, locale = "en-US") =>
str1.localeCompare(str2, locale, { sensitivity: "accent" }) === 0;
areEqual("ß", "ss", "de"); // false
areEqual("ı", "I", "tr"); // true
localeCompare() メソッドは strcmp() と同様の方法で文字列を比較することができます。ロケールを意識した方法で文字列を並べ替えることができます。
JavaScript では、 String オブジェクトとプリミティブ文字列は区別されることに注意してください。(Boolean や Number にも同じことが言えます。)
文字列リテラル(二重引用符または単一引用符で示されます)、および String 関数をコンストラクター以外の場面で(すなわち new キーワードを使わずに)呼び出した場合はプリミティブの文字列になります。
文字列プリミティブに対してメソッドを呼び出したり、プロパティを参照したりするコンテキストでは、JavaScript は自動的に文字列プリミティブをラップし、ラッパーオブジェクトに対してメソッドを呼び出したり、プロパティを参照したりします。
js
const strPrim = "foo"; // リテラルは文字列プリミティブ
const strPrim2 = String(1); // 文字列プリミティブ "1" に変換
const strPrim3 = String(true); // 文字列プリミティブ "true" に変換
const strObj = new String(strPrim); // new を付けて String を呼び出すと文字列ラッパーオブジェクトを返す
console.log(typeof strPrim); // "string"
console.log(typeof strPrim2); // "string"
console.log(typeof strPrim3); // "string"
console.log(typeof strObj); // "object"
警告:
String をコンストラクターとして使用することはほとんどないでしょう。
プリミティブの文字列と String オブジェクトは eval() を使用すると異なる結果となります。 eval に渡されたプリミティブは、ソースコードとして扱われます。 String オブジェクトは他のオブジェクトと同様に、オブジェクトとしてそのままの文字列を返します。
js
const s1 = "2 + 2"; // 文字列プリミティブを生成
const s2 = new String("2 + 2"); // String オブジェクトを生成
console.log(eval(s1)); // 数値の 4 を返す
console.log(eval(s2)); // 文字列の "2 + 2" を返す
こういった理由から、プリミティブの文字列を期待して実装されたコードは String オブジェクトでうまく動作しないことがあります。しかし、一般的にはこれらの違いを考慮しなければならないことはあまりありません。
なお、String オブジェクトは valueOf() メソッドを用いることで、プリミティブの文字列に変換することができます。
js
console.log(eval(s2.valueOf())); // 数値の 4 を返す
文字列を期待する組み込み操作の多くは、最初に引数を文字列に変換します(これが String オブジェクトが文字列プリミティブと同じように動作する主な理由です)。処理は以下のように要約できます。
JavaScript でほぼ同じ効果を得る方法はいくつかあります。
- テンプレートリテラル:
`${x}` は埋め込まれた式に対して、上記で説明した文字列変換と同じ手順を踏みます。
String() 関数: String(x) は x を変換するのに同じアルゴリズムを使用しますが、シンボルでも TypeError が発生せず、"Symbol(description)" の形で description にそのシンボルの説明が入ったものを返します。
+ 演算子: "" + x はオペランドを文字列ではなくプリミティブに変換します。一部のオブジェクトでは、通常の文字列変換とは完全に異なる動作をします。詳しくはリファレンスページを参照してください。
用途によっては `${x}` (組み込みの動作を模倣するため)または String(x)(エラーを発生させずにシンボル値を処理するため)を使用したいかもしれませんが、 "" + x は使用しないでください。
文字列は基本的に UTF-16 コード単位の並びとして表します。UTF-16 エンコーダーでは、すべてのコード単位は正確に 16 ビット長です。つまり、単一の UTF-16 コード単位として表現可能な文字は、最大で 216 個、つまり 65536 通りあります。この文字集合は基本多言語面 (BMP) と呼ばれ、ラテン語、ギリシャ語、キリル文字のような最も一般的な文字や多くの東アジアの文字を含みます。各コード単位は u の文字列の後にちょうど 4 つの 16 進数を続けて書くことができます。
しかし、Unicode の文字集合全体は 65536 よりはるかにずっと大きいのです。追加の文字は UTF-16 でサロゲートペアとして格納されます。これは単一の文字を表す 16 ビットのコード単位のペアです。曖昧さを避けるために、ペアの 2 つの部分は 0xD800 と 0xDFFF の間でなければならず、これらのコード単位は単一のコード単位の文字をエンコードするためには使用しません。(より正確に言えば、上位サロゲート(上位サロゲートコード単位とも呼ばれる)は、0xD800から0xDBFF(両端値を含む)までの値を持ち、下位サロゲート(下位サロゲートコード単位とも呼ばれる)は、0xDC00 から 0xDFFF(両端値を含む)までの値を持ちます。)各 Unicode コードポイントは文字列の中で \u{xxxxxx} と書くことができ、ここで xxxxxx は 1-6 桁の 16 進数を表します。
「孤立サロゲート」とは、下記の記述のいずれかを満たす 16 ビットのコード単位です。
0xD800 から 0xDBFF までの範囲(つまり上位サロゲート)にあるものの、文字列の最後のコード単位であるか、次のコード単位が下位サロゲートではないもの。
0xDC00 から 0xDFFF までの範囲(つまり下位サロゲート)にあるものの、文字列の最初のコード単位であるか、前のコード単位が上位サロゲートではないもの。
孤立サロゲートは Unicode 文字を表しません。すべて UTF-16 コード単位に基づいて動作するため、ほとんどの JavaScript 組み込みメソッドは正しく扱いますが、他のシステムとやりとりするとき、孤立サロゲートはしばしば有効な値ではありません。例えば、encodeURI() は孤立サロゲートがあると URIError が発生します。これは URI エンコーディングが UTF-8 エンコーディングを使用しており、孤立サロゲートに対するエンコーディングを持たないためです。孤立サロゲートを格納しない文字列は well-formed 文字列と呼ばれ、UTF-16 を扱わない関数(encodeURI() や TextEncoder など)で使用しても安全です。isWellFormed() メソッドで文字列が整形されているか調べたり、toWellFormed() メソッドで孤立サロゲートをサニタイズすることができます。
Unicode 文字の上に、書記素クラスターと呼ばれる 1 つの視覚単位として扱われるべき Unicode 文字並びがあります。最も一般的なケースは絵文字で、様々なバリエーションがある絵文字の多くは、実際には複数の絵文字で形成されており、たいていの場合、<ZWJ> (U+200D) 文字で結合されています。
どのレベルの文字を反復処理するのかに注意する必要があります。例えば、split("") は UTF-16 コード単位で分割し、サロゲートペアを区切ります。文字列インデックスも各 UTF-16 コード単位のインデックスを参照します。他にも、[Symbol.iterator]() はUnicode コードポイントで反復処理します。書記素クラスターを反復処理するには独自のコードが必要です。
js
"😄".split(""); // ['\ud83d', '\ude04']; 孤立サロゲートを 2 つに分割
// "Backhand Index Pointing Right: Dark Skin Tone"
[..."👉🏿"]; // ['👉', '🏿']
// 基本的な "Backhand Index Pointing Right" の絵文字と
// "Dark skin tone" の絵文字に分割
// "Family: Man, Boy"
[..."👨👦"]; // [ '👨', '', '👦' ]
// "Man" と "Boy" の絵文字を ZWJ で結合
// アメリカの国旗
[..."🇺🇳"]; // [ '🇺', '🇳' ]
// 2 つの "region indicator" 文字である "U" と "N"
// すべての国旗の絵文字は、2 文字の地域識別文字を結合することで構成されている
String()
-
String オブジェクトを生成します。関数として呼び出された場合、String 型のプリミティブ値を返します。
以下のプロパティは String.prototype で定義されており、すべての String インスタンスで共有されます。
String.prototype.constructor
-
インスタンスオブジェクトを作成したコンストラクター関数。文字列インスタンスの場合、初期値は String コンストラクターです。
以下のプロパティはそれぞれの String インスタンスに固有のプロパティです。
length
-
文字列の length を反映します。読み取り専用です。
String() 関数は、値の toString() メソッドを呼び出すよりも、値を文字列に変換する信頼性の高い方法です。前者は null や undefined に対して使用しても動作するからです。例を示します。
js
// null や undefined のプロパティにアクセスすることはできない
const nullVar = null;
nullVar.toString(); // TypeError: Cannot read properties of null
String(nullVar); // "null"
const undefinedVar = undefined;
undefinedVar.toString(); // TypeError: Cannot read properties of undefined
String(undefinedVar); // "undefined"