3

私はこのJavascriptコンストラクターを持っています-

function TestEngine() {
    this.id='Foo';
}

TestEngine.prototype.fooBar = function() {
    this.id='bar';
    return true;
}

TestEngine.prototype.start = function() {
    this.fooBar();
}

TestEngine.prototype.startMethod = function() {
    inter = setInterval(this.start, 200);
}

var test = new TestEngine();
test.startMethod();

このエラーが発生します-

Uncaught TypeError: Object [object global] has no method 'fooBar' 

試してみたところ、内からconsole.log呼び出すと、オブジェクトを指していることがわかりました。なんでそうなの?this.startsetIntervalthiswindow

4

3 に答える 3

4

thisポインタは、コンテキストに応じて、次のいずれかを指すことができます。

  1. コンストラクター関数(前にある関数呼び出しnewthisでは、新しく作成されたコンストラクターのインスタンスを指します。
  2. 関数がオブジェクトのメソッドとして呼び出されると(たとえばobj.funct()this、関数内のポインターはオブジェクトを指します。
  3. 、またはthisを使用して、ポイントを明示的に設定できます。callapplybind
  4. 上記のいずれでもない場合、thisポインタはデフォルトでグローバルオブジェクトを指します。ブラウザでは、これがwindowオブジェクトです。

あなたの場合、あなたはthis.start内部を呼んでいsetIntervalます。ここで、このダミーの実装について考えてみましょうsetInterval

function setInterval(funct, delay) {
    // native code
}

startと呼ばれていないことを理解することが重要this.startです。と呼ばれていfunctます。これは、次のようなことをするようなものです。

var funct = this.start;
funct();

これらの関数はどちらも通常は同じように実行されますが、小さな問題が1つありthisます。2番目のケースではポインターがグローバルオブジェクトを指しthis、最初のケースでは現在のオブジェクトを指します。

重要な違いは、this内部のポインタについて話していることですstart。検討:

this.start();           // this inside start points to this
var funct = this.start;
funct();                // this inside funct (start) point to window

これはバグではありません。これがJavaScriptの仕組みです。オブジェクトのメソッドとして関数を呼び出すと(上記の2番目のポイントを参照)、this関数内のポインターはそのオブジェクトを指します。

2番目のケースでfunctは、オブジェクトのメソッドとして呼び出されていないため、デフォルトで4番目のルールが適用されます。したがってthis、を指しwindowます。

この問題startは、現在のthisポインターにバインドしてからsetInterval、次のように渡すことで解決できます。

setInterval(this.start.bind(this), 200);

それでおしまい。この説明が、JavaScriptの素晴らしさについてもう少し理解するのに役立つことを願っています。

于 2013-03-23T13:56:46.740 に答える
3

これがjavascriptでOOPを行うためのきちんとした方法です:

//Global Namespace:
var MyNamespace = MyNamespace || {};

//Classes:
MyNamespace.MyObject = function () {

    this.PublicVar = 'public'; //Public variable
    var _privatVar = 'private'; //Private variable

    //Public methods:
    this.PublicMethod = function () {
    }

    //Private methods:
    function PrivateMethod() {
    }

}

//USAGE EXAMPLE:
var myObj = new MyNamespace.MyObject();
myObj.PublicMethod();

このようにして、メソッドと変数を名前空間/クラスにカプセル化して、使用と保守をはるかに簡単にします。

したがって、次のようにコードを記述できます。

    var MyNamespace = MyNamespace || {};

    //Class: TestEngine
    MyNamespace.TestEngine = function () {

        this.ID = null;
        var _inter = null;

        //Public methods:
        this.StartMethod = function (id) {
            this.ID = id;
            _inter = setInterval(Start, 1000);
        }

        //Private methods:
        function Start() {
            FooBar();
            console.log(this.ID);
        }

        function FooBar() {
            this.ID = 'bar';
            return true;
        }

    }

    //USAGE EXAMPLE:
    var testEngine = new MyNamespace.TestEngine();
    testEngine.StartMethod('Foo');
    console.log(testEngine.ID);

最初は、IDは「Foo」に設定されています。1秒後、IDは「bar」に設定されます。

すべての変数とメソッドがTestEngineクラス内にカプセル化されていることに注意してください。

于 2013-03-19T12:26:05.913 に答える
2

これを試して:

function TestEngine() {
    this.id='Foo';
}

TestEngine.prototype.fooBar = function() {
    this.id='bar';
    return true;
}

TestEngine.prototype.start = function() {
    this.fooBar();
}

TestEngine.prototype.startMethod = function() {
    var self = this;
    var inter = setInterval(function() {
       self.start();
    }, 200);
}

var test = new TestEngine();
test.startMethod();

setIntervalstartウィンドウコンテキストで関数を呼び出します。これは、start実行されると、this内部start関数がオブジェクトを指すことを意味しwindowます。また、ウィンドウオブジェクトには呼び出されるメソッドがなくfooBar、エラーが発生します。

匿名関数アプローチ:

関数を渡し、そこanonymous functionからsetInterval関数を呼び出すことをお勧めします。これは、関数がを使用する場合に役立ちますthis

私がやったことは、一時変数を作成し、TestEngineインスタンスをポイントし、それを使用して関数を呼び出すときにself割り当てられました。thisself.start()

startこれで関数内でthis、testInstanceをポイントし、すべてが期待どおりに機能します。

バインドアプローチ:

Bind作業が楽になり、コードの可読性も向上します。

TestEngine.prototype.startMethod = function() {
  setInterval(this.start.bind(this), 200);
}
于 2013-03-19T11:47:44.320 に答える