2

私はオンラインチュートリアルからJSを学ぼうとしています-http ://ejohn.org/apps/learn/#33、そこでJSコードをテストできます。入れ子関数を他の関数内のメソッドとして理解しようとしています。また、「this」キーワードが何を参照しているのかを理解しようとしています。上記のサイトコードを下から配置すると、機能しないのはなぜですか?誰かがJSのその側面を説明できますか?

function Ninja(name){
  this.name = name;
  this.changeName = function(newname) {
    this.name = newname;
    this.anotherFunction = function(newname2) {
      this.name2 = newname2;
    }
  }
}

var ninja = new Ninja("John");
assert( ninja.name == "John", "The name has been set on initialization" );

// ninja.anotherFunction("Luken");
// ninja.changeName.anotherFunction("Luken");
// Why both above functions doesn't work?

assert(ninja.name2, "It works?");

ninja.changeName("Bob");
assert( ninja.name == "Bob", "The name was successfully changed." );
4

2 に答える 2

3

の値はthis、関数が定義されたときではなく、関数が呼び出されたときに決定されます。したがって、コードでは、次の値を変える必要があります。が呼び出されthisたときninja.changeName()は、の値を指定しないためthis、未定義か、現在の値のいずれかになります。

一方new、演算子thisは関数を呼び出す前に設定しますNinja

あなたがする必要があるのは、thisinsideの値を「保存」して、内部関数がそれを使い続けるようにすることです(呼び出されたときにNinjaランダムな値が入っていたのではなく)。thisこれを行うことは、思ったよりも簡単です。

function Ninja(name){
  this.name = name;

  var self = this; // Create a hidden reference to "this" that is only visible in
                   // any functions defined before we return

  self.changeName = function(newname) {
    self.name = newname;
    self.anotherFunction = function(newname2) {
      self.name2 = newname2;
    }
  }
}

これが機能するのは、関数を定義するときにJavaScriptがコンテキスト(=到達可能なすべての変数)のコピーを保持するためです。

于 2012-10-03T13:25:09.620 に答える
1

それはかなり簡単です:

function Ninja(name)
{//this points to Ninja object inside constructor scope
    this.name = name;
    this.changeName = function(newname)
    {//method of Ninja, this points to context object, ie Ninja
        this.name = newname;//accesses the name property of Ninja
        this.anotherFunction = function(newname2)
        {//defines new method for this ==> Ninja object
            this.name2 = newname2;//context object is Ninja
        };
    };
}
var foo = new Ninja('foobar');
foo.name;//foobar
foo.changeName;//function, is defined in constructor
typeof foo.anotherFunction//undefined because it's assigned when the changeName method is called!
foo.changeName('Me');
foo.name;//Me
foo.anotherFunction('You');//works: changeName was called, and assigned anotherFunction to foo (instance of Ninja)
foo.name2;//You

何が起こったのか:changeNameメソッドを呼び出すことにより、単純anotherFunctionに定義され、に割り当てられましたthis。その時点でオブジェクトをthis参照していたため、メソッドは、メソッドが呼び出されNinjaたインスタンスに割り当てられました。メソッドを呼び出す前は、メソッドは単に存在していませんでした。NinjachangeNamechangeNameanotherFunction

これは役に立たないか愚かに見えるかもしれませんが、それは理にかなっています。覚えておく必要があるのは、関数/メソッドは本質的にスタンドアロンオブジェクトであるということです。このコードでは、それらはたまたまプロパティ/メソッドとして定義されていますが、そのように使用する必要はありません。上記のコードに戻ります。

foo.name;//Me
bar = {};//some object
foo.changeName.apply(bar,['You']);
foo.name;//Me, nothing has changed, the changeName method was applied to the bar object
bar.name;//You, in the apply call, this pointed to bar, not foo
typeof bar.anotherFunction;//function
//You could even create the anotherFunction globally:
//  JUST TO SHOW YOU CAN, THIS IS DANGEROUS
//  ONLY USE THIS IF YOU KNOW WHAT THE POSSIBLE CONSEQUESES ARE!
foo.changeName.call();//in global scope
typeof antoherFunction;//function ==> this function is now globally available

このメソッドは、任意のchangeNameオブジェクトに適用でき、新しいメソッドを追加したり、特定のインスタンスに特定のプロパティを変更/追加したりできます。

于 2012-10-03T13:32:47.110 に答える