访问类功能?

时间:2013-11-11 16:57:58

标签: javascript createjs

有人可以向我解释我为什么会这样做:

  

未捕获的TypeError:无法读取undefined game.js:48

的属性'canvas'      

未捕获的TypeError:无法调用undefined game.js的方法'resize':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();
    }
};

1 个答案:

答案 0 :(得分:0)

考虑一下:

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

这里我们定义了一个非常简单的类Foo:使用构造函数将其param分配给名为val的属性,并使用单个方法log处理Foo.prototype上定义的此值。 1}}。没什么特别的:

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和通过调用者函数调用之间有什么变化?

差异是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对象从barval属性等于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的函数(由其当前值定义)。


这虽然相当广泛,但只是快速浏览了this在JavaScript中的功能(不仅仅是关于功能,也没有双关语)))。我建议检查this answer - 以及其中提到的文章,他们肯定会很有启发性。 )