即使已为其设置值,如何解决此未定义的错误?

时间:2019-08-19 13:35:07

标签: javascript

我遇到了这个问题,我找不到任何解决方案,也许你们可以帮忙?

为什么我不能访问this._activeScene?即使我已经为此设置了一个值,它也总是返回undefined。_activeScene

class SceneManager {
    constructor() {
        this._activeScene = null;
    }

    init() {
        let loop = setInterval(function() {

            console.log(this._activeScene);
            // Returns undefined.

            if(this._activeScene != null) {
                const self = this._activeScene;
                self.options.update();
                self.options.render();
            }
        }, 16.66);
    }

    setScene(scene) {
        this._activeScene = scene;
        this._activeScene.options.initialize()
    }

    get activeScene() {return this._activeScene;}
}

let sceneManager = new SceneManager();
sceneManager.init();

let gameScene = new Scene();

sceneManager.setScene(gameScene);

2 个答案:

答案 0 :(得分:2)

所以这是范围的问题,当您创建匿名函数时,它在全局范围E.G function(){};中,而不是类实例的范围。 这是使用箭头功能() => {}的情况之一,因为它们在创建它们的作用域中运行,但是,箭头功能是ES6功能,因此如果您需要在没有ES6的情况下使用它,则可以使用{{3 }}方法

ES6版本

let loop = setInterval(()=>{ // using arrow functions

    console.log(this._activeScene);
    // Returns undefined.

    if(this._activeScene != null) {
        const self = this._activeScene;
        self.options.update();
        self.options.render();
    }
}, 16.66); // not sure you can have 16.66 milliseconds

非ES6使用.bind

let loop = setInterval((function() {

    console.log(this._activeScene);
    // Returns undefined.

    if(this._activeScene != null) {
        const self = this._activeScene;
        self.options.update();
        self.options.render();
    }
}).bind(this), 16.66); 
 // using .bind create a pointer to the function in the scope of the given var 
 // so in this case we're putting the function in the scope of this 
 // not sure you can have 16.66 milliseconds

答案 1 :(得分:-1)

在这种情况下,

this不是类实例。这里的问题是范围。

最实际的正确解决方案是使用箭头函数,它们不绑定自己的作用域,而是从父对象继承(在本例中为SceneManager的实例)。

代码如下:

class SceneManager {
    constructor() {
        this._activeScene = null;
    }

    init() {
        // As suggested by Liam
        // ES6 arrow functions will automatically inherit the current scope
        // as their scope
        let loop = setInterval(() => {

            console.log(this._activeScene);
            // Will no longer output undefined, will output null instead

            if(this._activeScene != null) {
                const self = this._activeScene;
                self.options.update();
                self.options.render();
            }
        }, 16.66);
    }

    setScene(scene) {
        this._activeScene = scene;
        this._activeScene.options.initialize()
    }

    get activeScene() {return this._activeScene;}
}

let sceneManager = new SceneManager();
sceneManager.init();

let gameScene = new Scene();

sceneManager.setScene(gameScene);

其他“较旧”的解决方案是使用let that = this;技巧,这是一种众所周知的转移范围的方法。

class SceneManager {
    constructor() {
        this._activeScene = null;
    }

    init() {
        let that = this;
        let loop = setInterval(function() {

            console.log(that._activeScene);
            // now outputs null

            if(that._activeScene != null) {
                const self = that._activeScene;
                self.options.update();
                self.options.render();
            }
        }, 16.66);
    }

    setScene(scene) {
        this._activeScene = scene;
        this._activeScene.options.initialize()
    }

    get activeScene() {return this._activeScene;}
}

let sceneManager = new SceneManager();
sceneManager.init();

let gameScene = new Scene();

sceneManager.setScene(gameScene);