JavaScript中的类/实例方法重写

JavaScript中的类/实例方法重写,javascript,overriding,static-methods,Javascript,Overriding,Static Methods,在JS中用相同的名称定义类(静态)和原型方法是否普遍可以接受和合理?在下面的node.js示例中,方法update是以这样的方式定义的,该示例就像一个符咒一样工作,但是有没有常见的情况会导致问题,例如,在实例上调用update会分派给类方法 函数基(id、值){ this.id=id; 这个值=值; Base.objects[id]=这个; } Base.objects={}; Base.find=函数(id,完成){ var err=null; var obj=this.objects[id]

在JS中用相同的名称定义类(静态)和原型方法是否普遍可以接受和合理?在下面的
node.js
示例中,方法
update
是以这样的方式定义的,该示例就像一个符咒一样工作,但是有没有常见的情况会导致问题,例如,在实例上调用
update
会分派给类方法

函数基(id、值){
this.id=id;
这个值=值;
Base.objects[id]=这个;
}
Base.objects={};
Base.find=函数(id,完成){
var err=null;
var obj=this.objects[id];
如果(!obj){
err=新错误(“未找到id”+id的obj);
}
完成(err,obj);
};
Base.update=函数(id、值、完成){
this.find(id,函数(err,obj){
如果(错误){
完成(错误);
}否则{
目标更新(值,完成);
}
});
};
Base.prototype.update=函数(值,完成){
这个值=值;
完成();
};
试一试:

新基地('aa',1);
新基地('bb',2);
基本更新('aa',3,函数(err){
如果(错误){
犯错误;
}
});
基本更新('bb',5,函数(err){
如果(错误){
犯错误;
}
});
console.log(Base.objects);
输出:

{ aa: { id: 'aa', value: 3 }, bb: { id: 'bb', value: 5 } }

JS是基于原型的语言。在这种语言中,从某个对象调用方法正是调用该函数,该函数以该名称存储在对象本身或某个级别的
\uuuuuuu proto\uuuuu


您感兴趣的不匹配只有在
SomeObj.prototype==SomeObj
时才可能发生。如果你不想做这样的事情,这在任何时候都不会出现。

不完全确定你在问什么,但我认为你不知道是否要打电话:

(new Base('aa', 1)).update(3, function (err){ if (err) throw err;});
这可以调用
Base.update
函数

当然,这个问题的答案是:

Base.update
函数与
Base.prototype.update
无关。一个函数,就像JS中几乎所有的东西一样,是一个对象。就像使用
newbase
创建的
Base
实例一样。
Base
函数(恰好兼作构造函数)有自己的继承链:

Base //the object itself
  || Object.getPrototypeOf(Base)
  ====> Function (or function Empty(){} in chromium)
         || Object.getPrototypeOf(Object.getPrototypeOf(Base));
         ====> Object {}
创建新的
Base
对象时,该链如下所示:

x // Base instance itself
 ||
  --> Base.prototype //or Base {} <-- an object!
       ||
        --> Object{}
但如果你要写:

x.update = Base.update;
然后您已经覆盖了原型,并在
x
上调用
update
(这是
Base
的一个实例),然后将调用
Base.update

但是,它不会按预期工作,因为它的调用上下文已更改<代码>此引用了
x
以及以下语句:

 this.find(...)
将不再工作,除非同时添加
x.find=Base.find
。但是,现在我们在
x.find
方法中遇到了类似的问题:

var obj = this.objects[id];
x
没有
对象
属性。。。要解决这个问题,您必须添加
x.objects=Base.objects
,以使其全部正常工作。我们最终得到:

x = new Base('x', 1);
x.update = Base.update;
x.find = Base.find;
x.objects = Base.objects;
但是现在我们已经将
Base
函数对象的所有属性分配给
x
,一个
Base
实例。这太傻了,所以让我们删除它们:

delete(x.update);
delete(x.find);
delete(x.objects);
现在,
x.update
将再次按预期工作:实例本身不会屏蔽原型方法,因此将调用该方法


这只是简单介绍JS如何计算表达式以及如何扫描原型(和范围),最后这个链接的答案还包含更多的链接,每个链接都指向以某种方式与同一事物(范围和原型链)相关的答案。

我问的正是这个问题。谢谢你的全面回答。根据语言的不同,这种行为并不明显。Java根本不允许这样的重写(对于相同的参数),python允许这样的重写(尽管需要不同的参数),并且如果实例方法不可用(例如,动态删除),python将分派给类方法。因此,不仅看到它起作用是好的,而且理解为什么也是好的。@OlegS:我完全同意。。。看到某些东西起作用是很好的,但更好的是知道原因和方式!也就是说:如果您的背景是Java和Python,那么我建议您花一些时间来掌握基于原型的系统的怪癖。他们完全不同。这一点不明显的唯一原因是,JS是一种非常滥用的语言,可以强制使用更经典的OO风格,但它不喜欢。JavaScript构造函数和原型可能有点奇怪,我试图在下面的回答中解释它的行为:希望有帮助。
delete(x.update);
delete(x.find);
delete(x.objects);