JavaScript OOP 错误的 _this 值

标签 javascript oop this self

假设我们有以下代码:

var MyClass = (function(){
    var _this;

    function MyClass(inputVal){
        _this = this;
        this.value = inputVal;
    }

    MyClass.prototype.getValue = function(){
        return this.value;
    }

    MyClass.prototype.getValue2 = function(){
        return _this.value;
    }

    return MyClass;
})();

让我们创建该类的两个实例:

var instance1 = new MyClass(10);
var instance2 = new MyClass(20);

现在,如果我们 console.log() 我们看到的值:

instance1.getValue();   // 10
instance1.getValue2();  // 20

var MyClass = (function(){
    var _this;

    function MyClass(inputVal){
        _this = this;
        this.value = inputVal;
    }

    MyClass.prototype.getValue = function(){
        return this.value;
    }

    MyClass.prototype.getValue2 = function(){
        return _this.value;
    }

    return MyClass;
})();


var instance1 = new MyClass(10);
var instance2 = new MyClass(20);


console.log(instance1.getValue());
console.log(instance1.getValue2());

为什么会发生这种情况?显然,_this 变量获取了最新创建的实例属性。如何解决这个问题?我需要保留的副本。谢谢!

编辑:

真实情况是这样的

var HoverEffects = (function(){
    var _this;

    function HoverEffects($nav){
        _this = this;
        this._$activeNav = $nav.siblings('.active_nav');
        this._$hoverableLis = $nav.find('>li');
        this._$activeLi = $nav.find('>li.active');

        if(!$nav.length || !this._$hoverableLis.length || !this._$activeNav.length || !this._$activeLi.length) return;

        if(this._$activeNav.hasClass('bottom')){
            this._$activeNav.align = 'bottom';
            this._$activeLi.cssDefault = {
                left: this._$activeLi.position().left,
                width: this._$activeLi.width()
            };
        }
        else if(this._$activeNav.hasClass('left')){
            this._$activeNav.align = 'left';
            this._$activeLi.cssDefault = {
                top: this._$activeLi.position().top,
                height: this._$activeLi.height()
            };
        }
        else{
            return;
        }

        this._$hoverableLis.hover(
            function(){

                // How to set the correct this inside this function?
                if(this._$activeNav.align === 'bottom'){
                    this._$activeNav.css({
                        left: $(this).position().left,
                        width: $(this).width()
                    });
                }
                else if(this._$activeNav.align === 'left'){
                    this._$activeNav.css({
                        top: $(this).position().top,
                        height: $(this).height()
                    });
                }

            },

            function(){
                // Same here, wrong this
                this._$activeNav.css(this._$activeLi.cssDefault);
            }
        );
    }

    return HoverEffects;
})();

var sideNavHoverMagic = new HoverEffects($('#side-navigation'));
var primaryNavHoverMagic = new HoverEffects($('#primary-navigation'));

最佳答案

Why is that happening?

每次调用new MyClass时,_this = this都会运行。第二次覆盖第一次。

所以_this指的是new MyClass(20),这意味着当您从any调用getValue2MyClass 实例,20 将被返回,因为所有 MyClass 实例都引用相同的 _this值。


基于对该问题的评论:

如果您尝试传递绑定(bind)到适当上下文的函数,有多种方法可以确保 this 引用正确的对象。在继续之前,请阅读"How does the 'this' keyword work?" ,因为我没有理由在这里重复所有内容。

如果您要绑定(bind)事件回调(例如在构造函数中):

function Example(something) {
    something.addEventListener(..event.., this.callback, false);
}
Example.prototype.callback = function () {
    this.doStuff();
    this.doMoreStuff();
};

回调将具有错误的 this 值,因为它没有被称为 this.callback,它只是被称为:

fn = this.callback;
fn(); //no reference to this

您可以通过多种方式解决这个问题。

Function.prototype.bind

您可以为每个实例绑定(bind)各自实例上的回调。这非常简洁:

function Example(something) {
    //generate a new callback function for each instance that will
    //always use its respective instance
    this.callback = this.callback.bind(this);
    something.addEventListener(..event.., this.callback, false);
}
Example.prototype.callback = function () {
    this.doStuff();
    this.doMoreStuff();
};

那个=这个

您可以在构造函数内创建回调(闭包),并在构造函数内引用变量。

function Example(something) {
    //every Example object has its own internal "that" object
    var that = this;
    this.callback = function () {
        //this function closes over "that"
        //every instance will have its own function rather than
        //a shared prototype function.
        that.doStuff();
        that.doMoreStuff();
    }

    something.addEventListener(..event.., this.callback, false);
}

() => {} ( Fat Arrow Syntax )

如果您使用的是 ES2015,您可以使用“胖箭头”语法来创建不创建新上下文的 lambda:

function Example(something) {
    this.callback = () => {
        //the callback function doesn't create a new "this" context
        //so it referes to the "this" value from "Example"
        //every instance will have its own function rather than
        //a shared prototype function.
        that.doStuff();
        that.doMoreStuff();
    }

    something.addEventListener(..event.., this.callback, false);
}

关于JavaScript OOP 错误的 _this 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40510506/

相关文章:

c# - 'this'在C#语言中有什么用?

javascript - jQuery:如何在整个文档主体中全局获取我悬停的最里面的 dom 元素?

javascript - 当单击第二个或任何其他图像单选按钮时,第一个图像会更新

javascript - 我无法解释以下输出的结果

javascript - 在Javascript中,如何区分使用实际数据保存的对象和作为引用保存的对象?

java - 为什么下面代码的输出没有区别?

java - 在类中将关键字 this 与多个构造函数一起使用

javascript - React-Flux : how to integrate constants?

javascript - 如何更改第二次单击时的不透明度?

c# - 为什么派生类的虚方法不能使用