【问题标题】:Why is my Javascript parent scope overridden when declaring a subclass?为什么在声明子类时会覆盖我的 Javascript 父范围?
【发布时间】:2016-05-05 07:53:35
【问题描述】:

我有两个 javascript 类,一个继承自另一个,声明如下:

var Sup = (function(){
    var self;

    var sup = function(){
        self = this;
        self.type = 'Sup';
    };

    sup.prototype.getType = function(){
        return self.type;
    };

    return sup;
})();

var Sub = (function(){
    var self;

    var sub = function(){
        self = this;
        Sup.call(self);
        self.type = 'Sub';
    };

    sub.prototype = Object.create(Sup.prototype);
    sub.prototype.constructor = sub;

    return sub;
})();

当我实例化 Sub 时,它会覆盖其父类中的 self 值:

var sup = new Sup();
var sub = new Sub();
console.log(sup.getType());
console.log(sub.getType());

产量

Sub // I expected Sup
Sub

我有两个问题:

  • 这是为什么呢?我认为self,正如在Sup 中声明的那样,将充当与Sup 的每个实例相关联的私有变量。
  • 我喜欢将所有类定义包含在 (function(){...}) 中时的整洁感,但是当我这样做时,我需要在声明私有方法时使用 self 变量来访问类范围。

    例如:

    var Sup = (function(){
        //...
        function _getType(){
            return self.type; // 'this.type' is undefined here
        }
    })();
    

    我可以在保留封闭的(function(){})() 结构的同时解决这个问题吗?


编辑:回答如何调用(我称之为)“私有”方法

_getType 中,this 将引用Sup 而不是正在创建的对象(例如sup),所以这解决了我的问题:

var Sup = (function(){
    var sup = function(){
        this.type = 'Sup';
    };

    sup.prototype.callPrivateGetType = function(){
        return _getType(this);
    };

    function _getType(that){
        return that.type;
    }
}

然后做

var sup = new Sup();
var sub = new Sub();
console.log(sup.callPrivateGetType());
console.log(sub.callPrivateGetType());

产量

Sup
Sub

【问题讨论】:

  • Sub 调用Sup.call(self) 时,Sup 中的thisSub 中的self 相同。只有一个对象,不是两个对象,它只能有一个type 属性。
  • "一个绑定到每个 Sup 实例的私有变量。" - 不。鉴于它是在构造函数之外声明的,它只不过是一个 static “私有”变量,保存最后构造的实例。
  • @Barmar @Bergi:谢谢,我想我把实例对象和它的工厂混为一谈了——sup 是实例,Sup 是工厂,self 指的是Sup .然后,如果我删除了 self,它并没有像我想象的那样做,还有什么办法可以访问从工厂创建的对象,就像在 _getType() 函数中一样?

标签: javascript oop inheritance scope


【解决方案1】:

self 不是“私有变量”,这些“类”也不是——因为 JavaScript 两者都没有。您可以非正式地谈论私有变量或类,但忘记这些概念并不能完美地从其他语言继承下来是非常危险的,正如您在这里所经历的那样。

self 是一个被getType 方法封闭的局部变量。评估是这样的:

  • 评估 Sup 分配右侧的 IIFE:
  • self 是一个局部变量(我们称之为SupSelf
  • sup构造函数已定义
  • getType 方法附在上面; getType 函数是一个闭包,关闭了 SupSelf
  • sup 原型从 IIFE 返回,并分配给 Sup

当您拨打sub.getType()时:

  • this 设置为sub,并评估Sup.prototype.getType
  • getType内部,self是封闭的SupSelf,它得到了Sup分配给它的值new Sup()。它无法读取Sub 内的值self,因为它不是本地的。

【讨论】:

  • 感谢您的解释,这很有帮助。但是,我不明白为什么在 original 对象sup = new Sup() 中实例化一个新的sub = new Sub() 会覆盖SupSelf,在我看来这应该是无关的。
  • 啊,这就是问题所在。是的,Sup.call(SubSelf) 实际上确实将SupSelf 设置为SubSelf;鉴于self 不是“实例变量”而是“类变量”(为熟悉起见),它们都打印SupSelf,最近一次调用(new Sub())将其分配为Sub ,覆盖之前的调用 (new Sup()) 在那里设置的内容。只有一个SupSelf 和一个SubSelf,而不是每个对象一个。
  • 我现在看到了区别,这是有道理的。我想我明白了如何使用我的私有方法_getType - 只需将“实例”范围作为参数传递,因为this 将引用“类”。谢谢!
  • 顺便说一句...你可以简单地做sub.constructor,如果你需要名字,如果你把var sub = function()...改成var sub = function Sub()...,你可以做sub.constructor.name - 不需要这个头痛:P
  • 是的,type 属性实际上只是在这里理解的一个示例 :) 感谢您的提示!
猜你喜欢
  • 1970-01-01
  • 2019-06-23
  • 1970-01-01
  • 2020-10-04
  • 2021-01-22
  • 2019-08-01
  • 2020-04-19
  • 1970-01-01
相关资源
最近更新 更多