考虑示例html代码:
<head>
....
<script src="/js/MyClass.js"></script>
<script src="/js/extend.js"></script>
<script>
$(document).ready(function($) {
var $obj=new MyClass();
$obj.run();
});
</script>
</head>
<body>
MyClass.js文件:
var MyClass=function()
{
this.run=function() {
alert("MyClass");
}
}
extend.js文件:
MyClass.prototype.run=function() {
alert("Extend");
}
为什么此代码会提醒“MyClass”而不是“Extend”?如何正确地重写(重载)类方法?
答案 0 :(得分:4)
这与如何 JS解析像<object>.<property/function>
这样的表达式有关。我之前已详细解释过这个问题,但这里是应用于您的案例的原理图淡化:
[ MyClass.run ]<=========================================================\ \
MyClass[run] ===> JS checks instance for property run | |
/\ || | |
|| || --> property found @instance, resolve value------------------------------| |
|| || | |
|| ===========> MyClass.prototype.run could not be found? check prototype | |
|| || | |
|| ||--> OR property found @MyClass.prototype, return---------------------| |
|| || | |
|| ==========> Object.prototype.run: not found check prototype? | |
|| || | |
|| ||--> property found @Object.prototype, return---------------------|-|
|| || |=|
|| =======> chech prototype of Object.prototype -> undefined~~~~~~~~~~|X|
|| \ /
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~< TypeError can't read property run of undefined
这是JS可以检查run
属性的所有地方。因为构造函数在实例(run
)上定义了this.run = function(){};
属性,所以查找永远不会超过第一步:“JS检查属性run
的实例”。
原型链从不发挥作用。
您询问是否以及如何重载 JS方法。简短的回答是:它不是,不是真的。重载是一种有效的OOP技术,在传统的基于类的OO模型中非常方便。 JS没有那种方式,它使用的是原型模型。试图强制原型系统像传统的OO语言一样工作 是可能的(由于原型系统的灵活性),但它需要付出太多的努力才能跟上,而且往往不值得它。
您可以将它与使用普通轿车/轿车来比较耕地。起初,你可能会这样做,但是在你遇到困难之前不会花很长时间,并且 打电话给拖拉机将你拖出现场。
如果您还想尝试一下,请按以下步骤操作:
function MyClass()
{
this.run = function()
{
console.log('child method');
var backup = this.run;//store reference to instance property
delete this.run;//delete instance property
this.run();//call again
//but now, the instance property is missing, JS will use the prototype
this.run = backup;//restore instance property
};
}
MyClass.prototype.run = function()
{
console.log('prototype run method');
};
var foo = new MyClass;
foo.run();
//logs:
//child method
//prototype run method
你可能会发现它很有用to take a look here,这是我之前的答案,其中我解释了JS更详细地解析表达式的方法。在我的答案的底部,我还添加了一些关于这个问题的链接,看看它们时可能也值得...
答案 1 :(得分:1)
只有当对象本身没有属性时才使用原型。
在您的情况下,您将run
放在对象本身上,这就是run
将解析的内容。
在某种程度上,你的MyClass会覆盖它自己的原型。
也许你想要
var MyClass=function(){};
MyClass.prototype.run = function() {
alert("MyClass");
}
var overridden = new MyClass();
overridden.run = function() {
alert("Extend");
}
这将是一个与其原型不同的方法的实例。
或者您可以链接原型来模拟类层次结构。
答案 2 :(得分:0)
你的MyClass构造函数正在覆盖原型。以下代码将依次提醒“MyClass”,“Extended”和“Overriden”。最后一个警告显示更改实例的功能不会改变原型的功能。
var MyClass=function()
{
this.run();
MyClass.prototype.run = function() { alert( "Extended" ) };
this.run();
this.run=function() {
alert("Overriden");
};
this.run();
};
MyClass.prototype.run = function() { alert( "MyClass" ); };
var myinstance = new MyClass();
alert( myinstance.run === MyClass.prototype.run );