From 994a43290111402e1744583138512683f992e08b Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Sat, 12 Oct 2024 22:22:59 +0900 Subject: [PATCH] =?UTF-8?q?2023/09/12=20=E6=99=82=E7=82=B9=E3=81=AE?= =?UTF-8?q?=E8=8B=B1=E8=AA=9E=E7=89=88=E3=81=AB=E5=9F=BA=E3=81=A5=E3=81=8D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reference/operators/typeof/index.md | 175 ++++++++---------- 1 file changed, 80 insertions(+), 95 deletions(-) diff --git a/files/ja/web/javascript/reference/operators/typeof/index.md b/files/ja/web/javascript/reference/operators/typeof/index.md index ba9327cfdf5ae3..84f9362a112115 100644 --- a/files/ja/web/javascript/reference/operators/typeof/index.md +++ b/files/ja/web/javascript/reference/operators/typeof/index.md @@ -1,21 +1,20 @@ --- title: typeof slug: Web/JavaScript/Reference/Operators/typeof +l10n: + sourceCommit: 4f86aad2b0b66c0d2041354ec81400c574ab56ca --- -{{JSSidebar("Operators")}} +{{jsSidebar("Operators")}} -`typeof` 演算子は、未評価のオペランドの型を示す文字列を返します。 +**`typeof`** 演算子は、オペランドの値の型を示す文字列を返します。 {{EmbedInteractiveExample("pages/js/expressions-typeof.html")}} ## 構文 -`typeof` 演算子の後に、オペランドを続けて書きます。 - ```js-nolint -typeof operand; -typeof(operand); +typeof operand ``` ### 引数 @@ -27,22 +26,19 @@ typeof(operand); 以下は `typeof` が返す可能性がある値の一覧です。型とプリミティブの詳細については、[JavaScript のデータ構造](/ja/docs/Web/JavaScript/Data_structures)のページも参照してください。 -| 型 | 結果 | -| ------------------------------------------------------------------------------------- | ------------------------------------- | -| [Undefined](/ja/docs/Glossary/Undefined) | `"undefined"` | -| [Null](/ja/docs/Glossary/Null) | `"object"` ([下記参照](#typeof_null)) | -| [論理値](/ja/docs/Glossary/Boolean) | `"boolean"` | -| [Number](/ja/docs/Glossary/Number) | `"number"` | -| [BigInt](/ja/docs/Glossary/BigInt) (ECMAScript 2020 の新機能) | `"bigint"` | -| [文字列](/ja/docs/Glossary/String) | `"string"` | -| [シンボル](/ja/docs/Glossary/Symbol) (ECMAScript 2015 の新機能) | `"symbol"` | -| [関数](/ja/docs/Glossary/Function) オブジェクト (ECMA-262 の用語では [[Call]] を実装) | `"function"` | -| その他のオブジェクト | `"object"` | - -> [!NOTE] -> ECMAScript 2019 およびそれ以前の実装では、呼び出し可能な標準外のオブジェクトに対して、`typeof` が任意の実装定義の文字列値を返すことを許可していました。 -> -> 実際にこれを利用したブラウザーとして知られているのは、古い Internet Explorer だけです。([下記参照](#ie-specific_notes)) +| 型 | 結果 | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | +| [Undefined](/ja/docs/Web/JavaScript/Reference/Global_Objects/undefined) | `"undefined"` | +| [Null](/ja/docs/Web/JavaScript/Reference/Operators/null) | `"object"` ([理由](#typeof_null)) | +| [論理型](/ja/docs/Web/JavaScript/Reference/Global_Objects/Boolean) | `"boolean"` | +| [数値型](/ja/docs/Web/JavaScript/Reference/Global_Objects/Number) | `"number"` | +| [長整数型](/ja/docs/Web/JavaScript/Reference/Global_Objects/BigInt) | `"bigint"` | +| [文字列型](/ja/docs/Web/JavaScript/Reference/Global_Objects/String) | `"string"` | +| [シンボル型](/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol) | `"symbol"` | +| [関数](/ja/docs/Web/JavaScript/Reference/Global_Objects/Function)オブジェクト (ECMA-262 の用語では [[Call]] を実装したもの、[クラス](/ja/docs/Web/JavaScript/Reference/Statements/class)も関数) | `"function"` | +| その他のオブジェクト | `"object"` | + +この値のリストは網羅的なものです。仕様を遵守するエンジンは、掲載されている値以外を生成する(または過去には生成していた)ことは報告されていません。 ## 例 @@ -69,7 +65,7 @@ typeof "1" === "string"; // 文字列内の数値は文字列型のままです typeof typeof 1 === "string"; // typeof は常に文字列を返します。 typeof String(1) === "string"; // String は何でも文字列に変換するので、toString よりも安全です。 -// 論理値 +// 論理型 typeof true === "boolean"; typeof false === "boolean"; typeof Boolean(1) === "boolean"; // Boolean は、値が真値か偽値かに基づいて変換します。 @@ -106,62 +102,56 @@ typeof class C {} === "function"; typeof Math.sin === "function"; ``` -### `typeof null` +### typeof null ```js // JavaScript の初期からの実装に基づく typeof null === "object"; ``` -JavaScript の最初の実装では、JavaScript の値は型タグと値で表現されていました。オブジェクトの型タグは `0` で、`null` は NULL ポインター (ほとんどのプラットフォームで `0x00`) として表されていました。その結果、`null` はタグの型として `0` を持っていたため、`typeof` の戻り値は `"object"` です。([リファレンス](http://www.2ality.com/2013/10/typeof-null.html)) +JavaScript の最初の実装では、JavaScript の値は型タグと値で表現されていました。オブジェクトの型タグは `0` で、`null` は NULL ポインター (ほとんどのプラットフォームで `0x00`) として表されていました。その結果、`null` はタグの型として `0` を持っていたため、`typeof` の返値は `"object"` です。([リファレンス](https://2ality.com/2013/10/typeof-null.html)) -ECMAScript の修正案が (オプトインを使用して) 提案されましたが、[却下されました](https://web.archive.org/web/20160331031419/http://wiki.ecmascript.org:80/doku.php?id=harmony:typeof_null)。それは `typeof null === 'null'` という結果になるものでした。 +ECMAScript の修正案が (オプトインを使用して) 提案されましたが、[却下されました](https://web.archive.org/web/20160331031419/http://wiki.ecmascript.org:80/doku.php?id=harmony:typeof_null)。それは `typeof null === "null"` という結果になるものでした。 -### `new` 演算子の使用 +### new 演算子の使用 + +[`new`](/ja/docs/Web/JavaScript/Reference/Operators/new) で呼び出されるコンストラクター関数はすべて、プリミティブ型以外の値を返します("object" または "function")。 ほとんどはオブジェクトを返しますが、特記すべき例外として、[`Function`](/ja/docs/Web/JavaScript/Reference/Global_Objects/Function) は関数を返します。 ```js -// Function コンストラクターを除くすべてのコンストラクター関数は、 -// 常に typeof 'object' です -let str = new String("String"); -let num = new Number(100); +const str = new String("String"); +const num = new Number(100); -typeof str; // 'object' を返す -typeof num; // 'object' を返す +typeof str; // "object" を返す +typeof num; // "object" を返す -let func = new Function(); +const func = new Function(); -typeof func; // 'function' を返す +typeof func; // "function" を返す ``` ### 構文で括弧が必要な場合 +`typeof` 演算子は、[優先順位](/ja/docs/Web/JavaScript/Reference/Operators/Operator_precedence)が加算 (`+`) などの二項演算子よりも高くなります。そのため、加算結果の型を評価するには括弧が必要です。 + ```js -// 式のデータ型を特定するために、かっこを使用することができます。 -let iData = 99; +// 括弧を使うと、式のデータ型を特定することができます。 +const someData = 99; -typeof iData + " Wisen"; // 'number Wisen' -typeof (iData + " Wisen"); // 'string' +typeof someData + " Wisen"; // "number Wisen" +typeof (someData + " Wisen"); // "string" ``` -### 正規表現 +### エラー -呼び出し可能な正規表現は、一部のブラウザーにおける標準外の追加機能でした。 +`typeof` は一般に、それが供給されたオペランドの文字列を返すことが保証されています。宣言されていない識別子があっても、`typeof` は `"undefined"` を返し、エラーは発生しません。 ```js -typeof /s/ === "function"; // Chrome 1-12 ECMAScript5.1 に非準拠 -typeof /s/ === "object"; // Firefox 5+ ECMAScript 5.1 に準拠 +typeof undeclaredVariable; // "undefined" ``` -### エラー - -ECMAScript 2015 より前では、`typeof` は常にそれが供給されたオペランドの文字列を返すことが保証されていました。宣言されていない識別子があっても、`typeof` は `'undefined'` を返します。`typeof` を使用すると、エラーは発生しません。 - -しかしながら、ブロックスコープの {{JSxRef("Statements/let", "let")}} と -{{JSxRef("Statements/const", "const")}} が追加されたことで、変数が宣言される前のブロック内で `let` と `const` に `typeof` を使用すると(またはクラスに `typeof` を使用すると)、 {{JSxRef("ReferenceError")}} が発生します。ブロックスコープ内の変数は、ブロックの開始から初期化が処理されるまで「[一時的なデッドゾーン](/ja/docs/Web/JavaScript/Reference/Statements/let#一時的なデッドゾーン_tdz)」にあり、その間にアクセスされるとエラーが発生します。 - -```js -typeof undeclaredVariable === "undefined"; +しかし、`typeof` を同じブロック内の字句宣言({{jsxref("Statements/let", "let")}}、{{jsxref("Statements/const", "const")}}、[`class`](/ja/docs/Web/JavaScript/Reference/Statements/class))の前に使用すると、{{jsxref("ReferenceError")}} が発生します。 ブロックスコープの変数は、ブロックの開始から初期化が処理されるまでの間、一時的なデッドゾーンにあり、その間にアクセスするとエラーが発生します。ブロックスコープ内の変数は、ブロックの開始から初期化が処理されるまで「[一時的なデッドゾーン](/ja/docs/Web/JavaScript/Reference/Statements/let#一時的なデッドゾーン_tdz)」にあり、その間にアクセスされるとエラーが発生します。 +```js example-bad typeof newLetVariable; // ReferenceError typeof newConstVariable; // ReferenceError typeof newClass; // ReferenceError @@ -171,7 +161,7 @@ const newConstVariable = "hello"; class newClass {} ``` -### 例外 +### document.all の例外的な動作 現在のブラウザーではすべて、標準外のホストオブジェクト [`document.all`](/ja/docs/Web/API/Document/all) は `undefined` 型になります。 @@ -179,44 +169,54 @@ class newClass {} typeof document.all === "undefined"; ``` -仕様では、標準外のオブジェクトのために独自の型タグが設定できるようにしていますが、定義済みの型タグとは異なる必要があります。 `document.all` が `'undefined'` という型であるというのは、ウェブ標準では元の ECMA JavaScript 標準において「故意の違反」として分類されています。 +`document.all` は[偽値](/ja/docs/Glossary/Falsy)でもあり、`undefined` と[緩い等価性](/ja/docs/Web/JavaScript/Reference/Operators/Equality)がありますが、[`undefined`](/ja/docs/Web/JavaScript/Reference/Global_Objects/undefined) ではありません。`document.all` が `"undefined"` という型を持つケースは、ウェブ標準では、ウェブ互換性を目的とした ECMAScript 標準の「意図的な違反」として分類されています。 -### 実際の使い方 +### より具体的な型を取得するカスタムメソッド -`typeof` は非常に便利ですが、汎用性はそれほど高くありません。たとえば、`typeof([])` は `typeof(new Date())` や `typeof(/abc/)` などと同様に `'object'` になります。 +`typeof` は非常に便利ですが、汎用性はそれほど高くありません。たとえば、`typeof []` は `"object"` になります。`typeof new Date()` や `typeof /abc/` などと同様です。 -型のチェックをより具体的にするためには、実用レベルのコードで使用するための `typeof` ラッパーは以下のようになります。(`obj` が存在する場合) +型チェックの精度を上げるために、ここではカスタム関数 `type(value)` を紹介します。これは主に `typeof` の動作を模倣しますが、プリミティブ型以外のもの(つまりオブジェクトや関数)については、可能な限り詳細な型名を返します。 ```js -function type(obj, fullClass) { - // obj の toPrototypeString() を取得します。(すべての型を処理します) - if (showFullClass && typeof obj === "object") { - return Object.prototype.toString.call(obj); +function type(value) { + if (value === null) { + return "null"; + } + const baseType = typeof value; + // プリミティブ型 + if (!["object", "function"].includes(baseType)) { + return baseType; } - if (obj == null) { - return (obj + "").toLowerCase(); - } // 暗黙の toString() 変換 - var deepType = Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); - if (deepType === "generatorfunction") { - return "function"; + // Symbol.toStringTag は、多くの場合、オブジェクトのクラスの + // 「表示名」を指定する。これは Object.prototype.toString() で使用する。 + const tag = value[Symbol.toStringTag]; + if (typeof tag === "string") { + return tag; } - // 過剰な特異性を防いでください。(例えば、[object HTMLDivElement] など) - // 関数的な正規表現 (Android 2.3 以前)、関数的な 要素 (Chrome 57 以前, Firefox 52 以前) などを考慮してください。 - // String.prototype.match は普遍的にサポートされています。 - - return deepType.match( - /^(array|bigint|date|error|function|generator|regexp|symbol)$/, - ) - ? deepType - : typeof obj === "object" || typeof obj === "function" - ? "object" - : typeof obj; + // ソースコードが "class" キーワードで始まる関数である場合 + if ( + baseType === "function" && + Function.prototype.toString.call(value).startsWith("class") + ) { + return "class"; + } + + // コンストラクターの名前。例えば、`Array`、`GeneratorFunction`、 + // `Number`、`String`、`Boolean`、`MyCustomClass`。 + const className = value.constructor.name; + if (typeof className === "string" && className !== "") { + return className; + } + + // ここまでくると、値の型を取得する確実な方法はないため、 + // 基本実装を使用します。 + return baseType; } ``` -存在しない変数をチェックすると、{{JSxRef("ReferenceError")}} が発生するため、`typeof nonExistentVar === 'undefined'` を使用します。 +存在しない可能性がある変数を調べるには、{{jsxref("ReferenceError")}} が発生する可能性があるため、`typeof nonExistentVar === "undefined"` を使用してください。この動作は、カスタムコードでは模倣できないためです。 ## 仕様書 @@ -226,22 +226,7 @@ function type(obj, fullClass) { {{Compat}} -### IE 固有のメモ - -IE 6、7、8 では、以下のように多くのホストオブジェクトがオブジェクト型であり、関数ではありません。 - -```js -typeof alert === "object"; -``` - -一部の標準外 IE プロパティは他の値を返します。([tc39/ecma262#1440 (comment)](https://github.com/tc39/ecma262/issues/1440#issuecomment-461963872)) - -```js -typeof window.external.AddSearchProvider === "unknown"; -typeof window.external.IsSearchProviderInstalled === "unknown"; -``` - ## 関連情報 -- {{JSxRef("Operators/instanceof", "instanceof")}} +- {{jsxref("Operators/instanceof", "instanceof")}} - [`document.all` willful violation of the standard](https://github.com/tc39/ecma262/issues/668)