Прежде всего, в этом коде:
MyString.prototype = String.prototype;
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
переменные MyString.prototype
и String.prototype
обе ссылаются на один и тот же объект!Назначение одному - назначение другому.Когда вы добавили метод reverse
в MyString.prototype
, вы также записали его в String.prototype
.Поэтому попробуйте это:
MyString.prototype = String.prototype;
MyString.prototype.charAt = function () {alert("Haha");}
var s = new MyString();
s.charAt(4);
"dog".charAt(3);
Последние две строки обе предупреждают, потому что их прототипы - это один и тот же объект.Вы действительно расширили String.prototype
.
Теперь о вашей ошибке.Вы назвали reverse
на вашем MyString
объекте.Где этот метод определен?В прототипе, который такой же, как String.prototype
.Вы переписали reverse
.Что это первое, что он делает?Он вызывает split
на целевом объекте.Дело в том, что для работы String.prototype.split
необходимо вызвать String.prototype.toString
.Например:
var s = new MyString();
if (s.split("")) {alert("Hi");}
Этот код генерирует ошибку:
TypeError: String.prototype.toString is not generic
Это означает, что String.prototype.toString
использует внутреннее представление строки для выполнения своей задачи (а именно, для возврата еевнутренняя примитивная строка), и нельзя применять к произвольным целевым объектам, которые совместно используют прототип строки .Поэтому, когда вы вызвали split
, реализация split сказала: «О, моя цель - не строка, позвольте мне вызвать toString
», но затем toString
сказала: «Моя цель не строка, и я не универсальный»так что он выбросил TypeError
.
Если вы хотите узнать больше о дженериках в JavaScript, вы можете увидеть этот раздел MDN о дженериках массивов и строк .
Какчтобы заставить это работать без ошибок, см. ответ Александра.
Что касается расширения точных встроенных типов , таких как String
и Date
и так далее, без изменения их прототипов,Вы действительно этого не сделаете, не создавая оболочки, делегаты или подклассы.Но тогда это не позволит использовать синтаксис, такой как
d1.itervalTo(d2)
, где d1
и d2
- это экземпляры встроенного класса Date
, прототип которого вы не расширили ,:-) JavaScript использует цепочки прототипов для этого вида синтаксиса вызова метода.Это просто так.Хороший вопрос, но ... но вы это имели в виду?