【JavaScript】replace関数の使い方

はじめに

 JavaScriptにおけるreplace関数は、単純な文字列置き換えの他、replacer用のfunctionを指定することで、柔軟な動作を実現することができます。

 今回は、replace関数を使ってプレースホルダの置換処理を書いてみます。

プレースホルダとは

 JavaScriptのテンプレート文字列や、シェルにおける${var}など、変数の中身を展開(置換)することのできる文字列をプレースホルダと呼びます。

 今回は、任意のデータを文字列上に展開できるようなプログラムを書いてみましょう。

やりたいこと

 ユーザーが入力した文字列に変数を展開する。

設計

 大まかなデータと方式の設計を行いましょう。

変数はJSONとしてMapで持つ

let variables = {
  "name": "John",
  "age": 20
}

プレースホルダ文字列は、「{{key}}」とする

 よくあるやつです。

let placeHolderString = "I'm {{name}}. {{age}} years old.";

実装

 何も考えずにやるなら、以下のようなコードが考えられます。

let variables = {
  "name": "John",
  "age": 20
}
let placeHolderString = "I'm {{name}}. {{age}} years old.";
let replaced = Object.keys(variables).reduce((acc, key)=>acc.replace("{{" + key + "}}", variables[key]), placeHolderString);
console.log(replaced);    // -> I'm John. 20 years old.

 変数のキーに対してeachを掛け、順次replace処理を施しています。

問題点

 以下のような過大な変数群を、ひとつのプレースホルダに適用する場合を考えてみましょう。ついでにパフォーマンスも計測しておきます。

let variables = {};
for(let i = 0; i < 100000; i++){
  variables[`user-${i}`] = Math.random().toString(36).slice(-8);
}
console.time();
let placeHolderString = "hello, {{user-1000}}.";
let replaced = Object.keys(variables).reduce((acc, key)=>acc.replace("{{" + key + "}}", variables[key]), placeHolderString);
console.log(replaced);    // -> hello, hhn5ylan.
console.timeEnd();    // -> default: 91.742919921875ms

 ちなみに、

let replaced = Object.keys(variables).reduce((acc, key)=>acc.replace("{{" + key + "}}", variables[key]), placeHolderString);

 は、以下のコードと同義です。

let replaced = placeHolderString;
Object.keys(variables).forEach(key=>{
  replaced = replaced.replace("{{" + key + "}}", variables[key]);
});

 これらは、オブジェクトの中身を全て処理するため、かなり遅いです。

replacer(function)を使う

 そこで、今回の本題であるreplacer(第二引数のfunction)を使ってみます。

let variables = {};
for(let i = 0; i < 100000; i++){
  variables[`user-${i}`] = Math.random().toString(36).slice(-8);
}
console.time();
let placeHolderString = "hello, {{user-1000}}.";
let replaced = placeHolderString.replace(/\{\{(.*?)\}\}/g, (match, p1)=>{
  return variables[p1];
});
console.log(replaced);    // -> hello, i24g408u.
console.timeEnd();    // -> default: 0.427001953125ms

 for文ループがなくなったため、91.7ms -> 0.42msと、かなり高速化しました。

まとめ

 本例は、foreach(reduce)の場合も、replace functionを使う場合も、まったく同じ結果をもたらします。変数が少なければ問題になりませんが、処理ひとつひとつのコストを常に考えることで、将来起こりうるパフォーマンス問題を最小限に抑えることができます。

 考え付いたまま、またはネットで拾ってきたソースコードをそのまま貼り付けて使っていたりすると、このような問題を容易に引き起こします。熟考とまでは行かずとも、意識したプログラミングを行うことが大切です。