我正在尝试在对象之间创建某种继承:
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'
为什么doFooStuff
无法访问?你会推荐另一种方法,而不是使用$.extend
吗?
答案 0 :(得分:7)
$.extend(this, foo);
this
不是您从下面的函数返回的对象(实际上它不能是因为它是在此调用之后创建的),而是全局对象 - 检查MDN's introduction to the this
keyword。
您想做什么,有两种方法:
Copy all properties从foo
到您的bar
对象:
var bar = (function() {
…
return {…};
})();
$.extend(bar, foo);
您也可以直接在返回的对象上执行此操作:
return $.extend({…}, foo);
此模式的变体允许您覆盖foo
属性。将foo
复制到空对象中,然后将bar
属性写入其中:
return $.extend({}, foo, {…});
使用原型继承。 Create从foo
继承其属性的对象,然后将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();
}
即使您以某种方式设法扩展doFooStuff
,this
也不会在范围内。 )请记住,范围解析不涉及上下文对象。
那么解决方案是什么?好吧,我经常在类似情况下使用聚合:
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,
});
})();
是的,它是聚合,而不是继承。但那又怎么样?我仍然能够获得主要奖项 - 删除代码重复并且我能够控制子模块中父函数的使用。
答案 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
。
如果删除匿名函数减速,它将起作用。