Вопрос о наследовании прототипа в javascript

Я понимаю, что такое наследование прототипа, но я должен быть смущен в отношении реализации. Я думал, что изменение прототипа конструктора функции повлияет на все экземпляры этого конструктора, но это не так. Как JS выполняет поиск метода от объекта к его прототипу?

Вот пример

function A(name){
  this.name = name;
}

a = new A("brad");

A.prototype = {
  talk: function(){
    return "hello " + this.name;
  }
}

a.talk() // doesn't work
b = new A("john");
b.talk() // works

У меня сложилось впечатление, что a будет искать метод talk() в Aпрототип, поэтому любая модификация Aпрототип, до или после a было бы отражено, но это не так. Может кто-нибудь объяснить это для меня?

2 ответа

Решение

Это разница между модификацией и заменой прототипа.

function A(name){
  this.name = name;
}

a = new A("brad");
// Change, don't replace.
A.prototype.talk = function(){
    return "hello " + this.name;
};

a.talk() // works
b = new A("john");
b.talk() // works

Вот что происходит:

// Continued from above
var old_proto = A.prototype;

// Nuke that proto
A.prototype = {
talk: function() {
    return "goodbye " + this.name;
}
};

var c = new A("Al");

a.talk() // hello brad
b.talk() // hello john
c.talk() // goodbye Al

old_proto.say_goodbye = function() {
    return "goodbye " + this.name;
};

a.say_goodbye() // goodbye brad
b.say_goodbye() // goodbye john
c.say_goodbye() // TypeError c.say_goodbye is not a function.

В поддержку хорошего ответа Шона: нет ничего плохого в замене всего прототипа, если вы делаете это до создания экземпляров объекта. Это также работает:

function A(name){
  this.name = name;
}

A.prototype = {
  talk: function(){
    return "hello " + this.name;
  }
}

a = new A("brad");

a.talk() // works

Только убедитесь, что не замените это позже (если только это не то, что вы пытаетесь сделать).

В вашем оригинальном примере A у вас не было своего собственного прототипа во время создания вашего первого экземпляра, но он имел его при создании второго экземпляра, потому что вы создали промежуточный прототип.

Цепочка прототипов создается, когда создается экземпляр объекта, так что два экземпляра одного и того же "класса" могут иметь разные прототипы, как вы продемонстрировали.

Это может вызвать все виды проблем:

var a = new A("brad");
console.log(a instanceof A) // true

A.prototype = {
  talk: function(){
    return "hello " + this.name;
  }
}

console.log(a instanceof A) // false

Объект, на который ссылается a больше не считается экземпляром A так как instanceof работает, проверяя, если A.prototype находится в цепи прототипа a,

Другие вопросы по тегам