Я просто пытаюсь получить вдохновение из того, как мы можем эффективно избежать такого конфликта в javascript, предполагая, что мы должны называть их таким образом.
Чтобы избежать путаницы, давайте называть val
вас на прототипе «прото val
» и один присвоенным в конструктор «например val
».
Вы не можете иметь свойство на объекте («экземпляр val
»), имеющее то же имя, что и свойство на его прототипе («proto val
»), и получить доступ к ним непосредственно через ссылку на объект, получить один или другой в зависимости от контекста. Это просто не функция JavaScript. Это неотъемлемо от того, как работает поиск свойств JavaScript, и тот факт, что «методы» JavaScript - это просто свойства, относящиеся к функциям.
Варианты ниже, но давайте более внимательно рассмотрим, почему «экземпляр val
» отменяет «прото val
»:
С любым из исправленных версий кода выше, эта строка:
var c = new Card(42);
дает нам это в памяти (некоторые детали опущены):
+------------------------------------------+
| |
\ +------------+ |
Card>--+->| (function) | |
+------------+ +-------------+ |
| prototype |>---+->| (object) | |
+------------+ / +-------------+ |
| | constructor |>--+ +------------+
| | val |>----->| (function) |
| +-------------+ +------------+
|
+---------------+ |
c>--->| (object) | |
+---------------+ |
| [[Prototype]] |>---+
| val: 42 |
+---------------+
идентификатор Card
(фактически переменная) относится к функц ион. Свойство этой функции prototype
относится к объекту, на который мы положили метод «proto val
». Переменная c
относится к экземпляру, в котором спецификация называет «внутренний слот» под названием [[Prototype]]
, который ссылается на его прототип, который он получил от Card.prototype
, когда мы сделали new Card
. Прототип имеет свойство val
, указывающее на метод, а также свойство constructor
, которое указывает на обратную функцию Card
.
Когда мы попросим механизм JavaScript найти объект val
на c
, он находит его на объекте c
, ссылается на него и использует его оттуда; «instance val
» переопределил «proto val
».Если «экземпляр val
» не был там, механизм JavaScript не нашел бы его на объекте c
точек и не посмотрел бы на прототип объекта (на что указывает внутренний слот объекта [[Prototype]]
), а затем он найдет свойство, указывающее на функцию. Но «пример val
» мешает.
Вы в основном есть три варианта:
делать то, что вы сказали, что вы не хотите делать: давать им разные имена. Свойство данных («экземпляр val
») может быть, например, _val
, или метод («proto val
») может быть getVal
(поскольку имена методов обычно должны быть глаголами) или оба (что было бы довольно распространенным) и т. Д.
Создать метод val
в конструкторе и не имеют свойство val
данных на всех:
// ES2015 (ES6) and higher
class Card {
constructor(val) {
this.val = function() {
return val;
};
}
}
или
// ES5 and earlier
function Card(val) {
this.val = function() {
return val;
};
}
Поскольку данные val
больше не является свойством экземпляра, нет конфликта с методом val
.
Это работает, потому что метод val
теперь является закрытием по контексту вызова Card
, и поэтому он имеет устойчивый доступ к аргументу val
. Однако никакие прототипные методы не имели бы прямого доступа к нему; они должны будут использовать this.val()
, чтобы получить его.
Делайте то, что вы делаете сейчас и посмотреть на "прото val
" на прототипе, а не на экземпляре:
var c = new Card(val).val()
Object.getPrototypeOf(c).val.call(c); // ES5+
или (менее надежный)
var c = new Card(val).val()
Card.prototype.val.call(c);
или (еще менее надежный)
var c = new Card(val).val()
c.constructor.prototype.val.call(c);
... который, как вы можете видеть, это довольно болезненно. Это работает, потому что в этих примерах я не ищу «proto val
» на c
(потому что «экземпляр val
» мешает); Я смотрю его прямо на прототипе c
(определенно, в первом примере: , вероятно, во втором примере; , надеюсь, в третьем).