7

When using a constructor function in JavaScript to create a class, is it possible to redefine the class's method later?

Example:

function Person(name)
{
    this.name = name;
    this.sayHello = function() {
        alert('Hello, ' + this.name);
    };
};

var p = new Person("Bob");
p.sayHello();   // Hello, Bob

Now I'd like to redefine sayHello like this:

// This doesn't work (creates a static method)
Person.sayHello() = function() {
   alert('Hola, ' + this.name);
};

so when I create another Person, the new sayHello method will be called:

var p2 = new Person("Sue");
p2.sayHello();   // Hola, Sue
p.sayHello();    // Hello, Bob

EDIT:

I realize I could send in an argument like "Hello" or "Hola" to sayHello to accomplish the different output. I also realize I could simply assign a new function to p2 like this:

p2.sayHello = function() { alert('Hola, ' + this.name); };

I'm just wondering if I can redefine the class's method so new instances of Person will use the new sayHello method.

tronman
  • 9,432
  • 9
  • 44
  • 56

2 Answers2

13

is it possible to redefine the class's method later?

Yes. However, you must not assign the new function to a property of the Person constructor, but to the instance itself:

var p2 = new Person("Sue");
p2.sayHello();   // Hello, Sue
p2.sayHello = function() {
   alert('Hola, ' + this.name);
};
p2.sayHello();   // Hola, Sue

If you want to do this for all new instances automatically (and have not used the prototype for the method, which you easily could exchange as in @dystroy's answer), you will need to decorate the constructor:

Person = (function (original) {
    function Person() {
        original.apply(this, arguments);   // apply constructor
        this.sayHello = function() {       // overwrite method
            alert('Hola, ' + this.name);
        };
    }
    Person.prototype = original.prototype; // reset prototype
    Person.prototype.constructor = Person; // fix constructor property
    return Person;
})(Person);
Bergi
  • 572,313
  • 128
  • 898
  • 1,281
  • I tried your idea for "decorating the constructor". It doesn't currently seem to work, and I get a "requires new" error. I am not a JS expert but this may be something to do with newer versions of JS (I think I am currently using ES6 (async/await)... or is it ES7???). – mike rodent Sep 02 '17 at 07:24
  • 1
    @mikerodent The above method does not work for ES6 `class`es. It's [a bit more complicated](https://stackoverflow.com/a/31789308/1048572) there. – Bergi Sep 02 '17 at 08:52
  • Note that this only works for proper functions, not for arrow functions – Pum Walters May 15 '18 at 09:40
  • @PumWalters Sure, [arrow functions are no constructors](https://stackoverflow.com/q/34361379/1048572). – Bergi May 15 '18 at 11:23
  • @Bergi: I'm not sure I understand. An ordinary function can be assigned to an object property and will act as a method (i.e. will get 'this'). An arrow function will act as a function but not as a method (won't get 'this') – Pum Walters May 15 '18 at 14:59
  • @PumWalters I thought you were talking about the `Person` (constructor) function not the `sayHello` (method) function? But yes, of course you can't use arrow functions here, requiring dynamic `this`. – Bergi May 15 '18 at 15:11
12

To have a different function for p2, you can just set the sayHello property of p2 :

p2.sayHello = function(){ 
    alert('another one');
}
p2.sayHello(); 

If you use prototype, then you can also change it for all instances of Person (and still you can overwrite it for a specific person) :

function Person(name)
{
    this.name = name;
};
Person.prototype.sayHello = function() {
    alert('Hello, ' + this.name);
};

var p = new Person("Bob");

// let's set a specific one for p2
p2.sayHello = function(){ 
    alert('another one');
}

// now let's redefine for all persons (apart p2 which will keep his specific one)
Person.prototype.sayHello = function(){ 
    alert('different!');
}

p.sayHello();  // different!
p2.sayHello(); // another one
Denys Séguret
  • 355,860
  • 83
  • 755
  • 726
  • I know about prototype and that I could assigned a new function to p2, but what I wanted was to change Person directly so new instances of Person would use the "Hola" function. Sorry I didn't make that more clear. – tronman Jan 20 '14 at 22:05