在JavaScript中理解简单的类模拟器

时间:2013-09-26 20:39:33

标签: javascript prototypal-inheritance

最近我开始学习更高级的JavaScript(至于我只使用jQuery执行一些简单的任务)并购买了一本Alex MaxCaw“JavaScript Web Applications”一书。第一章讨论创建简单的类模拟器。我理解几乎所有的东西,除了下面标有评论的两行代码:

var Class = function(parent) {

    var _class = function() {
        this.init.apply(this, arguments);
    };

    if(parent) {
        var subclass = function() {};
        subclass.prototype = parent.prototype;
        _class.prototype = new subclass();
    };

    _class.prototype.init = function() {};

    _class.fn = _class.prototype;

    //????
    _class.fn.parent = _class;

    //????
    _class._super = _class.__proto__;

    return _class;
};

谁能告诉我这两行的目的是什么?我会非常感激的。

2 个答案:

答案 0 :(得分:3)

浏览代码:

  • 类被定义为一个函数,它使用提供的参数调用init。这意味着您可以使用new使用标准构造函数语法调用它,例如。 var instance = new Thingy()并使用正确的init值调用this函数。
  • 如果您传入父类,则您的类会将该类的prototype属性添加到新空对象的原型链中,并将其用作 prototype属性。在现代浏览器中更简洁的方法是_class.prototype = Object.create(parent.prototype);
  • 定义了init函数。在创建_class实例后,可能会使用更有用的初始化代码覆盖这一点(或者应该更改代码以允许在创建类时传入init函数...或允许用于遍历原型链以查找其他init函数的实例。
  • 创建
  • _class.fn以提供对_class构造函数原型函数的引用。
  • 创建
  • _class.fn.parent以提供对构造函数的引用。如果您在其他上下文中应用原型并希望将引用返回到原型的构造函数,这可能很有用。
  • _class._super被赋予构造函数的内部非标准__proto__属性。请记住,构造函数是函数,在Javascript中,函数是对象。这意味着他们有自己的内部原型。早期对prototype的引用是分配给使用此构造函数创建的对象的原型而不是构造函数的原型本身。所有函数都继承自Function.prototype,这是他们获得bindapply等的地方。_super在这种情况下只是对Function.prototype的引用。

至于何时使用此类_super,可以想象如下:

function Maker(){                  //this will be called as a constructor, ie. with new 
  var fun = function(){};          //Make a function
  fun.__proto__ = this.__proto__;  //yuck. Set the function's this value to the instance
  return fun;                      //return the function
}

Maker.prototype={say:function(){console.log("Javascript is fun!.. And weird.")}};

var fun = new Maker();
fun.say()                   //"Javascript is fun!.. And weird."
console.log(fun.__proto__)  // Object{say:function}
console.log(fun.bind)       // undefined!!

哇!刚刚发生了什么? 实际上,您使用Object替换了函数内部原型。这允许您构建有趣的原型链,并以类似的方式与功能和对象进行交互。但请注意,与Function.prototype的链接已被切断,这就是我们无法访问bind的原因。但是,让我们用更多原型魔法修复它!

function FunctionConnector(obj){
  for (var prop in obj){
    if(obj.hasOwnProperty(prop){
      this.prop=obj.prop
    }
  }
}

FunctionConnector.prototype=Function.prototype;

Maker.prototype=new FunctionConnector({say:function(){
                                       console.log("Javascript is fun!.. And weird.")
                                      }});

var fun = new Maker();
fun.say()                   //"Javascript is fun!.. And weird."
console.log(fun.__proto__)  // Object{say:function}
console.log(fun.bind)       // function bind(){ [native code] }

现在FunctionConnector是什么?它接受一个对象,当作为构造函数调用时,返回一个对象,该对象具有传递的对象的所有属性并继承自Function.prototype。正如您所看到的,我们对bind的访问权已经恢复(当然,我们也可以使用我们原来的实施方式,只是Function.prototype.bind.call以我们的方式取得胜利。

有了这个新模式,你可能会更清楚代码中的_super,即它引用你正在构建的_class构造函数的内置原型(在我们的例子中是{的实例{1}}将是FunctionConnector)。此引用可用于在运行时修补原型,使用_super调用方法,或者通过引用对象调用其他任何内容。

这是因为你可能已经注意到有点hackish,特别是因为apply是非标准的。但如果你喜欢它允许的模式,它也有点整洁。如果你对Javascript继承的知识非常有信心,我建议你只做这样的事情,除非你负责你的整个代码库,否则我甚至不会这样做。

答案 1 :(得分:-1)

据我所知,fn只是prototype属性的别名

关于_super,那个用于引用你继承的“类”

以下是有关使用_super和js继承的更多信息:article