最初に、JavaScript のいくつかの細かい点を見てみましょう。それから、あなたの例を扱うことができます。
関数のコンテキスト
誤解の 1 つのポイントはコンテキストです。すべての関数は、キーワードを使用して利用できるコンテキストで呼び出されますthis
。コンテキストを検査するために使用できる関数を書きましょう。
var probe = function(){
// if the context doesn't have a name, let's name it
if(!this.name){
this.name = "lumberjack";
}
// print the name of my context
console.log(this.name);
};
どうぞ:
name = "global!";
// when we call a function normally it still have a context:
// the global context
probe(); // prints: global!
var ctx = {name: "ctx"};
// we can set a context explicitly using call()
probe.call(ctx); // prints: ctx
// we can set a context explicitly using apply()
probe.apply(ctx); // prints: ctx
// it is set implicitly, if we call a function as a member
ctx.fun = probe;
ctx.fun(); // prints: ctx
// or we can create a brand new object and set it as a context:
// that's what "new" does
var t = new probe(); // prints: lumberjack
// let's sum it up:
console.log(name); // prints: global!
console.log(ctx.name); // prints: ctx
console.log(t.name); // prints: lumberjack
そのため、混乱してうっかりグローバル コンテキストに陥ってしまうのは非常に簡単です。
コンストラクタで値を返す
コンストラクターが値を返すのを見ると、多くの人が混乱します。合法です。コンストラクターは、オブジェクト、関数、または配列を返すことができます。この値はインスタンスとして使用されます。古いインスタンスは破棄されます。
var myClass = function(){
// if it is called as a constructor, "this" will be a new instance
// let's fill it up:
this.a = 42;
this.b = "Ford";
this.c = function(){ return "Perfect"; };
// done? let's discard it completely!
// and now for something completely different...
return {
owner: "Monty Python",
establishment: "Flying Circus"
};
};
var t = new myClass();
alert(t.owner + "'s " + t.establishment);
さすが「モンティ・パイソンズ・フライング・サーカス」。
コンストラクターが何か他のもの (数値、文字列、null、未定義など) を返す場合、返された結果は破棄され、古いインスタンスが使用されます。
例
あなたの例は、主にそれが書かれた方法のために理解するのが難しいです. 簡単に書き直してみましょう。
まず、次のものを扱いましょうx
。
var x = function() {
this.foo = "foo";
return function() {
this.bar = "bar";
return foo + bar;
};
}(); // returns inner
ご覧のとおり、無名関数 ( 1番目 function
) はすぐに実行されるため、インライン化できます。
// next assignment can be simplified because
// top "this" is window or the global scope
//this.foo = "foo"; =>
foo = "foo";
x = function() {
this.bar = "bar"; // this line depends on its context, or "this"
return foo + bar; // this line uses global "foo" and "bar"
};
最後に、(foo
文字列) とx
(関数) の 2 つのグローバル変数があります。
それでは、最初のアラートを見てみましょう。
alert(x()); // 'foobar', so both 'this' variables are set
繰り返しますが、インライン化しましょうx()
:
// next assignment can be simplified because
// top "this" is window or the global scope
//this.bar = "bar"; =>
bar = "bar";
// at this moment both global "foo" and "bar" are set
alert(foo + bar); // => "foo" + "bar" => "foobar"
2番目のアラートも同様に単純です。
alert(x.bar); // undefined - but wasn't it used correctly?
あまり書き直す必要はありません。x
は関数であり、プロパティを追加していないためx.bar
未定義です。追加すると、結果が表示されます。
x.bar = "bar2";
alert(x.bar); // bar2
3番目のアラートは、JavaScript の OOP の動作を示しています。
alert(new x().bar); // ok, works
(補足: 最初に実行した場合にのみ機能します。それ以外の場合は未定義x()
であるために爆発します)。bar
次のように書き直してみましょう。
var t = new x();
alert(t.bar); // bar
それでは、コンストラクターを分析しましょう。これには、割り当てと戻りの 2 つのステートメントがあります。後者は文字列を返すため無視されます。したがって、次のように書き直すことができます。
x = function(){
this.bar = "bar";
};
var t = new x();
alert(t.bar); // bar
すべてが簡単に見えることを願っています。