Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript redefine and override existing function body

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.

      // 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.

like image 360
peter Avatar asked Aug 29 '12 17:08

peter


People also ask

Can I override function in JavaScript?

JavaScript supports overriding not overloading, meaning, that if you define two functions with the same name, the last one defined will override the previously defined version and every time a call will be made to the function, the last defined one will get executed.

Which keyword is used to override the functions already existing in JavaScript?

Use the super Keyword in Inheritance to Get Back Previous Function. The only way to get back the previous function once we override it is to use the super keyword. We will create two functions with the same name and parameters, one in the parent class and one in the child class.

Can JavaScript built in functions be redefined?

Strictly speaking, no, it isn't possible to redefine a JavaScript function at all. Though it's kind of a matter of semantics. A function may overwrite its reference within a certain scope with another function, which serves as a sleight of hand where another function appears in the place of the first.

What is redefinition in JavaScript?

The "Redefinition of '{a}'" error is thrown when JSHint or ESLint encounters a variable declaration with an identifier that is the same as that of a built-in native object. In the following example we attempt to declare a variable with the identifier String : var String = "My String"; ​x. 1.


2 Answers

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 answer and 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.

You can see this behavior if you don't assign hello to this inside your constructor:

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.

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:

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.

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 particular instance (i.e., only to i and not to any other instances that you may have created).

If you take out this, then you have basically have:

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 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.

like image 60
Vivin Paliath Avatar answered Sep 23 '22 02:09

Vivin Paliath


When you create an instance of the O object using new O("somename"); you are assigning an instance method to the newly created object. When you then assign another method of the same name to O's prototype the method is already shadowed by the instance method. So:

Object.prototype.hello // undefined        |        O.prototype.hello // alternate function          |          i.hello // original function provided in constructor 

JavaScript starts at the bottom of 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 (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 on the 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:

// 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 JavaScript for more information on the subject.

like image 36
Sean Vieira Avatar answered Sep 22 '22 02:09

Sean Vieira