Javascript 重新定义和覆盖现有的函数体
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12183011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript redefine and override existing function body
提问by peter
I am wondering can we still change the function body once it is constructed ?
我想知道一旦构造函数体,我们还可以更改它吗?
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"
The javascript statement O.prototype.hello = function(){....}
doesn't override and redefine the hello function behavior. Why is that ? I know it will have a type error if you tried to reuse the parameter someValue
.
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;
}
I am wondering why It allows to add function during runtime like
我想知道为什么它允许在运行时添加功能,例如
O.prototype.newFunction = function(){
return "this is a new function";
}
i.newFunction(); // print 'this is a new function' with no problem.
but doesn't allow you to change the definition once it's defined.
Did i do something wrong ? how do we override and redefine a function within a class ? and is there a way to reuse the parameter that we passed in earlier to create the object ? in this cases how do we re-use someValue
if we want to extend more functions to it.
但不允许您在定义后更改定义。我做错什么了吗 ?我们如何覆盖和重新定义类中的函数?有没有办法重用我们之前传入的参数来创建对象?在这种情况下,someValue
如果我们想为其扩展更多功能,我们如何重用。
采纳答案by Vivin Paliath
When you use new
, the value of this
inside the constructor points to the newly created object (for more information on how new
works, take a look at this answerand this answer). So your new instance i
, has a hello
function. When you try to access the property of an object, it walks up the prototype chain until it finds it. Since hello
exists on the instance of the object, there is no need to walk up the prototype chain to access the version of hello
that returns hhhhhhhh
. In a sense, you have overridden the default implementation in your instance.
使用时new
,this
构造函数内部的值指向新创建的对象(有关new
工作原理的更多信息,请查看此答案和此答案)。所以你的新实例i
,有一个hello
功能。当你试图访问一个对象的属性时,它会沿着原型链向上走,直到找到它。由于hello
存在于对象的实例上,因此无需沿着原型链向上访问hello
返回的版本hhhhhhhh
。从某种意义上说,您已经覆盖了实例中的默认实现。
You can see this behavior if you don't assign hello
to this
inside your constructor:
如果您不在构造函数内部赋值hello
,您可以看到这种行为this
:
var O = function(someValue) {
}
O.prototype.hello = function(){
return "hhhhhhh";
}
var i = new O("chris");
console.log(i.hello()); //this prints out hhhhhhh
What you're doing is kind of backwards. The prototype basically provides the "default" form of something, which you can override on a per-instance basis. The default form is used only if the property you're looking for cannot be found on the object. That is, JavaScript will start walking up the prototype chain to see if it can find a property that matches what you're looking for. It it finds it, it will use that. Otherwise, it will return undefined
.
你在做什么有点倒退。原型基本上提供了某些东西的“默认”形式,您可以在每个实例的基础上覆盖它。仅当在对象上找不到您要查找的属性时,才使用默认形式。也就是说,JavaScript 将开始沿着原型链向上走,看看它是否可以找到与您要查找的内容相匹配的属性。它找到它,它将使用它。否则,它将返回undefined
。
What you basically have in the first case is as follows:
您在第一种情况下的基本情况如下:
Object.prototype.hello (not defined; returns "undefined")
|
+----O.prototype.hello (returns "hhhhhhhh")
|
+----i.hello (returns "hello, chris")
So when you do i.hello
, JavaScript sees that there is a hello
property on i
and uses that. Now if you didn't explicitly define a hello
property, you basically have the following:
所以当你这样做时i.hello
,JavaScript 会看到有一个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.)
What this means is that you can provide a default implementation in the prototype, and then override it (in a sense it's like sub-classing). What you can also do is modify the behavior on a per-instance basis by directly modifying the instance. The version of hello
that you have on the prototype is kind of a fail-safe and a fall-back.
这意味着您可以在原型中提供默认实现,然后覆盖它(从某种意义上说,它就像子类化)。您还可以通过直接修改实例来修改每个实例的行为。hello
你在原型上的版本是一种故障安全和后备。
EDIT:Answers to your questions:
编辑:回答您的问题:
Overriding on a per-instance basis means you attach a property or a function to a particular instance. For example, you could do:
在每个实例的基础上覆盖意味着您将属性或函数附加到特定实例。例如,你可以这样做:
i.goodbye = function() {
return "Goodbye, cruel world!";
};
Which means that this behavior is specific to that particularinstance (i.e., only to i
and not to any other instances that you may have created).
这意味着此行为特定于该特定实例(即,仅适用于i
而不适用于您可能已创建的任何其他实例)。
If you take out this
, then you have basically have:
如果您取出this
,那么您基本上拥有:
hello = function() {
return "hello, " + someValue;
}
Which is equivalent to doing:
这相当于做:
window.hello = function() {
return "hello, " + someValue;
}
So in this case, hello
is a global reference to that function. What this means is that hello
isn't attached to any of your objects.
所以在这种情况下,hello
是对该函数的全局引用。这意味着它hello
不附加到您的任何对象。
hello
can be undefined if you don't have this.hello = function() { .... };
inside your constructor. I was also talking about the general process that JavaScript uses to try to resolve properties on objects. As I mentioned before, it involves walking up the prototype chain.
hello
如果您this.hello = function() { .... };
的构造函数内部没有,则可以是未定义的。我还谈到了 JavaScript 用来尝试解析对象属性的一般过程。正如我之前提到的,它涉及沿着原型链向上走。
回答by Sean Vieira
When you create an instance of the O
object using new O("somename");
you are assigning an instancemethod to the newly created object. When you then assign another method of the same name to O
's prototype
the method is already shadowedby the instance method. So:
当您使用创建O
对象的实例时,new O("somename");
您正在为新创建的对象分配一个实例方法。当您将另一个同名方法分配给O
' 时,prototype
该方法已经被实例方法遮蔽了。所以:
Object.prototype.hello // undefined
|
O.prototype.hello // alternate function
|
i.hello // original function provided in constructor
JavaScript starts at the bottomof the chain and stops when it finds a match for the name. So it stops at i.hello
and never sees O.prototype.hello
.
JavaScript 从链的底部开始,当它找到与 name 匹配时停止。所以它停在i.hello
并且永远不会看到O.prototype.hello
。
JavaScript (as of ECMAScript 5) really doesn't (as far as I am aware) give you a good way to do private variables like that that can be accessed by instance methods added after definition (either added onthe instance or on the prototype
). Closures get you most of the way there but if you want to be able to add methods outside of the closure that have access to closure variables you need to expose get
and / or set
methods that give these new methods access to the closure variables:
JavaScript的(如ECMAScript中5),确实没有(据我所知),给你一个很好的方式做私有变量一样,可以被定义后加入(或者加入实例方法来访问的实例或上prototype
) . 闭包可以帮助您完成大部分工作,但是如果您希望能够在闭包之外添加可以访问闭包变量的方法,您需要公开get
和/或set
让这些新方法访问闭包变量的方法:
// Possibility #1 - marked as private member
var O = function(someValue) {
this._someValue = someValue;
};
O.prototype.hello = function() { return "hhhh"; };
var i = new O("somename");
i.hello = function() { return "aloha," + this._someValue; };
console.log(O.hello()); // hhhh
console.log(i.hello()); // aloha, somename
// Possibility #2 - factory function + closure with get and set methods
var OMaker = function(someValue) {
var realO = function() {};
realO.prototype.getSomeValue = function() { return someValue; };
realO.prototype.setSomeValue = function(newVal) { someValue = newVal; };
realO.prototype.hello = function() { return "hhhh"; };
return realO;
};
var O = OMaker("somename"),
i = new O();
i.hello = function() { return "aloha," + this.getSomeValue(); };
console.log(O.hello()); // hhhh
console.log(i.hello()); // aloha, somename
// Possibility #3 - eschew prototype inheritance and create new objects
var O = function(someValue) {
return {
getValue: function() { return someValue; },
setValue: function(newValue) { someValue = newValue; },
hello: function() { return "hhhh"; }
};
};
var i = O(); // Note the lack of the "new" keyword
i.hello = function() { return "aloha," + this.getSomeValue(); };
console.log(O.hello()); // hhhh
console.log(i.hello()); // aloha, somename
You'll really want to read bobince's great answer on OOP in JavaScriptfor more information on the subject.
您真的很想阅读bobince 在 JavaScript 中的 OOP 上的精彩回答,以获取有关该主题的更多信息。
回答by Victor 'Chris' Cabral
No. You cannot, but here is a good example of ways around that limitation by patterning your inheritance in a different way.
不。你不能,但这里有一个很好的例子,通过以不同的方式对你的继承进行模式化来解决这个限制。
// 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"
回答by MicronXD
Firstly, you need to understand prototypal inheritance.
首先,您需要了解原型继承。
When you create an object using O
as a constructor, this happens:
当您使用O
构造函数创建对象时,会发生这种情况:
- 1st, a new object is created.
- 2nd, the hello property of that object is set to a function (via the constructor you defined).
- 3rd, a secret link from the object, pointing to the
O.prototype
object, is created.
- 第一,创建一个新对象。
- 第二,该对象的 hello 属性设置为一个函数(通过您定义的构造函数)。
- 第三,从对象指向对象的秘密链接
O.prototype
被创建。
When referencing properties of O
objects, those properties are first looked for in the object itself. Only if the object doesn't have the property itself does it look up to it's prototype.
引用O
对象的属性时,首先在对象本身中查找这些属性。只有当对象本身没有属性时,它才会查找它的原型。
Secondly, you need to understand closures.
其次,你需要了解闭包。
someValue
is a variable (not a property) defined in the O
function. It can only be accessed from other things that are also defined in the same function (or any functions defined inside the O
function). So, we say "someValue
was closed over". It can't be accessed by a function that you define outside of O
.
someValue
是O
函数中定义的变量(不是属性)。它只能从在同一函数中定义的其他事物(或在O
函数内部定义的任何函数)中访问。所以,我们说“someValue
被关闭了”。您在O
.
To achieve what you want, you either need to set someValue to a property (which makes it less like a private
thing and more like a public
thing). Or, you need to define all the functions that need access to someValue
inside of O
's original definition.
为了实现你想要的,你要么需要将 someValue 设置为一个属性(这使得它不像一个private
东西而更像一个public
东西)。或者,您需要定义所有需要访问someValue
ofO
原始定义内部的函数。
To change what i.hello
points to after i
has been created, you need set the property of the object directly.
要更改创建i.hello
后指向的内容i
,需要直接设置对象的属性。
i.hello = function () { /* stuff */ };
回答by RajV
When you access a property, system first looks for it in the instance. If it is not found, it looks for it in the prototype. This is why this.hello is being used, rather than O.prototype.hello.
当您访问一个属性时,系统首先在实例中查找它。如果没有找到,它会在原型中寻找它。这就是为什么使用 this.hello 而不是 O.prototype.hello 的原因。
If you wish to override the implementation of hello, you will need to use JavaScript inheritance. Here is a basic example:
如果您希望覆盖 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();
回答by SmaLL
Override method refreshEditorfor created instance:
为创建的实例覆盖方法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);
回答by Sujay
This is because when you access a property of an Object, JavaScript check the properties of the objects first, before going into its prototype.
这是因为当您访问对象的属性时,JavaScript 在进入其原型之前首先检查对象的属性。
This is analogous to Java's derived class overriding the base class functionality.
这类似于 Java 的派生类覆盖基类功能。
For a better understanding check the code example in Inheriting properties
为了更好地理解,请查看继承属性中的代码示例
Also note that someValue in your case is local to the constructor function. If you need it in other functions, you should assign it to this.someValue inside the constructor.
另请注意,您的情况下的 someValue 是构造函数的局部值。如果你在其他函数中需要它,你应该将它分配给构造函数中的 this.someValue 。
You'll be able to override the hello function for a particular Object here like the following. But not for the entire Class.
您将能够在此处覆盖特定对象的 hello 函数,如下所示。但不适用于整个班级。
i.hello = function(){ console.log('even here someValue is not accessible');};
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
Note that here we have not changed the constructor, and hence this will not work with other instances like test
in the above example.
请注意,这里我们没有更改构造函数,因此这不适test
用于上面示例中的其他实例。
The best way to do it would be to define functions only in the prototype & not in the constructor, like the following snippet.
最好的方法是只在原型中而不是在构造函数中定义函数,就像下面的代码片段一样。
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
回答by Hymanwanders
If I recall correctly, functions that are direct members of objects take precedence over like-named members of that object's prototype. Therefore, O.prototype.hello
is usurped by O.hello
, even though the former is defined later in the code.
如果我没记错的话,作为对象直接成员的函数优先于该对象原型的同名成员。因此,O.prototype.hello
被 篡夺O.hello
,即使前者在代码中稍后定义。
The reason someValue
isn't available to your O.prototype.hello
is because the scope of someValue
is constrained to the constructor function and any functions defined or executed within it. Since O.prototype.hello
is defined outside the scope of the O
constructor, it doesn't know about someValue
原因someValue
对您不可用O.prototype.hello
是因为范围someValue
被限制在构造函数和在其中定义或执行的任何函数。由于O.prototype.hello
是在O
构造函数的范围之外定义的,它不知道someValue