JavaScript中的类/实例方法重写
Class/instance method overrides in JavaScript
在JS中使用相同的名称定义类(静态)和原型方法是否普遍可以接受和合理?在下面的node.js
示例中,方法update
以这样的方式定义,并且示例工作得很好,但是是否有任何常见的情况下,这可能会导致问题,例如,在实例上调用update
会分派给类方法?
function Base(id, value) {
this.id = id;
this.value = value;
Base.objects[id] = this;
}
Base.objects = {};
Base.find = function(id, done) {
var err = null;
var obj = this.objects[id];
if (!obj) {
err = new Error("no obj found for id " + id);
}
done(err, obj);
};
Base.update = function(id, value, done) {
this.find(id, function(err, obj) {
if (err) {
done(err);
} else {
obj.update(value, done);
}
});
};
Base.prototype.update = function(value, done) {
this.value = value;
done();
};
试用:
new Base('aa', 1);
new Base('bb', 2);
Base.update('aa', 3, function(err) {
if (err) {
throw err;
}
});
Base.update('bb', 5, function(err) {
if (err) {
throw err;
}
});
console.log(Base.objects);
输出:{ aa: { id: 'aa', value: 3 }, bb: { id: 'bb', value: 5 } }
我不太确定你在问什么,但我想你想知道你是否要打电话:
(new Base('aa', 1)).update(3, function (err){ if (err) throw err;});
该可以调用Base.update
函数。
这个问题的答案当然是:No
Base.update
函数与Base.prototype.update
无关。函数,就像JS中的几乎所有东西一样,是一个对象。就像您使用new Base
创建的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{}
这意味着任何Base
实例的任何属性都必须位于该继承链上:要么定义在对象本身上,要么定义在Base.prototype
对象上,要么定义在所有对象的母体:Object
上。
在任何情况下都不会考虑函数对象 Base
。
那么,这到底是什么意思呢?
var x = new Base('x', 1);
console.log(x.update === Base.prototype.update);//true
console.log(x.update === Base.update);//false, of course
但是如果你要写:
x.update = Base.update;
然后重写原型,在x
上调用update
(这是Base
的一个实例),然后Base.update
将被调用。然而,它不会像预期的那样工作,因为它的调用上下文已经改变。this
现在引用x
和下面的语句:
this.find(...)
将不再工作,除非你也添加x.find = Base.find
。但是,现在我们在x.find
方法中遇到了类似的问题:
var obj = this.objects[id];
x
没有objects
属性…要解决这个问题,您必须添加x.objects = Base.objects
以使其全部工作。我们最后得到:
x = new Base('x', 1);
x.update = Base.update;
x.find = Base.find;
x.objects = Base.objects;
但是现在我们已经将Base
函数对象的所有属性赋值给Base
实例x
。这太愚蠢了,所以让我们删除它们:
delete(x.update);
delete(x.find);
delete(x.objects);
现在,x.update
将再次像预期的那样工作:实例本身不会掩盖原型方法,因此将调用原型方法。
这只是JS如何计算表达式以及如何扫描原型(和作用域)的快速浏览。我之前已经详细解释过了。这个链接的答案还包含更多的链接,每个链接的答案在某种程度上都与相同的事情相关(范围和原型链)。
JS是基于原型的语言。在这种语言中,从某个对象调用方法就是调用存储在该对象本身中具有该名称或在其__proto__
中的某个级别的函数。
您感兴趣的不匹配只可能在SomeObj.prototype==SomeObj
。如果你不做这样的事情,这将不会出现在任何时候。
- 将其中一个异步方法重写为使用promise的方法
- 从实例方法调用实例方法
- Javascript:在对象实例方法上使用apply()方法失败
- 我将如何创建一个带有私有变量的实例方法
- 用javascript在实例方法中实例化对象
- 绑定实例方法与包装匿名函数
- 如何在猫鼬.js子文档数组中定义实例方法
- 如何根据所选选项调用实例方法
- 如何在匿名函数中调用实例方法
- 在续集中使用实例方法
- 如何将实例方法添加到帆中的所有模型.js
- 如何在 Javascript 中同时拥有静态方法和实例方法
- 使用木偶.js访问生态模板中的实例方法
- 在 JavaScript 中修饰实例方法时出现问题
- 在Javascript中使用寄生继承,是否可以实现内省实例方法
- 使用私有实例方法实现 TS/JS 装饰器
- ES6+React组件实例方法
- 更改<对象>.原型的实例方法(通过上下文)
- 用于区分节点JS中模块/实例/方法变量的命名约定
- JavaScript中的类/实例方法重写