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.
Override method refreshEditor for created instance:
Firstly, you need to understand prototypal inheritance.
When you create an object using
O
as a constructor, this happens:O.prototype
object, is created.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.Secondly, you need to understand closures.
someValue
is a variable (not a property) defined in theO
function. It can only be accessed from other things that are also defined in the same function (or any functions defined inside theO
function). So, we say "someValue
was closed over". It can't be accessed by a function that you define outside ofO
.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 apublic
thing). Or, you need to define all the functions that need access tosomeValue
inside ofO
's original definition.To change what
i.hello
points to afteri
has been created, you need set the property of the object directly.When you create an instance of the
O
object usingnew O("somename");
you are assigning an instance method to the newly created object. When you then assign another method of the same name toO
'sprototype
the method is already shadowed by the instance method. So: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 seesO.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 exposeget
and / orset
methods that give these new methods access to the closure variables:You'll really want to read bobince's great answer on OOP in JavaScript for more information on the subject.
When you use
new
, the value ofthis
inside the constructor points to the newly created object (for more information on hownew
works, take a look at this answer and this answer). So your new instancei
, has ahello
function. When you try to access the property of an object, it walks up the prototype chain until it finds it. Sincehello
exists on the instance of the object, there is no need to walk up the prototype chain to access the version ofhello
that returnshhhhhhhh
. In a sense, you have overridden the default implementation in your instance.You can see this behavior if you don't assign
hello
tothis
inside your constructor: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:
So when you do
i.hello
, JavaScript sees that there is ahello
property oni
and uses that. Now if you didn't explicitly define ahello
property, you basically have the following: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:
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:Which is equivalent to doing:
So in this case,
hello
is a global reference to that function. What this means is thathello
isn't attached to any of your objects.hello
can be undefined if you don't havethis.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.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
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 byO.hello
, even though the former is defined later in the code.The reason
someValue
isn't available to yourO.prototype.hello
is because the scope ofsomeValue
is constrained to the constructor function and any functions defined or executed within it. SinceO.prototype.hello
is defined outside the scope of theO
constructor, it doesn't know aboutsomeValue