创建模块化模式对象的继承

时间:2013-09-15 20:34:36

标签: javascript jquery

我正在尝试在对象之间创建某种继承:

var foo = (function(){

    function doFooStuff(){
        console.log(arguments.callee.name);
    }

    return {
        doFooStuff: doFooStuff
    }

})();

var bar = (function(){

    $.extend(this, foo);

    function doBarStuff(){
        console.log(arguments.callee.name);
        doFooStuff();
    }

    return {
        doBarStuff: doBarStuff,
    }

})();

bar.doBarStuff();
bar.doFooStuff(); //<-- Uncaught TypeError: 
                  //Object #<Object> has no method 'doFooStuff' 

http://jsfiddle.net/wRXTv/

为什么doFooStuff无法访问?你会推荐另一种方法,而不是使用$.extend吗?

4 个答案:

答案 0 :(得分:7)

$.extend(this, foo);

this不是您从下面的函数返回的对象(实际上它不能是因为它是在此调用之后创建的),而是全局对象 - 检查MDN's introduction to the this keyword

您想做什么,有两种方法:

    创建后,{li>

    Copy all propertiesfoo到您的bar对象:

    var bar = (function() {
        …
        return {…};
    })();
    $.extend(bar, foo);
    

    您也可以直接在返回的对象上执行此操作:

        return $.extend({…}, foo);
    

    此模式的变体允许您覆盖foo属性。将foo复制到空对象中,然后将bar属性写入其中:

        return $.extend({}, foo, {…});
    
  • 使用原型继承。 Createfoo继承其属性的对象,然后将bar属性写入其中:

        return $.extend(Object.create(foo), {…});
    

    现在foo之后发生变化时,您仍然可以在bar上访问这些新属性(除非它们被自己的属性遮挡)。请注意,旧版环境可能不支持Object.create,但您可以轻松地对其进行填充。


如@ raina77ow所述,您的doBarStuff功能也存在缺陷。 doFooStuff函数不在您的函数范围内,您无法更改它。您永远无法从foo模块访问私有声明的函数和变量,只能访问那些公开的函数和变量 - 如果确实需要它们,请考虑使用不同的模式或应用程序设计。但是,doFooStuff是导出的(公共)foo对象上的属性,从该对象继承(无论上述哪种方式)。因此,您也可以使用bar作为this.doFooStuff()的方法进行访问。

答案 1 :(得分:5)

您尝试使用显示模块,就像它是构造函数一样。因此,出于多种原因试图扩展this错误。我想,最引人注目的是,函数既不是用作构造函数(没有new)也不是它的上下文被改变。简单来说,this只是指向一个全局对象。

但这不是唯一的问题。考虑一下您的代码:

function doBarStuff(){
  console.log(arguments.callee.name);
  doFooStuff();
}

即使您以某种方式设法扩展doFooStuffthis也不会在范围内。 )请记住,范围解析不涉及上下文对象。

那么解决方案是什么?好吧,我经常在类似情况下使用聚合:

var foo = (function(){
    function doFooStuff(){
        console.log(arguments.callee.name);
    }
    return {
        doFooStuff: doFooStuff
    }
})();

var bar = (function(){
    var _super = foo;
    function doBarStuff(){
        console.log(arguments.callee.name);
        _super.doFooStuff();
    }
    // static parent: further changes on `foo` won't affect `bar`,
    // as $.extend takes the parent's current state
    return $.extend({}, _super, {
        doBarStuff: doBarStuff,
    });
    // dynamic parent: further changes on `foo` will affect `bar`,
    // as extended object now has `foo` in its prototype chain
    return $.extend(Object.create(_super), {
        doBarStuff: doBarStuff,
    });
})();

JS Fiddle

是的,它是聚合,而不是继承。但那又怎么样?我仍然能够获得主要奖项 - 删除代码重复并且我能够控制子模块中父函数的使用。

答案 2 :(得分:1)

您的代码存在的问题是$ .extend(this,foo)中的 this 是指窗口对象而不是foo 。匿名函数在窗口的上下文中运行。

我建议在javascript中使用经典继承的 John Resig 实现。 http://ejohn.org/blog/simple-javascript-inheritance/

摘录:

var Person = Class.extend({
 init: function(isDancing){
 this.dancing = isDancing;
 },
dance: function(){
 return this.dancing;
 }
});

var Ninja = Person.extend({
 init: function(){
  this._super( false );
 },
dance: function(){
 // Call the inherited version of dance()
 return this._super();
},
 swingSword: function(){
  return true;
 }
});

var p = new Person(true);
p.dance(); // => true

var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true

// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class

答案 3 :(得分:0)

这是因为这是一个匿名函数。这部分功能减速:

   var foo = (function(){

    function doFooStuff(){
        console.log(arguments.callee.name);
    }

    return {

        doFooStuff: doFooStuff
      }

   })();

您是否看到您正在立即调用此函数调用,并且最终无法在return语句中访问doFooStuff

如果删除匿名函数减速,它将起作用。