【问题标题】:JavaScript Inheritance and HoistingJavaScript 继承与提升
【发布时间】:2017-03-23 21:28:55
【问题描述】:

在我当前的 Web 项目中,我正在处理多个 JavaScript 文件,每个文件都包含从其他类型继承的类型定义。所以在任何给定的文件中,我都可以有类似 ...

function Type(){
    ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;

...ParentType 在另一个文件中类似声明:

function ParentType(){
    this.data = "";    
}    

由于在 <head> 标记中处理许多 JavaScript 文件变得很麻烦,我编写了一个 bash 脚本来将这些文件连接成一个文件(称为 master.js)。这样,我可以在我的 HTML 中链接单个文件。

对于只有一个子类型的类型,无论我的文件的串联顺序如何,原型链都会正确构建。也就是说,这个sn-p ...

function ParentType(){
    this.data = "";
}

function Type(){
    ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;

... 行为与此 sn-p 相同:

function Type(){
    ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;

function ParentType(){
    this.data = "";
}

当我在任一情况下创建Type 的实例时,ParentType.prototype.isPrototypeOf(typeobj) 返回 true(其中typeobj 是我的Type 实例)。

但是,当我将另一种类型添加到“原型链”的末尾时,它仅在文件按顺序连接时才有效,即:

function ParentType(){
    this.data = "";
}

function Type(){
    ParentType.call(this);
}
Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;

function ChildType(){
    Type.call(this);
}
ChildType.prototype = Object.create( Type.prototype );
ChildType.prototype.constructor = ChildType;

... 否则,链条会“断裂”。我猜测为什么这在单子场景中是可以的,因为这两个类型定义都被提升了,并且只有一组 statements 需要担心原型链。但是对于多链原型链,如果语句乱序,链就无法正常连接。

所以我真正要问的是,有没有一种方法可以在 JavaScript 中实现继承,而不管文件连接的顺序如何?我的第一个想法是 @987654333 @ 和 extends 的做事方式,但后来我了解到,即使 class 定义也没有被提升!

注意:我所说的“作品”是指子类型从(所有)它们的父类继承函数/值,并且isPrototypeOf 在检查其任何父类的原型时为任何对象返回 true。

【问题讨论】:

    标签: javascript inheritance prototype hoisting


    【解决方案1】:

    对于多链接原型链,如果语句乱序,则链无法正常连接。

    是的。您需要先设置Type.prototype,然后才能使用它来创建ChildType.prototype。这与函数声明的提升无关。

    有没有一种方法可以在 JavaScript 中实现继承,而不管我的文件连接的顺序如何?

    嗯,你可以使用Object.setPrototypeOf

    function ChildType(){
        Type.call(this);
    }
    Object.setPrototypeOf(ChildType.prototype, Type.prototype);
    
    function Type(){
        ParentType.call(this);
    }
    Object.setPrototypeOf(Type.prototype, ParentType.prototype);
    
    function ParentType(){
        this.data = "";
    }
    

    但是,您真的很想避免这种方法,并且像这样依赖提升是一种非常糟糕的做法,因此您确实应该修复您的连接脚本以使用正确的顺序。或者使用为您计算依赖关系的模块系统。

    我的第一个想法是 classextends 做事方式,但后来我了解到即使 class 的定义也没有提升!

    That's a good thing。只需将它们视为纯粹的糖 - 您始终需要按照层次结构以正确的顺序设置它们。

    【讨论】:

    • +1 用于回答实际问题,这几乎就是我想要的(“探索我的其他选择”)。除非我想使用外部源,否则似乎没有什么好的方法可以避免改进我的脚本。
    【解决方案2】:

    一种方法是为每种类型声明一个静态初始化器。

    但是,这仅在执行运行时才有可能(通过Object.crate 或通过赋值),因此我们又回到了起点。如果您的文件确实以随机顺序连接,那么您应该使用更复杂的机制和一种“工厂”函数,该函数将在类型出现时创建它们并将子类型“搁置”直到创建它们的父类型。

    仅用于说明目的的简化示例:

    function factory(precondition, callback)
    {
         if( !this.registry ) this.registy = [];
         if( !precondition || this.registry[precondition] ) 
             this.registry[callback()] = true;
         else setTimeout(function(){factory(precondition, callback);}, 100);
    }
    
    factory('Type', function()
    {
         Window.ChildType = function(){}
         return 'ChildType';
    });
    
    factory(null, function()
    {
         Window.Type= function(){}
         return 'Type';
    });
    

    【讨论】:

      【解决方案3】:

      函数被提升,所以它们可能是无序的,但链接原型的调用必须是有序的。

      如果它们出现故障,托管后您的代码将如下所示。

      function ParentType(){
        this.data = "";
      }
      
      function Type(){
          ParentType.call(this);
      }
      
      function ChildType(){
          Type.call(this);
      }
      ChildType.prototype = Object.create( Type.prototype );
      ChildType.prototype.constructor = ChildType;
      
      Type.prototype = Object.create( ParentType.prototype );
      Type.prototype.constructor = Type;
      

      也就是说,将ChildType.prototype 链接到Type.prototype,然后覆盖Type.prototype 以将其链接到ParentType.prototype

      没有办法让这个工作无序,JavaScript 继承依赖于那些按顺序调用的代码行。

      【讨论】:

      • 我已经知道了。我要问的是是否有一种方法可以在代码顺序无关紧要的情况下实现继承。
      • 如果您已经知道,为什么您的问题甚至提到托管?
      猜你喜欢
      • 1970-01-01
      • 2012-03-12
      • 2012-10-13
      • 2019-02-09
      • 1970-01-01
      • 2013-11-07
      • 2011-06-10
      • 2014-08-08
      • 1970-01-01
      相关资源
      最近更新 更多