1

なぜ私が得ているのか誰かが私に説明できますか:

キャッチされていない TypeError: 未定義の game.js:48 のプロパティ 'canvas' を読み取れません

キャッチされていない TypeError: 未定義の game.js:4 のメソッド 'resize' を呼び出せません

何らかの理由で this.stage が start 関数の範囲外にあるようです。

//index.js
var game;
function init()
{
    game    = new Game(document.getElementById('canvas'));
}
function resize()
{
    game.resize();
}

_

//game.js
function Game(canvas)
{
    this.canvas = canvas;
    this.stage  = null;
    this.loader = null;

    this.scaleCanvas();
    this.initCreateJS();
    this.loadAssets();
}

Game.prototype =
{
    resize: function()
    {
        this.scaleCanvas(this.canvas);
        this.level.resize(this.canvas.width, this.canvas.height);
        this.stage.update();
    },
    scaleCanvas: function()
    {
        this.canvas.width   = window.innerWidth;
        this.canvas.height  = window.innerHeight;
    },
    initCreateJS: function()
    {
        this.stage  = new createjs.Stage(this.canvas);
        createjs.Ticker.setFPS(30);
        this.stage.enableMouseOver(10);
        if(createjs.Touch.isSupported())
        {
            createjs.Touch.enable(this.stage);
        }
    },
    loadAssets: function()
    {
        manifest = [
            {src:"base.png", id:"base"},
            {src:"logo.png", id:"logo"}
        ];

        this.loader = new Loader(manifest, this.start);
    },
    start: function()
    {
        this.level = new Level(4,4,this.stage.canvas.width,game.stage.canvas.height);
        this.level.randomLevel();
        this.level.print();

        game.stage.addChild(this.level);
        game.stage.update();
    }
};
4

1 に答える 1

0

このことを考慮:

var Foo = function(val) {
  this.val = val;
}
Foo.prototype.log = function() {
  console.log('Me haz ' + this.val);
}

ここでは、非常に単純なクラスを定義Fooしました。コンストラクター関数でパラメーターを という名前のプロパティに割り当て、で定義されたこの値valを処理する単一のメソッドを使用します。特別なことは何もありません:logFoo.prototype

var foo = new Foo(42);
foo.log(); // Me haz 42

次に、単純な関数を定義します。これは、別の関数をパラメーターとして取り、この関数を呼び出します。このようなもの:

var fooCaller = function(cb) { cb(); }
fooCaller(function() { 
  console.log('I am called'); 
});

簡単ですよね。しかし今、事態は突然複雑になります。

fooCaller(foo.log); // Me haz undefined

何?明らかに正しい関数が呼び出されています (したがってMe haz...) - しかし、なぜthis.valがありundefined42そこにないのでしょうか? foo.log直接の呼び出しと呼び出し元の関数を介した呼び出しの間で何が変わったのですか?

違いはthisです。JavaScript のユニークな機能は、本体に触れることなくthis同じ関数のコンテキスト ( によって参照されるオブジェクト) を切り替える機能です。関数を呼び出す方法だけが重要です。Function.prototype.callFunction.prototype.applyの値を明示的に設定できる特別なメソッドが 2 つあります。例えば:this

var bar = new Foo(34);
bar.log(); // Me haz 34
bar.log.call(foo); // Me haz 42

ご覧のとおり、オブジェクトを(プロパティは 34 に等しい) から にcall切り替えました。どのオブジェクトが関数を「所有」しているかは問題ではないことに注意してください。thisbarvalfoo


それでは、独自のコードに戻りましょう。この線...

new Loader(manifest, this.start);

...明らかにバグがあります。バインドされていないオブジェクトメソッドをコールバックとして渡すことは、ほとんどの場合悪い考えです。この場合、Loader は最終的にthis.start- に格納されている関数を呼び出しますが、呼び出されると、this別のオブジェクトを指します。

これを防ぐには、コンテキストをバインドする必要があります:new Loaderの現在の値によって定義される別の関数に渡しますthis。最も簡単な方法は、Function.prototype.bindを使用することです:

new Loader(manifest, this.start.bind(this));

this...基本的に、 (現在の値で定義された)の固定値を持つ別の関数を作成します。


これは非常に広範ではありthisますが、JavaScript でどのように機能するかをざっと見ただけです (機能に関してだけでなく、しゃれは意図されていません )))。この回答を確認することをお勧めします-そしてそれに記載されている記事は、確かに非常に啓発的です。)

于 2013-11-12T13:01:44.413 に答える