4

コンストラクター関数内で自己実行 anon 関数を使用する場合のコンテキスト/スコープに関する簡単な質問があります。

次の作業コードを観察します。

function Foo() {
    this.height = 10;
    this.width = 10;
    this.init = function() {
        this.create();
    };
    this.create = function() {
        alert('test');
    };
} 

var span1 = new Foo();
span1.init();

アラートは予測どおりに表示されます。ただし、一番下で span1.init を呼び出したくありません。コンストラクター関数の init 関数を自己実行したいと思います。これにより、次のようなコードが得られます。

function Foo() {
    this.height = 10;
    this.width = 10;
    this.init = (function() {
        this.create();
    })();
    this.create = function() {
        alert('test');
    };
} 

var span1 = new Foo();

ただし、いくつかのグーグルの後、一見自己実行を使用するとグローバルスコープが与えられるため、 this.create はグローバルな意味では存在しません。

call/applyで何かをしなければならないと思いますが、何をどこで正確に行うかわかりません。

任意のポインタは非常に高く評価されます。

乾杯、広告。

4

5 に答える 5

2

Adi さん、この例で行ったことには 2 つの問題があります。最初の問題は、すぐに呼び出される関数内のthis === window.

2 番目の問題は、これらがすべて関数式であることです。そのため、それらはすべてインラインで定義されています。

function makeIt () {
    this.a = function () { this.b(); };
    this.b = function () { console.log("B"); };
}

これは、late-static バインディングのために機能します。これが意味することは、 の内部では、関数が呼び出される瞬間までaブラウザは何を参照しているのかわからないということです。次に、その正確な瞬間を参照するthisオブジェクトを見つけます。this

それ以外の場合は、変数を割り当てるのと同じです。

function makeIt () {
    this.a = this.b;
    this.b = "George";
}

そこでエラーになります。なんで?を割り当てている時点ではabまだ値がないためです。

function Foo () {
    this.init = (function (context) { context.change(); }(this));
    this.change = function () { doStuff(); };
}

では、この発言のどこが問題なのでしょうか? さて、すぐに呼び出す関数は、すぐに呼び出す関数です。つまり、問題を解決したとしても、 の値をパラメータとして内部スコープにthis渡すことで...this

...まだ存在しないものを実行するように求めています。

function Foo () {
    this.change = function () { doStuff(); };
    this.init = (function (context) { context.change(); }(this));
}

それはうまくいくはずです。...でも...

……なんでわざわざそんなことするの?のように、自動的に構築したいのに、なぜpublic initプロパティ (これは)を与えるのでしょうか?undefined

なぜinit undefinedですか?何も返さないため-関数を実行して関数initの戻り値に設定していますが、何も返していないため、に設定initされundefinedます。では、なぜinitそこにあるのでしょうか。

2 つのソリューション:

function Foo () {
    this.change = function () { doStuff(); };
    var init = function () { this.change(); };
    // other stuff......
    init();
}

また:

function Foo () {
    this.change = function () { doStuff(); };
    // other stuff....


    (function (context) {
       context.change();
       /* a bunch of other stuff that would be in init
          if there was no other stuff, why not just call this.change()? */
    }(this));
}

正直なところ、initが非公開で自動的に実行される場合、create本当に公開する必要があるのでしょうか? myObj.create();すでに作成された後に呼び出すつもりですか?

次のようなことをしてみませんか:

function Foo () {
    this.public1 = "Bob";
    this.public2 = 32;
    this.publicMethod = function () {};

    var create = function () { /* initialize here */ };
    create();
}

または繰り返しますが、それ以上のことをしている場合create:

function Foo () {
    this.public1 = "Bob";
    this.public2 = 32;
    this.arrayOfThings = [];
    this.publicMethod = function () {};

    var create = function () {},
        overclock = function () {},
        polish = function () {};

    // Initialize Everything
    (function (context) {
        var thing;
        for (/* ... */) {
            thing = create();
            polish(thing);
            context.arrayOfThings.push(thing);
        }
        overclock(context.arrayOfThings); 
    }(this));
}

これで、すべての関数、プロパティ、および変数を 1 つのスコープで取得し、初期化を別のスコープで取得しました。すべてのセットアップ ロジックは、最終的なオブジェクトのロジックから分離されています... ...そして入力パラメーターに基づいてオブジェクトを分岐するようなことを行うことができます (同じインターフェイスを維持しながら、取得したものに基づいて提供されたものを変更するポリモーフィック コンストラクターや、すべての設計図が含まれている自己完結型のファクトリ パターンなど)。 100% プライベートで囲まれています)、実際の割り当てが if と for の混乱のように見えることはありません。

完成したオブジェクトの外でセットアップを呼び出す必要はありません (つまり、他の誰も完成したオブジェクトでセットアップを呼び出して再作成/リセットすることはできません) this.initとにかく使用する匿名関数が 1 つだけだったのです。

于 2012-08-21T13:47:45.573 に答える
0

コンテキストを新しいクロージャに渡すことができます:

this.init = (function(ctx) {
    ctx.create();
})(this);

これは宣言された時点で実行されるため、代入する前init代入しないと機能しないことに注意してください。前の例では、両方の後に手動で呼び出され、割り当てられているため、これは問題ではありません。create initspan1.init()createinit

于 2012-08-21T12:56:28.217 に答える
0

私は何かが足りないかもしれませんが、おそらくあなたが望むのは:

function Foo() {
    this.height = 10;
    this.width = 10;
    this.init = function() {
        this.create();
    };
    this.create = function() {
        alert('test');
    };

    this.init();
} 

もちろん、同様に、init関数を完全に削除することも、非公開にすることもできます。例えば:

function Foo() {
    this.height = 10;
    this.width = 10;
    this.create = function() {
        alert('test');
    };

    this.create();
} 

さらに、関数が何も返さないため、が にthis.init = (function() {})();設定this.initされていることに注意してください。undefined

于 2012-08-21T13:02:21.280 に答える
0

それがどのように機能するか(デモを参照:http://jsfiddle.net/Jw8jz/1/):

function Foo() {
  this.height = 10;
  this.width = 10;

  this.init();
}

Foo.prototype = {
  init: function() {
    this.create();
  },

  create: function() {
    alert('test');
  }
};

var span = new Foo();

プロトタイプ プロパティの詳細をご覧ください。

于 2012-08-21T13:02:09.090 に答える
0

はい、call動作します(applyまったく使用しない別の引数パラメーターがあります):

this.init = (function() {
    this.create();
    // return something?
}).call(this);
于 2012-08-21T13:04:39.960 に答える