0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

新・JavaScript文法(2):文字列/演算子/型変換の基礎

Posted at

前回の記事では、JavaScriptの実行環境の構築と基本的な文法について紹介しました。今回は、文字列の取り扱い方やデータ型、演算子について、より詳しく扱います。

文字列の基本

文字列の作成方法

JavaScriptでは、文字列を作成するために以下の3つの方法があります:

// 1. シングルクォート
const str1 = 'Hello World';

// 2. ダブルクォート
const str2 = "Hello World";

// 3. テンプレートリテラル(バッククォート)
const str3 = `Hello World`;

シングルクォートとダブルクォートは機能的に同じですが、テンプレートリテラル(バッククォート)には特別な機能があります。

テンプレートリテラルの機能と利点

テンプレートリテラルには、以下のような機能と利点があります:

const name = "Alice";
const age = 25;

// 従来の文字列結合
const message1 = name + "さんは" + age + "歳です。";


// テンプレートリテラルを使用
const message2 = `${name}さんは${age}歳です。`;


console.log(message1); // "Aliceさんは25歳です。"
console.log(message2); // "Aliceさんは25歳です。"

テンプレートリテラルのメリット

  • 変数の埋め込みが直感的
  • 複数行の文字列が書きやすい
  • 特殊文字のエスケープが少なくて済む
// 複数行の文字列
const multiline = `
  こんにちは、
  これは複数行の
  文字列です。
`;

console.log(multiline);
// 出力:
//   こんにちは、
//   これは複数行の
//   文字列です。

// タグ付きテンプレート
function sanitizeHTML(strings, ...values) {
  return strings.reduce((result, str, i) => {
    const value = values[i - 1] || '';
    // 簡易的なHTMLエスケープ
    const escaped = String(value)
      .replace(/&/g, '&')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
    return result + escaped + str;
  });
}

const userInput = '<script>alert("危険!")</script>';
const safeName = sanitizeHTML`<div>ようこそ、${userInput}さん</div>`;     // タグつきテンプレートの使用例

console.log(safeName);
// 出力:<div>ようこそ、&lt;script&gt;alert(&quot;危険!&quot;)&lt;/script&gt;さん</div>

エスケープシーケンス

文字列内で特殊な文字を表現する場合は、エスケープシーケンスを使用します:

// よく使うエスケープシーケンス
const str1 = "改行を\n入れます";
const str2 = "タブを\t入れます";
const str3 = "\"クォートを\"入れます";

// テンプレートリテラルなら、クォートのエスケープが不要
const str4 = `"クォート"を入れます`;

型と変数の基本

JavaScriptの型システムを理解することは、バグの少ない安全なコードを書くために重要です。第1回でも扱いましたが、ここで改めて取り上げます。

プリミティブ型の種類

JavaScriptには以下の6つのプリミティブ型があります:

// 1. 文字列型(String)
const str = "Hello";

// 2. 数値型(Number)
const num = 42;

// 3. 真偽値型(Boolean)
const bool = true;

// 4. undefined型
let undef;  // 値を代入していない変数。初期化されていない変数は暗黙的に undefined になる
console.log(undef); // undefined が出力される
console.log(typeof undef); // "undefined" が出力される

// 5. null型
const nullValue = null;  // 意図的に「値がない」ことを表現

// 6. Symbol型(ES2015で追加):ユニークな値を生成
const sym = Symbol('description');

変数宣言の種類と使い分け

モダンなJavaScriptでは、var の代わりに letconst を使用します:

// constの使用例(再代入不可)
const PI = 3.14159;
// PI = 3.14;  // エラー:constは再代入できない

// letの使用例(再代入可能)
let count = 0;
count = 1;  // OK

// varは使用を避ける(スコープの問題があるため)
var x = 10;  // 非推奨

typeof演算子による型の確認

変数の型を調べるには typeof 演算子を使用します:

const str = "Hello";
const num = 42;
const bool = true;
const arr = [1, 2, 3];
const obj = { name: "Alice" };

console.log(typeof str);   // "string"
console.log(typeof num);   // "number"
console.log(typeof bool);  // "boolean"
console.log(typeof arr);   // "object"
console.log(typeof obj);   // "object"

// nullの特殊なケース
console.log(typeof null);   // "object" (これはJavaScriptの有名な仕様バグ)

NaNとNumber型のユーティリティ関数

JavaScriptでの数値の扱いには、いくつか注意の必要な点があります:

// NaN(Not a Number)の特徴
console.log(typeof NaN);           // "number"
console.log(NaN === NaN);          // false(NaNは自分自身とも等しくない)
console.log(Number.isNaN(NaN));    // true(正しいNaNの判定方法)
console.log(isNaN("文字列"));      // true(グローバルのisNaN()は型変換を行う)
console.log(Number.isNaN("文字列")); // false(Number.isNaN()は型変換を行わない):グローバルの isNaN() は文字列を数値に変換しようとするため true を返してしまう

// 数値判定のユーティリティ関数
console.log(Number.isFinite(42));     // true(有限数かどうか)
console.log(Number.isFinite(1/0));    // false(Infinityは有限数ではない)
console.log(Number.isInteger(42));    // true(整数かどうか)
console.log(Number.isInteger(42.5));  // false(小数は整数ではない)

// 安全な整数の範囲
console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER);  // -9007199254740991
console.log(Number.isSafeInteger(9007199254740991));  // true
console.log(Number.isSafeInteger(9007199254740992));  // false

演算子と型変換

比較演算子

JavaScriptには2種類の等価演算子があります:

// 1. 厳密等価演算子(===):型と値の両方を比較
console.log(5 === "5");    // false
console.log(5 === 5);      // true

// 2. 等価演算子(==):暗黙的な型変換を行ってから比較
console.log(5 == "5");     // true(非推奨)

// 型変換の例
console.log(1 == true);    // true (数値型 1 に変換される)
console.log(0 == false);   // true (数値型 0 に変換される)
console.log("" == false);   // true (空文字は数値の0、つまり false に変換される)
console.log("1" == true); // true (文字列型 "1" は数値型 1 に変換され、true は数値型 1 に変換される)
console.log(null == undefined); // true (特殊なケース)

モダンなJavaScriptでは、バグの予防のために ===(厳密等価演算子)の使用を推奨します:

// 厳密等価演算子を使った安全な比較
function checkValue(value) {
  // 良い例:型を含めた厳密な比較
  if (value === null || value === undefined) {
    //  == を使うと null も undefined も true となるので注意
    //  if (value == null) と書くこともできるが、型を明確にするために === を使う方が良い
    // if(value == null)
    //    console.log('値は null or undefined');
    //
    // if(value == undefined)
    //    console.log('値は null or undefined');
    return "値が設定されていません";
  }
  
  // 良い例:数値の型を保証
  if (typeof value === "number") {
    return "数値です";
  }
  
  return "その他の型です";
}

console.log(checkValue(null));     // "値が設定されていません"
console.log(checkValue(42));       // "数値です"
console.log(checkValue("42"));     // "その他の型です"

型変換

JavaScriptでは、明示的な型変換と暗黙的な型変換があります。安全なコードを書くために、基本的には明示的な型変換を使用することを推奨します。

// 明示的な型変換(推奨)
const numStr = "42";
const num = Number(numStr);       // 42(数値型)
const str = String(num);          // "42"(文字列型)
const bool = Boolean(num);        // true(真偽値型)

// 暗黙的な型変換(非推奨)
const result1 = "42" - 0;         // 42(数値型)
const result2 = 42 + "";         // "42"(文字列型)

// 数値への変換
console.log(Number("42"));        // 42
console.log(parseInt("42.5"));    // 42(整数部分のみ)
console.log(parseFloat("42.5"));  // 42.5(小数点も含める)
console.log(Number("abc"));       // NaN(変換できない場合)

// 真偽値への変換
console.log(Boolean(""));         // false(空文字列)
console.log(Boolean("abc"));      // true(空でない文字列)
console.log(Boolean(0));          // false
console.log(Boolean(1));          // true
console.log(Boolean([]));         // true(空配列)
console.log(Boolean(null));       // false
console.log(Boolean(undefined));  // false

実践的なコード例

function validateAndParseNumber(input) {
  try {
    // 文字列型でない場合は文字列に変換
    const strValue = String(input).trim();
    
    // 空文字列チェック
    if (strValue === "") {
      return {
        isValid: false,
        value: null,
        error: "入力が空です"
      };
    }
    
    // 数値への変換
    const numValue = Number(strValue);
    
    // NaN、Infinity、-Infinityのチェック
    if (!Number.isFinite(numValue)) {
      return {
        isValid: false,
        value: null,
        error: "有効な数値ではありません"
      };
    }
    
    // 安全な整数範囲のチェック(必要な場合)
    if (!Number.isSafeInteger(numValue)) {
      return {
        isValid: false,
        value: null,
        error: "数値が大きすぎるか、整数ではありません"
      };
    }
    
    return {
      isValid: true,
      value: numValue,
      error: null
    };
  } catch (error) {
    // 予期せぬエラーの処理
    console.error("数値変換処理でエラーが発生:", error);
    return {
      isValid: false,
      value: null,
      error: "入力の処理中にエラーが発生しました"
    };
  }
}

// 使用例
console.log(validateAndParseNumber("42"));        // { isValid: true, value: 42, error: null }
console.log(validateAndParseNumber("abc"));       // { isValid: false, value: null, error: "有効な数値ではありません" }
console.log(validateAndParseNumber(""));          // { isValid: false, value: null, error: "入力が空です" }
console.log(validateAndParseNumber("1e+999"));    // { isValid: false, value: null, error: "有効な数値ではありません" }
console.log(validateAndParseNumber(42.5));        // { isValid: false, value: null, error: "数値が大きすぎるか、整数ではありません" }

// より実践的な数値処理の例
function calculateDiscount(price, discountRate) {
  try {
    // 引数の型チェックと変換
    const validPrice = validateAndParseNumber(price);
    if (!validPrice.isValid) {
      throw new Error(`価格が不正です: ${validPrice.error}`);
    }

    // 割引率の検証(0-100の範囲)
    const rate = Number(discountRate);
    if (!Number.isFinite(rate) || rate < 0 || rate > 100) {
      throw new Error("割引率は0から100の間で指定してください");
    }

    // 割引計算
    const discount = Math.floor(validPrice.value * (rate / 100));
    const finalPrice = validPrice.value - discount;

    return {
      originalPrice: validPrice.value,
      discountRate: rate,
      discount: discount,
      finalPrice: finalPrice
    };
  } catch (error) {
    return {
      error: error.message,
      originalPrice: null,
      discountRate: null,
      discount: null,
      finalPrice: null
    };
  }
}

// 使用例
console.log(calculateDiscount("1000", 20));
// {
//   originalPrice: 1000,
//   discountRate: 20,
//   discount: 200,
//   finalPrice: 800
// }

console.log(calculateDiscount("invalid", 20));
// {
//   error: "価格が不正です: 有効な数値ではありません",
//   originalPrice: null,
//   discountRate: null,
//   discount: null,
//   finalPrice: null
// }

まとめ

この回では、JavaScriptの文字列操作、データ型、演算子、型変換について学びました。重要なポイントを整理しましょう:

  1. 文字列操作
    • テンプレートリテラル(`)を使用すると、可読性の高いコードが書ける
    • タグ付きテンプレートを使用することで、文字列の安全な加工が可能
    • 複数行の文字列も簡単に記述可能
  2. 変数宣言
    • constletを使用し、varは避ける
    • できるだけconstを使用し、再代入が必要な場合のみletを使用
  3. 比較演算子
    • ===(厳密等価演算子)を使用し、==は避ける
    • 型の安全性を確保することでバグを防ぐ
  4. 型変換
    • 明示的な型変換(Number()String()Boolean())を使用
    • 暗黙的な型変換は予期せぬバグの原因になるため、特別な理由がない限り避ける
    • Number.isNaN()Number.isFinite()などの適切な判定関数を使用
  5. エラー処理
    • 型変換やバリデーションでは適切なエラーハンドリングを実装
    • エラーメッセージは具体的で理解しやすいものを使用
    • try-catchを使用して予期せぬエラーに対応

これらの基礎を押さえることで、より安全で保守性の高いJavaScriptコードが書けるようになります。とくに、型の安全性を意識したコーディングは、バグの予防と早期発見に大きく貢献します。

次回予告

次回は「制御構文とループ」について紹介します。条件分岐(if文、switch文)や繰り返し処理(for文、while文)の基本と、モダンな書き方について扱います。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?