Можно ли переопределить метод класса JavaScript?

При использовании функции конструктора в JavaScript для создания класса возможно ли позднее переопределить метод класса?

Пример:

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

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

Теперь я хотел бы переопределить sayHello как это:

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

поэтому, когда я создаю другой Person, новый sayHello метод будет вызван:

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

РЕДАКТИРОВАТЬ:

Я понимаю, что могу послать аргумент типа "Привет" или "Привет" sayHello для достижения другого выхода. Я также понимаю, что мог бы просто назначить новую функцию для p2 следующим образом:

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

Мне просто интересно, могу ли я переопределить метод класса, чтобы новые экземпляры Person будет использовать новый sayHello метод.

3 ответа

Решение

возможно ли переопределить метод класса позже?

Да. Однако вы не должны назначать новую функцию свойству Person конструктор, но для самого экземпляра:

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

Если вы хотите сделать это для всех новых экземпляров автоматически (и не использовали прототип для метода, который вы легко могли бы обменять, как в ответе @dystroy), вам нужно украсить конструктор:

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);

Чтобы иметь другую функцию для p2, вы можете просто установить sayHello свойство p2:

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

Если вы используете прототип, вы также можете изменить его для всех экземпляров 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

Чтобы решить вашу проблему, вы можете использовать объект Reflect

      class Person {
    public name: string;
    
    constructor(name: string) {
        this.name = name;
    }

    public sayHello(): void {
        console.log(`Hello, ${this.name}`)
    }
}

const p = new Person("Bob");

p.sayHello();   // Hello, Bob

Reflect.defineProperty(Person.prototype, 'sayHello', { value: function() {
    console.log(`Goodbye, ${this.name}`)
}})

p.sayHello();   // Goodbye, Bob
Другие вопросы по тегам