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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 07:20:41  来源:igfitidea点击:

Javascript redefine and override existing function body

javascriptprototype

提问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 someValueif we want to extend more functions to it.

但不允许您在定义后更改定义。我做错什么了吗 ?我们如何覆盖和重新定义类中的函数?有没有办法重用我们之前传入的参数来创建对象?在这种情况下,someValue如果我们想为其扩展更多功能,我们如何重用。

采纳答案by Vivin Paliath

When you use new, the value of thisinside the constructor points to the newly created object (for more information on how newworks, take a look at this answerand this answer). So your new instance i, has a hellofunction. When you try to access the property of an object, it walks up the prototype chain until it finds it. Since helloexists on the instance of the object, there is no need to walk up the prototype chain to access the version of hellothat returns hhhhhhhh. In a sense, you have overridden the default implementation in your instance.

使用时newthis构造函数内部的值指向新创建的对象(有关new工作原理的更多信息,请查看此答案此答案)。所以你的新实例i,有一个hello功能。当你试图访问一个对象的属性时,它会沿着原型链向上走,直到找到它。由于hello存在于对象的实例上,因此无需沿着原型链向上访问hello返回的版本hhhhhhhh。从某种意义上说,您已经覆盖了实例中的默认实现。

You can see this behavior if you don't assign helloto thisinside 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 helloproperty on iand uses that. Now if you didn't explicitly define a helloproperty, 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 hellothat 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 iand 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, hellois a global reference to that function. What this means is that helloisn't attached to any of your objects.

所以在这种情况下,hello是对该函数的全局引用。这意味着它hello不附加到您的任何对象。

hellocan 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 Oobject 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 prototypethe 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.helloand 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 getand / or setmethods 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.

不。你不能,但这里有一个很好的例子,通过以不同的方式对你的继承进行模式化来解决这个限制。

JavaScript override methods

JavaScript 覆盖方法

// 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 Oas 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.prototypeobject, is created.
  • 第一,创建一个新对象。
  • 第二,该对象的 hello 属性设置为一个函数(通过您定义的构造函数)。
  • 第三,从对象指向对象的秘密链接O.prototype被创建。

When referencing properties of Oobjects, 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.

其次,你需要了解闭包。

someValueis a variable (not a property) defined in the Ofunction. It can only be accessed from other things that are also defined in the same function (or any functions defined inside the Ofunction). So, we say "someValuewas closed over". It can't be accessed by a function that you define outside of O.

someValueO函数中定义的变量(不是属性)。它只能从在同一函数中定义的其他事物(或在O函数内部定义的任何函数)中访问。所以,我们说“someValue关闭了”。您在O.



To achieve what you want, you either need to set someValue to a property (which makes it less like a privatething and more like a publicthing). Or, you need to define all the functions that need access to someValueinside of O's original definition.

为了实现你想要的,你要么需要将 someValue 设置为一个属性(这使得它不像一个private东西而更像一个public东西)。或者,您需要定义所有需要访问someValueofO原始定义内部的函数。

To change what i.hellopoints to after ihas 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 testin 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.hellois usurped by O.hello, even though the former is defined later in the code.

如果我没记错的话,作为对象直接成员的函数优先于该对象原型的同名成员。因此,O.prototype.hello被 篡夺O.hello,即使前者在代码中稍后定义。

The reason someValueisn't available to your O.prototype.hellois because the scope of someValueis constrained to the constructor function and any functions defined or executed within it. Since O.prototype.hellois defined outside the scope of the Oconstructor, it doesn't know about someValue

原因someValue对您不可用O.prototype.hello是因为范围someValue被限制在构造函数和在其中定义或执行的任何函数。由于O.prototype.hello是在O构造函数的范围之外定义的,它不知道someValue