この記事ではJavaScriptの『in演算子』について、
in演算子とはin演算子の構文in演算子の使い方in演算子の特徴in演算子とhasOwnPropertyメソッドの違い
などをサンプルコードを用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです
in演算子とは
JavaScriptのin演算子は、指定されたプロパティが指定されたオブジェクトに存在するかどうかをチェックする演算子です。存在する場合にはtrueを返し、存在しない場合にはfalseを返します。
in演算子の構文を以下に示します。
in演算子の構文
prop in objectpropは検査したいプロパティ名 or 配列のインデックス or シンボルです。
objectはチェック対象のオブジェクトです。
in演算子の使い方
JavaScriptのin演算子を用いたサンプルコードを以下に示します。
const person = { name: 'Taro', age: 30 };
//'name'はpersonオブジェクトに存在するか?
console.log('name' in person); // true
//'age'はpersonオブジェクトに存在するか?
console.log('age' in person); // true
//'gender'はpersonオブジェクトに存在するか?
console.log('gender' in person); // false上記のサンプルコードにおいて、'name' in personは、personオブジェクトにnameプロパティが存在するかどうかをチェックしています。personオブジェクトにはnameプロパティがあるので、trueを返しています。'age' in personも同様にtrueを返しています。
一方、'gender' in personはpersonオブジェクトにgenderプロパティが存在するかどうかをチェックします。personオブジェクトにはgenderプロパティがないので、falseを返しています。
in演算子の特徴
in演算子の特徴を以下に示します。
- 配列に対しても使用できる
- 定義済みオブジェクトに対しても使用できる
- オブジェクトのプロトタイプチェーン上のプロパティもチェックする
in演算子にはオブジェクトを指定しなければいけないdelete演算子で削除されたプロパティに対してはfalseを返すundefinedを設定しているプロパティに対してはtrueを返す- 空の配列スロットに対しては
falseを返す
各特長について順番に説明します。
配列に対しても使用できる
in演算子は配列に対しても使用できます。サンプルコードを以下に示します。
const fruits = ['apple', 'banana', 'melon'];
// インデックス 0 は fruits配列内に存在するか?
console.log(0 in fruits); // true
// インデックス 3 は fruits配列内に存在するか?
console.log(3 in fruits); // false
//'length'はfruitsのプロパティとして存在するか?
console.log('length' in fruits); // true(lengthはArrayの標準プロパティ)
// 以下の使い方はNG
console.log('apple' in fruits); // false(添字の指す値ではなく、添字の数値を指定しなければならない)配列fruitsにおいて、インデックス0の要素('apple')は存在するので0 in fruits は true を返しています。インデックス3の要素は存在しないため、3 in fruitsはfalseを返しています。また、すべての配列にはlengthプロパティがあるため、'length' in fruits も true を返しています。
定義済みオブジェクトに対しても使用できる
in演算子は定義済みオブジェクトに対しても使用できます。サンプルコードを以下に示します。
console.log('PI' in Math); // true定義済みオブジェクトであるMathオブジェクトにはPIプロパティがあるため、'PI' in Mathはtrueを返しています。
JavaScriptのMathオブジェクトは様々な数学的なプロパティとメソッドを提供しています。その中でPIは円周率π(約3.14159)の値を表すMathオブジェクトのプロパティです。
オブジェクトのプロトタイプチェーン上のプロパティもチェックする
in演算子は、オブジェクト自身のプロパティだけでなく、そのプロトタイプチェーン上のプロパティもチェックします。サンプルコードを以下に示します。
console.log('toString' in {}); // true
console.log('constructor' in {}); // true
console.log('hasOwnProperty' in {}); // trueこの例では、toStringやconstructorやhasOwnPropertyはオブジェクト自体には存在しないが、オブジェクトのプロトタイプチェーン(Object.prototype)に定義されているメソッドやプロパティなので、trueを返しています。
in演算子にはオブジェクトを指定しなければいけない
in演算子には、オブジェクトを指定しなければなりません。例えば、Stringコンストラクターで作成した文字列は指定できますが、文字列リテラル自体は指定できません。サンプルコードを以下に示します。
const name1 = new String('Taro');
console.log('length' in name1); // true
const name2 = 'Taro';
console.log('length' in name2); // エラーが発生 (name2 は String オブジェクトではない)name1はStringオブジェクトとして作成されます。Stringオブジェクトにはlengthプロパティがあります(文字列の長さを返します)。そのため、'length' in name1はtrueを返しています。一方、name2はプリミティブな文字列です。in演算子にオブジェクトを指定しない場合には、エラーが発生します。
この振る舞いは、JavaScriptのバージョンや実行環境に依存します。
delete演算子で削除されたプロパティに対してはfalseを返す
delete演算子で削除されたプロパティについては、in演算子はfalseを返します。サンプルコードを以下に示します。
オブジェクトのプロパティの削除
const person = { name: 'Taro', age: 30 };
delete person.name;
console.log('name' in person); // false上記のサンプルコードでは、まずpersonオブジェクトが作成され、その中にnameとageという2つのプロパティが含まれています。delete person.nameはpersonオブジェクトからnameプロパティを削除しています。その後、'name' in personでpersonオブジェクトにnameプロパティがまだ存在するかどうかをチェックしますが、プロパティが削除されているためfalseを返しています。
配列要素の削除
const fruits = ['apple', 'banana', 'melon'];
delete fruits[1];
console.log(1 in fruits); // false上記のサンプルコードでは、fruitsという配列があり、delete fruits[1];は配列のインデックス1('banana')を削除します。1 in fruitsは、インデックス1の要素がまだ配列に存在するかどうかをチェックしますが、要素が削除されているので、falseを返しています。
undefinedを設定しているプロパティに対してはtrueを返す
プロパティや要素にundefinedを設定されていても、in演算子はプロパティの存在自体をチェックするため、結果としてtrueを返します。サンプルコードを以下に示します。
オブジェクトのプロパティにundefinedを設定
const person = { name: undefined, age: 30 };
console.log('name' in person); // true上記のサンプルコードでは、personオブジェクトのnameプロパティにundefinedを設定しています。'name' in personはpersonオブジェクトにnameプロパティが存在するかどうかをチェックします。nameプロパティは存在するので、trueを返しています。
配列要素にundefinedを設定
const fruits = ['apple', undefined, 'melon'];
console.log(1 in fruits); // true上記のサンプルコードでは、fruits配列のインデックス1の要素にundefinedを設定しています。1 in fruits は、インデックス1の要素が配列に存在するかどうかをチェックします。要素は存在するので、true を返しています。
空の配列スロットに対してはfalseを返す
in演算子は、空の配列スロットに対してはfalse を返します(直接アクセスした場合にはundefined が返されます)。
const fruits = ['apple', , 'banana'];
// 空のスロットの存在をチェックするとfalseを返す
console.log(1 in fruits); // false
// 空のスロットへのアクセスはundefinedを返す
console.log(fruits[1]); // undefined上記のサンプルコードにおいて、fruits配列のインデックス1が空のスロットになっています。JavaScriptの配列では、明示的に値が設定されていないスロット(この場合はインデックス1の位置)は、実際には配列の中に「存在しない」とみなされます。そのため、1 in emptiesはfalseを返しています。
in演算子とhasOwnPropertyの違い
in演算子とhasOwnPropertyメソッドは、JavaScriptにおいてオブジェクト内のプロパティの存在をチェックする際に使用されますが、それぞれ異なる挙動を示します。以下にその違いを説明します。
in演算子- 指定されたプロパティ(またはメソッド)がオブジェクト自体に存在するか、または、そのプロトタイプチェーン内に存在するかをチェックします。
hasOwnPropertyメソッド- 指定されたプロパティ(またはメソッド)がオブジェクト自体に存在するかどうかを直接チェックします。プロトタイプチェーンは考慮しません。
実際にサンプルコードでその違いを確認してみましょう。
const person = { name: 'Taro', age: 30 };
// in演算子を使用した場合
console.log('name' in person); // true
console.log('toString' in person); // true (プロトタイプチェーン上に存在)
// hasOwnPropertyメソッドを使用した場合
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('toString')); // false (プロトタイプチェーン上に存在するが、personオブジェクト自体にはない)また、クラス構文で定義されたメソッドは、インスタンス自体には直接配置されず、クラスのプロトタイプオブジェクトに配置されます。そのため、クラス構文を使用した場合、インスタンスに直接メソッドが存在しないため、hasOwnPropertyメソッドはメソッドの存在をfalseとして返します。一方、in演算子はプロトタイプチェーンを検索するため、メソッドの存在をtrueとして検出します。
class MyClass {
constructor() {
this.name = 'Taro';
}
hello() {
console.log('hello!');
}
}
const myInstance = new MyClass();
// in演算子を使用した場合
console.log('hello' in myInstance); // true
// hasOwnPropertyメソッドを使用した場合
console.log(myInstance.hasOwnProperty('hello')); // false上記のサンプルコードでは、helloメソッドはMyClassのプロトタイプにあり、myInstanceインスタンス自体には存在しません。そのため、hasOwnPropertyメソッドはfalseを返しますが、in演算子はtrueを返します。
本記事のまとめ
この記事ではJavaScriptの『in演算子』について、以下の内容を説明しました。
in演算子とはin演算子の構文in演算子の使い方in演算子の特徴in演算子とhasOwnPropertyメソッドの違い
お読み頂きありがとうございました。