【JavaScript】in演算子とは?使い方などをわかりやすく解説!

この記事ではJavaScriptの『in演算子』について、

  • in演算子とは
  • in演算子の構文
  • in演算子の使い方
  • in演算子の特徴
  • in演算子とhasOwnPropertyメソッドの違い

などをサンプルコードを用いて分かりやすく説明するように心掛けています。ご参考になれば幸いです

in演算子とは

JavaScriptのin演算子は、指定されたプロパティが指定されたオブジェクトに存在するかどうかをチェックする演算子です。存在する場合にはtrueを返し、存在しない場合にはfalseを返します。

in演算子の構文を以下に示します。

in演算子の構文

prop in object

propは検査したいプロパティ名 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 personpersonオブジェクトに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 fruitstrue を返しています。インデックス3の要素は存在しないため、3 in fruitsfalseを返しています。また、すべての配列にはlengthプロパティがあるため、'length' in fruitstrue を返しています。

定義済みオブジェクトに対しても使用できる

in演算子は定義済みオブジェクトに対しても使用できます。サンプルコードを以下に示します。

console.log('PI' in Math); // true

定義済みオブジェクトであるMathオブジェクトにはPIプロパティがあるため、'PI' in Mathtrueを返しています。

JavaScriptのMathオブジェクトは様々な数学的なプロパティとメソッドを提供しています。その中でPIは円周率π(約3.14159)の値を表すMathオブジェクトのプロパティです。

オブジェクトのプロトタイプチェーン上のプロパティもチェックする

in演算子は、オブジェクト自身のプロパティだけでなく、そのプロトタイプチェーン上のプロパティもチェックします。サンプルコードを以下に示します。

console.log('toString' in {}); // true
console.log('constructor' in {}); // true
console.log('hasOwnProperty' in {}); // true

この例では、toStringconstructorhasOwnPropertyはオブジェクト自体には存在しないが、オブジェクトのプロトタイプチェーン(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 オブジェクトではない)

name1Stringオブジェクトとして作成されます。Stringオブジェクトにはlengthプロパティがあります(文字列の長さを返します)。そのため、'length' in name1trueを返しています。一方、name2はプリミティブな文字列です。in演算子にオブジェクトを指定しない場合には、エラーが発生します。

この振る舞いは、JavaScriptのバージョンや実行環境に依存します。

delete演算子で削除されたプロパティに対してはfalseを返す

delete演算子で削除されたプロパティについては、in演算子はfalseを返します。サンプルコードを以下に示します。

オブジェクトのプロパティの削除

const person = { name: 'Taro', age: 30 };
delete person.name;
console.log('name' in person); // false

上記のサンプルコードでは、まずpersonオブジェクトが作成され、その中にnameageという2つのプロパティが含まれています。delete person.namepersonオブジェクトからnameプロパティを削除しています。その後、'name' in personpersonオブジェクトに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 personpersonオブジェクトに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 emptiesfalseを返しています。

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メソッドの違い

お読み頂きありがとうございました。