オブジェクトは通常、ユーザー、注文など、現実世界のエンティティを表すために作成されます。
let user = {
name: "John",
age: 30
};
そして、現実世界では、ユーザーは行動できます。ショッピングカートから何かを選択したり、ログインしたり、ログアウトしたりなどです。
JavaScriptでは、プロパティ内の関数によってアクションを表します。
メソッドの例
まず、userに挨拶をさせましょう。
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert("Hello!");
};
user.sayHi(); // Hello!
ここでは、関数式を使用して関数を作成し、オブジェクトのプロパティuser.sayHiに割り当てました。
その後、user.sayHi()として呼び出すことができます。ユーザーは話すことができるようになりました!
オブジェクトのプロパティである関数は、そのメソッドと呼ばれます。
したがって、ここではオブジェクトuserのメソッドsayHiがあります。
もちろん、このように事前に宣言された関数をメソッドとして使用することもできます。
let user = {
// ...
};
// first, declare
function sayHi() {
alert("Hello!");
}
// then add as a method
user.sayHi = sayHi;
user.sayHi(); // Hello!
エンティティを表すオブジェクトを使用してコードを作成する場合、それはオブジェクト指向プログラミング(略して「OOP」)と呼ばれます。
OOPは大きなものであり、それ自体が興味深い科学です。適切なエンティティを選択する方法、エンティティ間の相互作用を整理する方法などは、アーキテクチャであり、E. Gamma、R. Helm、R. Johnson、J. Vissidesによる「Design Patterns: Elements of Reusable Object-Oriented Software」やG. Boochによる「Object-Oriented Analysis and Design with Applications」など、このトピックに関する優れた書籍があります。
メソッドの簡略表記
オブジェクトリテラルには、メソッドのより短い構文が存在します。
// these objects do the same
user = {
sayHi: function() {
alert("Hello");
}
};
// method shorthand looks better, right?
user = {
sayHi() { // same as "sayHi: function(){...}"
alert("Hello");
}
};
示されているように、"function"を省略してsayHi()と書くことができます。
正直に言うと、表記は完全に同一ではありません。オブジェクトの継承(後で説明します)に関連する微妙な違いがありますが、今のところ問題ではありません。ほとんどの場合、短い構文が優先されます。
メソッド内の"this"
オブジェクトメソッドが、その仕事をするためにオブジェクトに保存されている情報にアクセスする必要があることは一般的です。
たとえば、user.sayHi()内のコードは、userの名前を必要とする場合があります。
オブジェクトにアクセスするために、メソッドはthisキーワードを使用できます。
thisの値は、オブジェクト「ドットの前」、メソッドの呼び出しに使用されたオブジェクトです。
たとえば
let user = {
name: "John",
age: 30,
sayHi() {
// "this" is the "current object"
alert(this.name);
}
};
user.sayHi(); // John
ここで、user.sayHi()の実行中、thisの値はuserになります。
技術的には、外部変数を通じて参照することで、thisなしでオブジェクトにアクセスすることもできますが…
let user = {
name: "John",
age: 30,
sayHi() {
alert(user.name); // "user" instead of "this"
}
};
…このようなコードは信頼性がありません。userを別の変数(例:admin = user)にコピーし、userを別のものに上書きすると、間違ったオブジェクトにアクセスします。
以下に示します。
let user = {
name: "John",
age: 30,
sayHi() {
alert( user.name ); // leads to an error
}
};
let admin = user;
user = null; // overwrite to make things obvious
admin.sayHi(); // TypeError: Cannot read property 'name' of null
alert内でuser.nameの代わりにthis.nameを使用した場合、コードは機能します。
"this"はバインドされていません
JavaScriptでは、キーワードthisは他のほとんどのプログラミング言語とは異なって動作します。オブジェクトのメソッドではない場合でも、任意の関数で使用できます。
次の例には構文エラーはありません。
function sayHi() {
alert( this.name );
}
thisの値は、コンテキストに応じて実行時に評価されます。
たとえば、ここで同じ関数が2つの異なるオブジェクトに割り当てられ、呼び出しでは異なる"this"を持っています。
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// use the same function in two objects
user.f = sayHi;
admin.f = sayHi;
// these calls have different this
// "this" inside the function is the object "before the dot"
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (dot or square brackets access the method – doesn't matter)
ルールは簡単です。obj.f()が呼び出されると、fの呼び出し中はthisはobjになります。したがって、上記の例ではuserまたはadminのいずれかになります。
this == undefinedオブジェクトなしで関数を呼び出すこともできます。
function sayHi() {
alert(this);
}
sayHi(); // undefined
この場合、厳格モードではthisはundefinedです。this.nameにアクセスしようとすると、エラーが発生します。
厳格モードではない場合、そのような場合のthisの値はグローバルオブジェクト(ブラウザではwindow、この章の後半でグローバルオブジェクトで説明します)になります。これは、"use strict"で修正された履歴的な動作です。
通常、このような呼び出しはプログラミングエラーです。関数内にthisがある場合、オブジェクトコンテキストで呼び出されることを期待しています。
他のプログラミング言語を使用している場合、オブジェクトで定義されたメソッドは常にそのオブジェクトを参照する「バインドされたthis」という考え方に慣れている可能性があります。
JavaScriptでは、thisは「フリー」であり、その値は呼び出し時に評価され、メソッドが宣言された場所ではなく、どのオブジェクトが「ドットの前」にあるかに依存します。
実行時に評価されるthisの概念には、長所と短所があります。一方では、関数を異なるオブジェクトに対して再利用できます。他方では、柔軟性の向上により、ミスが発生する可能性が高くなります。
ここでは、この言語設計の決定が優れているか悪いかを判断することはしません。それを使ってどのように機能するか、どのように利点を得て問題を回避するかを理解します。
アロー関数には"this"がありません
アロー関数は特殊です。「独自の」thisがありません。そのような関数からthisを参照すると、外部の「通常の」関数から取得されます。
たとえば、ここではarrow()は外部user.sayHi()メソッドからthisを使用します。
let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya
これはアロー関数の特別な機能であり、個別のthisを持つ必要がなく、むしろ外部コンテキストから取得する場合に役立ちます。後の章アロー関数の再考では、アロー関数についてさらに詳しく説明します。
まとめ
- オブジェクトプロパティに格納されている関数は、「メソッド」と呼ばれます。
- メソッドにより、オブジェクトは
object.doSomething()のように「動作」できます。 - メソッドは、オブジェクトを
thisとして参照できます。
thisの値は実行時に定義されます。
- 関数が宣言されると、
thisを使用できますが、そのthisには、関数が呼び出されるまで値がありません。 - 関数はオブジェクト間でコピーできます。
- 関数が「メソッド」構文で呼び出されると:
object.method()、呼び出し中のthisの値はobjectです。
アロー関数は特殊であることに注意してください。thisがありません。アロー関数内でthisにアクセスすると、外部から取得されます。
コメント
<code>タグを使用し、複数行の場合は<pre>タグで囲み、10行を超える場合はサンドボックス(plnkr、jsbin、codepen…)を使用してください。