我想知道一旦它构建完成后我们还能改变它吗?
var O = function(someValue){
this.hello = function(){
return "hello, " + someValue;
}
}
O.prototype.hello = function(){
return "hhhhhhh";
}
var i = new O("chris");
i.hello(); // -> this still returns the old definition "hello, chris"
javascript语句O.prototype.hello = function(){....}
不会覆盖并重新定义hello函数行为。这是为什么 ?我知道如果您尝试重用参数someValue
将会出现类型错误。
// this will fail since it can't find the parameter 'someValue'
O.prototype.hello = function(){
return "aloha, " + someValue;
}
我想知道为什么它允许在运行时添加函数,如
O.prototype.newFunction = function(){
return "this is a new function";
}
i.newFunction(); // print 'this is a new function' with no problem.
但不允许您在定义后更改定义。
我做错什么了吗 ?我们如何覆盖和重新定义类中的函数?有没有办法重用我们之前传递的参数来创建对象?在这种情况下,如果我们想要向其扩展更多功能,我们如何重新使用someValue
。
答案 0 :(得分:23)
当您使用new
时,构造函数中this
的值指向新创建的对象(有关new
如何工作的详细信息,请查看this answer }和this answer)。因此,您的新实例i
具有hello
功能。当您尝试访问对象的属性时,它会沿着原型链向上走,直到找到它为止。由于hello
存在于对象的实例上,因此无需走原型链来访问返回hello
的{{1}}版本。从某种意义上说,您已经覆盖了实例中的默认实现。
如果您未在构造函数中将hhhhhhhh
分配给hello
,则可以看到此行为:
this
你正在做的事情是倒退。原型基本上提供了某种东西的“默认”形式,您可以在每个实例的基础上覆盖它。仅当在对象上找不到您要查找的属性时,才使用默认表单。也就是说,JavaScript将开始走向原型链,看看它是否能找到与您正在寻找的匹配的属性。它找到它,它将使用它。否则,它将返回var O = function(someValue) {
}
O.prototype.hello = function(){
return "hhhhhhh";
}
var i = new O("chris");
console.log(i.hello()); //this prints out hhhhhhh
。
在第一种情况下你基本上拥有的内容如下:
undefined
因此,当您执行Object.prototype.hello (not defined; returns "undefined")
|
+----O.prototype.hello (returns "hhhhhhhh")
|
+----i.hello (returns "hello, chris")
时,JavaScript会在i.hello
上看到hello
属性并使用该属性。现在,如果您没有明确定义i
属性,则基本上具有以下内容:
hello
这意味着您可以在原型中提供默认实现,然后覆盖它(在某种意义上它就像子类)。您还可以做的是通过直接修改实例来修改每个实例的行为。你在原型上拥有的Object.prototype.hello (not defined; returns "undefined")
|
+----O.prototype.hello (returns "hhhhhhhh")
|
+----i.hello (is "undefined", so JavaScript will walk up the chain until
it sees O.prototype.hello, which does have a defined value
it can use.)
版本是一种故障安全和后备。
编辑:您的问题的答案:
基于每个实例的覆盖意味着您将属性或函数附加到特定实例。例如,你可以这样做:
hello
这意味着此行为特定于特定实例(即仅限于i.goodbye = function() {
return "Goodbye, cruel world!";
};
,而不是您可能已创建的任何其他实例。
如果你取出i
,那么你基本上有:
this
这等同于:
hello = function() {
return "hello, " + someValue;
}
因此,在这种情况下,window.hello = function() {
return "hello, " + someValue;
}
是对该函数的全局引用。这意味着hello
没有附加到任何对象上。
hello
,则 hello
可能未定义。我还谈到了JavaScript用来尝试解析对象属性的一般过程。正如我之前提到的,它涉及走原型链。
答案 1 :(得分:3)
使用O
创建new O("somename");
对象的实例时,您正在为新创建的对象分配实例方法。然后,当您为O
的{{1}}分配另一个同名方法时,该方法已被实例方法隐藏。所以:
prototype
JavaScript从链的底部开始,在找到名称匹配时停止。因此,它会停在Object.prototype.hello // undefined
|
O.prototype.hello // alternate function
|
i.hello // original function provided in constructor
,永远不会看到i.hello
。
JavaScript(从ECMAScript 5开始)实际上没有(据我所知)给你一个很好的方法来做私有变量,可以通过定义后添加的实例方法访问(添加 on 实例或O.prototype.hello
)。闭包可以帮助您完成大部分工作,但是如果您希望能够在闭包之外添加可以访问闭包变量的方法,则需要公开prototype
和/或get
方法来提供这些新方法。方法访问闭包变量:
set
您真的想阅读bobince's great answer on OOP in JavaScript了解有关此主题的更多信息。
答案 2 :(得分:1)
没有。你不能,但是这里有一个很好的例子,可以通过以不同的方式模式化你的继承来解决这个限制。
// Create a class
function Vehicle(color){
this.color = color;
}
// Add an instance method
Vehicle.prototype.go = function(){
return "Underway in " + this.color;
}
// Add a second class
function Car(color){
this.color = color;
}
// And declare it is a subclass of the first
Car.prototype = new Vehicle();
// Override the instance method
Car.prototype.go = function(){
return Vehicle.prototype.go.call(this) + " car"
}
// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"
var c = new Car("red");
c.go() // "Underway in red car"
答案 3 :(得分:1)
首先,您需要了解原型继承。
使用O
作为构造函数创建对象时,会发生以下情况:
O.prototype
对象的对象的秘密链接。引用O
个对象的属性时,首先在对象本身中查找这些属性。只有当对象本身没有属性时,它才会查看它的原型。
其次,您需要了解闭包。
someValue
是O
函数中定义的变量(不是属性)。它只能从同一函数中定义的其他东西(或O
函数中定义的任何函数)访问。因此,我们说“someValue
关闭”。您在O
之外定义的函数无法访问它。
要实现您想要的功能,您需要将someValue设置为属性(这使得它不像private
那样,更像是public
的东西。或者,您需要在someValue
的原始定义中定义需要访问O
的所有函数。
要更改i.hello
创建i
之后的内容,您需要直接设置对象的属性。
i.hello = function () { /* stuff */ };
答案 4 :(得分:0)
如果我没记错的话,作为对象直接成员的函数优先于该对象原型的同名成员。因此,O.prototype.hello
被O.hello
篡夺,即使前者在代码中稍后定义。
someValue
无法使用O.prototype.hello
的原因是因为someValue
的范围受限于构造函数以及在其中定义或执行的任何函数。由于O.prototype.hello
的定义超出了O
构造函数的范围,因此它不了解someValue
答案 5 :(得分:0)
这是因为当您访问Object的属性时,JavaScript会在进入其原型之前首先检查对象的属性。
这类似于Java的派生类重写基类功能。
为了更好地理解,请查看Inheriting properties
中的代码示例另请注意,在您的情况下someValue是构造函数的本地。 如果在其他函数中需要它,则应将其分配给构造函数中的this.someValue。
您可以在此处覆盖特定对象的hello函数,如下所示。但不是整个班级。
i.hello = function(){ console.log('even here someValue is not accessible');};
var O = function(someValue){
this.someValue = someValue;
this.hello = function(){
return "hello, " + someValue;
}
}
var i = new O("chris");
console.log(i.hello()); // prints hello, chris
i.hello = function() {
return 'Hi there '+ this.someValue;
}
console.log(i.hello()); // prints Hi there chris
var test = new O('Sujay')
console.log(test.hello()) // this still prints hello, Sujay
请注意,这里我们没有更改构造函数,因此在上面的示例中,这不适用于其他实例,例如test
。
最好的方法是仅在原型和放大器中定义功能。不在构造函数中,如下面的代码片段。
var O = function(someValue){
this.someValue = someValue;
};
O.prototype.hello = function(){
return "hello, " + this.someValue;
};
var i = new O("chris");
console.log(i.hello()); // prints hello, chris
O.prototype.hello = function() {
return 'Hi there '+ this.someValue;
}
console.log(i.hello()); // prints Hi there chris
var test = new O('Sujay')
console.log(test.hello()) // prints Hi there Sujay
答案 6 :(得分:0)
当您访问属性时,系统首先在实例中查找它。如果找不到,它会在原型中查找它。这就是使用this.hello的原因,而不是O.prototype.hello。
如果您希望覆盖hello的实现,则需要使用JavaScript继承。这是一个基本的例子:
var A = function(){
console.log("A is getting constructed");
};
A.prototype.constructor = A;
A.prototype.someValue = 1;
A.prototype.hello = function() {
console.log("A.hello(): " + this.someValue);
};
var B = function(){
//Constructor of A is automatically called before B's
console.log("B is getting constructed");
};
B.prototype = new A; //Inherit from A
B.prototype.constructor = B;
B.prototype.hello = function() {
console.log("B.hello() called");
console.log("Calling base class method");
A.prototype.hello.call(this);
};
var a = new A();
a.hello();
var b = new B();
b.hello();
答案 7 :(得分:0)
为已创建的实例覆盖方法 refreshEditor :
var cp = hot1.getPlugin('comments');
cp.refreshEditor = (function (original) {
return function (force) {
//do something additional
if(console) {
console.log('test!!!!!!!!!');
console.log(force)
}
original.call(cp, force);
}
})(cp.refreshEditor);