1

有人可以向我解释为什么我会得到:

未捕获的类型错误:无法读取未定义 game.js:48 的属性“画布”

未捕获的类型错误:无法调用未定义 game.js:4 的方法“调整大小”

似乎由于某种原因 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,以及一个log处理该值的方法Foo.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.valundefined,而不是42呢?foo.log直接调用和通过调用者 func之间发生了什么变化?

不同的是this。看,JavaScript 的一个独特特性是能够this为同一个函数切换上下文(由 引用的对象)而不触及其主体:只有调用函数的方式才重要。有两种特殊方法允许您显式设置 的值thisFunction.prototype.callFunction.prototype.apply。例如:

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

如您所见,call我已将this对象从bar(哪个val属性等于 34)切换到foo. 请注意,哪个对象“拥有”该函数不再重要。


现在让我们回到您自己的代码。这条线...

new Loader(manifest, this.start);

...显然是错误的:将未绑定的对象方法作为回调传递几乎总是一个坏主意。在这种情况下,Loader 最终会调用存储在其中的函数this.start——但当它调用时,this它将指向另一个对象。

为了防止这种情况,您需要绑定上下文:传递给new Loader另一个由 . 的当前值定义的函数this。最简单的方法是使用Function.prototype.bind

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

...这将基本上创建另一个具有固定值的函数this(由其当前值定义)。


这虽然相当广泛,但只是快速浏览一下thisJavaScript 中的函数(不仅仅是关于函数,不是双关语)))。我建议检查这个答案- 以及其中提到的文章,它们肯定会很有启发性。)

于 2013-11-12T13:01:44.413 回答