Override function in JavaScript [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Calling base method using JavaScript prototype
I want to inheritance object that will override function in javascript.
From the method I want to call to the base method.
In this case I inherit object reader from Person and now I want to override the function getName meaning that in reader first I want to call the function on Person and then to do some changes.
<script>
/* Class Person. */
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
var reader = new Person('John Smith');
reader.getName = function() {
// call to base function of Person, is it possible?
return('Hello reader');
}
alert(reader.getName());
</script>

Vincent answered your direct question but here is what you would do if you would like to set up a true inheritance hierarchy where you can further extend Reader.
Create your person class:
function Person(name) {
this.name = name;
}
Person.prototype.getName = function(){
alert('Person getName called for ' + this.name);
return this.name;
}
Create a Reader class as well:
function Reader(name) {
// Calls the person constructor with `this` as its context
Person.call(this, name);
}
// Make our prototype from Person.prototype so we inherit Person's methods
Reader.prototype = Object.create(Person.prototype);
// Override Persons's getName
Reader.prototype.getName = function() {
alert('READER getName called for ' + this.name);
// Call the original version of getName that we overrode.
Person.prototype.getName.call(this);
return 'Something';
}
Reader.prototype.constructor = Reader;
And now we can repeat a similar process to extend Reader with say a VoraciousReader:
function VoraciousReader(name) {
// Call the Reader constructor which will then call the Person constructor
Reader.call(this, name);
}
// Inherit Reader's methods (which will also inherit Person's methods)
VoraciousReader.prototype = Object.create(Reader.prototype);
VoraciousReader.prototype.constructor = VoraciousReader;
// define our own methods for VoraciousReader
//VoraciousReader.prototype.someMethod = ... etc.
fiddle:
http://jsfiddle.net/7BJNA/1/
Object.create: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create
Object.create(arg) is creating a new object whose prototype is what was passed in as an argument.
Edit
Its been years since this original answer and now Javascript supports the class keyword which works as you'd expect if you're coming from language like Java or C++. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

Since you are correctly overriding the function on the object itself and not on its prototype, you can still call the prototype function with your object.
reader.getName = function() {
var baseName = Person.prototype.getName.call(this);
...
}

I use this technique from John Resig to get inheritance and method overriding. It even lets you access to the overridden method by calling this._super().
http://ejohn.org/blog/simple-javascript-inheritance/

This is one way to do it:
function Person(name) {
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
}
var reader = new Person('John Smith');
reader.oldGetName = reader.getName;
reader.getName = function() {
//call to base function of Person , is it possible ?
return this.oldGetName();
}
alert(reader.getName());​
http://jsfiddle.net/fXWfh/

Related

JS inheritance - MDN article

given MDN JS Inheritance article, we have these lines
My question is, why use Object.create and not just Person.prototype?
I understand the need to link prototypes.
But here is console example rendering the call to Object.create in fact not connecting the inherited methods:
Why is that? is it mistake in the article?
Teacher.prototype = Person.prototype
That sets the prototye of the teachers to the same object as the persons prototype. So if you change that:
Teacher.prototype.hi = () => alert("hi");
Then that exists both on teachers and persons:
new Person().hi();
Thats not what you want when creating a subclass. If you do
Teacher.prototype = Object.create( Person.prototype );
You create a new object that inherits the persons prototype. Now the properties do not exist on the object itself, but they are inherited. That getOwnPropertyNames returns nothing does not mean that the properties are not inherited but the opposite: They just don't exist on the object itself, but on its parent.
new Teacher().greeting(); // works :)
The problem with Teacher.prototype = Person.prototype is that then, there is no actual inheritence going on - both prototypes will reference the same object. If you proceed to add a function to Teacher's prototype, for example getClassTaught(), that will mutate Person.prototype, which should not have that method.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() { return this.name; };
function Teacher(name, className) {
this.name = name;
this.className = className;
}
Teacher.prototype = Person.prototype;
Teacher.prototype.getClassTaught = function() { return this.className; };
const person = new Person();
console.log('getClassTaught' in person);
You also wouldn't be able to shadow Person functions without replacing them entirely. For example, if there's a greeting() function on Person.prototype, and you assign another greeting() function to Teacher.prototype, you'll be overwriting the function on Person.prototype - other persons calling greeting() may not work anymore, because the function is now Teacher-specific, rather than Person-generic.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() { return this.name; };
Person.prototype.greeting = function() { return 'Hi, I am ' + this.name; };
function Teacher(name, className) {
this.name = name;
this.className = className;
}
Teacher.prototype = Person.prototype;
Person.prototype.greeting = function() { return 'Hi, I am Teacher ' + this.name; };
const person = new Person('Bob');
console.log(person.greeting());
getOwnPropertyNames only shows you the property names directly on the object itself - it does not show inherited property names. When you use Object.create(Person.prototype), greeting is inherited from the Person prototype; it's not directly on Teacher.prototype, so it doesn't show up in getOwnPropertyNames.

Whats the equivalent of ES6 methods(class) in es5?

How would we polyfill es6 class methods into ES5?
I am reading a book and it says the following:
class Ninja {
constructor(name) {
this.name = name;
}
swingSword() {
return true;
}
}
is the same as
function Ninja(name) {
this.name = name;
}
Ninja.prototype.swingSword = function() {
return true;
};
I am just asking why are we adding the swingSword on the prototype and not inside the constructor function?
Because the function should be on the object and not on the prototype chain.
Am i right or wrong?
It should be on the prototype, methods are not per-instance data. Can't think of any language that implements it that way, the whole idea of classes is to have a whole class of objects that have the same set of methods.
If it was put it inside the constructor function, it would be a unique function per instance made with the constructor. e.g, 1000 objects == 1000 functions, per "method".
Adding the function to just the object would only work for a Ninja. To create a class that extends Ninja, for example Kunoichi, you would normally copy the Ninja prototype. Unfortunately, because swingSword is not in the prototype, your Kunoichi cannot swing swords.
You must add the function in prototype to allow the class to be extended.
If we add a method to the prototype, only one instance of that method exists in memory, and it’s shared between all objects created from the constructor.
If we add the swingSword method directly to the Ninja constructor function, then every object would have its own copy of that method, taking up more memory.
var $class = function ($superclass, config) {
// All classes have a superclass with the root
// of this $class hierarchy being Object.
var self = function (config) {
// Object.assign or $.extend or ...
config && Object.assign(this, config);
};
self.prototype = new $superclass(config);
return self;
};
var A = $class(Object, {
sayWhat: "Hello, I'm an A",
say: function () {
console.log(this.sayWhat);
}
});
var B = $class(A, {
sayWhat: "Hello, I'm a B"
});
var C = $class(B, {
say: function () {
console.log("C SAYS: " + this.sayWhat);
},
superSay: function () {
// how to call a superclass method
B.prototype.say.call(this);
}
});
var a = new A();
a.say();  // Hello, I'm an A
var b = new B();
b.say();  // Hello, I'm a B
var c = new C();
c.say();  // C SAYS: Hello, I'm a B
// create a "one-off" object
var d = new C({
sayWhat: "I'm special!",
say: function () {
console.log("hey!");
}
});
d.say();  // hey!
d.superSay();  // I'm special!
C.prototype.say.call(d);  // C SAYS: I'm special!

Does Object.create support so called class methods?

When I create an object using a constructor like:
function Person(name, age) {
this.name = name;
this.age = age;
}
I can add properties that are functions to the constructor function which act like (static) class methods. Object.create doesn't seem to support that. Is that right? The constructor property of all object created by Object.create seem to be the same function.
Thanks in advance.
Are you sure you mean static?
What I mean is, in a more class-dependent language, you might have:
class Person {
static people = 0;
public name;
public age;
public Person (name, age) { this.name = name; this.age = age; Person::people += 1; }
public sayName () { echo this.name; }
static numPeople () { echo Person::people; }
}
Then you might say:
bob = new Person("Bob", 32);
bob.sayName(); // "Bob"
Person::numPeople(); // 1
If you wanted Person::numPeople(); functionality, there's nothing stopping you from adding Object.create.numPeople = function () {};
The question you might want to ask yourself is "Why?"
Are you trying to call static methods like:
bob.constructor.numPeople();
If so, I'm sure that there's a better way around that.
For example, extending the constructor's prototype would provide access to static properties/methods by default.
var personObj = {
sayName : function () { console.log(this.name); },
sayAge : function () { console.log(this.age); }
};
var bob = Object.create(personObj, { name : "Bob", age : 32 });
These are accessed in a way which is similar to traditional inheritance, but static in the sense that each object references the same functions and values, so if that prototype object changes, each constructed instance changes, as well.
Personally, I prefer the freedom of doing most of my object creation inline and on-demand.
If I need to create multiples of the same format, then I'll typically create a factory, rather than creating a constructor or using Object.create.
With a factory, even just a simple one, using one or two levels of closure, you can simulate private properties/methods, and with the second closure, you can simulate "class-wide" private-statics.

How to change Prototype class declarations into jquery?

I'm working with my Rails 3.1 migration and it's getting harder and harder to keep jquery and prototype living peacefully side by side. I'm investigating a way to change my Prototype-way implemented js-files into jquery format.
I've used heavily prototype-way of declaring classes and sub-classes:
// properties are directly passed to `create` method
var Person = Class.create({
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
}
});
// when subclassing, specify the class you want to inherit from
var Pirate = Class.create(Person, {
// redefine the speak method
say: function($super, message) {
return $super(message) + ', yarr!';
}
});
var john = new Pirate('Long John');
john.say('ahoy matey');
// -> "Long John: ahoy matey, yarr!"
I've read about John Resig's script: http://ejohn.org/blog/simple-javascript-inheritance/. Is this the way to go? Or should I choose some other approach?
I have about 15 js-files (one class per file). I'm willing to spend some time for this migration, so I'd like to do it right. Thanks for your professional help!
Here's one possible way to implement your example with plain functions.
function Person(name) {
this.name = name;
}
Person.prototype.say = function (message) {
return this.name + ": " + message;
};
function Pirate(name) {
this._super = Person.prototype;
this._super.constructor.apply(this, arguments);
}
Pirate.prototype.say = function (message) {
return this._super.say.apply(this, arguments) + ", yarr!";
};
john = new Pirate("Long John");
john.say("ahoy matey");
You'd probably want to extract the inheritance operations into a function, but this gives you the basic idea.
This is a bit improved version of Jimmy's example. Firstly, I'd add an extra function that helps you to define prototype chain more conveniently. You could also use Object.create(), but that is not yet supported in all browsers, so this function should be a bit more bulletproof:
// A convenient function to define prototype chain
function inheritPrototype(child, parent) {
function F(){}
F.prototype = parent.prototype;
child.prototype = new F();
// set the constructor back to the original, explained later
child.prototype.constructor = child;
}
Then define objects. Notice the extra function setName which enables us to set the name of the Person. (nevermind that in JS there's usually no need for getters/setters). Also notice the extra inheritPrototype call after Pirate function has been defined.
function Person(name) {
this.name = name;
}
Person.prototype.say = function (message) {
return this.name + ": " + message;
};
Person.prototype.setName = function(name) {
this.name = name;
};
function Pirate(name) {
this._super = Person.prototype;
this._super.constructor.apply(this, arguments);
}
inheritPrototype(Pirate, Person);
Pirate.prototype.say = function (message) {
return this._super.say.apply(this, arguments) + ", yarr!";
};
var john = new Pirate("Long John");
john.say("ahoy matey");
This style enables you to automatically call parent's functions, and you don't have to override each and every one of them, if they are the same as their parents'. Also this doesn't stop you from redefining functions that already exist for the parent (in this case say is overridden). And remember, all functions are 1-way, meaning that if you override a function in a children, then parent's function remains unchanged. An example:
// Should result in John "The Pirate" Long: ahoy matey, yarr!
// instead of how it was defined in Person
john.setName('John "The Pirate" Long');
john.say('ahoy matey');
// Notice that even though Pirate redefined say function, it
// still works as defined in Person, if it's called on a Person object
var president = new Person("Obama");
president.say('Vote for me!');
Also using this style allows you to check object types, if the child.prototype.construtor was redefined to child (replacing the prototype sets it to parent's constructor function). John is both Person and Pirate (because Pirate inherits from Person). An example:
john instanceof Person
> true
john instanceof Pirate
> true
Since president is directly a Person object and not a Pirate, the results would be the following:
president instanceof Person
> true
president instanceof Pirate
> false
jQuery has no concept of classes. It is a library which is built to abstract the browser differences and simplify the process of common operations; DOM manipulation, AJAX, and event handling.
Take a look at Dean Edward's Base.js: http://dean.edwards.name/weblog/2006/03/base/
var object = new Base;
object.method = function() {
alert("Hello World!");
};
object.extend({
method: function() {
// call the "super" method
this.base();
// add some code
alert("Hello again!");
}
});
object.method();
// ==> Hello World!
// ==> Hello again!
If you call _super directly, you might run into problems if the super method also uses this._super - and then runs as an infinite loop as you always pass the same object as "this".

Why use prototype for methods instead of this.methodName [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Advantages of using prototype, vs defining methods straight in the constructor?
Why use:
Person.prototype.toString = function() { return this.name; }
over
Function Person(name) {
this.name = name;
this.toString = function() {
return this.name;
}
}
Well, you should use prototypes because of code reuse and inheritance.
Basically, if you bind a method to the this keyword, you are providing that method to only that particular instance, while with prototype, you write the method for all instances of that class.
ex:
function Person(name) {
this.name = name;
this.toString = function() {
return this.name;
}
}
var bob = new Person('Bob');
var jim = new Person('Jim');
jim.toString = function() {
return "I have amnesia, I forgot my name!";
};
Now, although bob and jim are both persons (instances of the same class), they behave differently, because they have their own set of rules (methods) that they rely on.
If you were to use a prototype:
function Person(name) {
this.setName(name);
}
Person.prototype = {
name : 'default name',
setName : function(name) {
this.name = name;
},
toString : function() {
return this.name;
}
};
var bob = new Person('Bob');
var jim = new Person('Jim');
Person.prototype.toString = function() {
return "I have amnesia, I forgot my name!";
};
Now, all of your persons behave the same.
Using prototypal inheritance is benefic for code reuse and it won't load the memory with unnecessary duplicate things. + Updating classes is muuuch more easy this way.
One reason is because it will update/add that function to objects of that type that have already been created.
function Person(name) {
this.name = name;
}
var person = new Person("Test");
alert(person.toString()); // alerts [object Object]
Person.prototype.toString = function() {
return this.name;
};
alert(person.toString()); // alerts Test
http://jsfiddle.net/28puy/
In javascript, methods are objects. In your second Person constructor, you're creating a new instance of the toString function for each instance of Person. By using the prototype object, there is just one instance of the toString function that will be shared among all instances of Person.

Categories

Resources