この記事では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 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
メソッドの違い
お読み頂きありがとうございました。