Изменение объектов ECMAScript

Используя ECMAScript, можно не только создавать объекты, но и изменять поведение существующих объектов.

Атрибут prototype позволяет не только определить свойства и методы конструктора, но и добавлять свойства и методы для локальных объектов.

Создание новых методов

Создание новых методов с использованием уже существующих методов

Методы можно определить для любого существующего класса с помощью свойства prototype, как если бы вы работали со своим классом. Например, помните метод toString() класса Number? Если передать ему параметр 16, он выведет шестнадцатеричную строку. Если параметр равен 2, он выведет двоичную строку. Можно создать метод, который преобразует объект числа в шестнадцатеричную строку. Создание этого метода очень просто:

Number.prototype.toHexString = function() {
  return this.toString(16);
};

В этой среде ключевое слово this указывает на экземпляр класса Number, поэтому можно полностью использовать все методы класса Number. С этим кодом можно выполнить следующее:

var iNum = 15;
alert(iNum.toHexString());		// Вывод "F"

TIY

Поскольку число 15 равно F в шестнадцатеричной системе, будет выведено "F".

Переименование уже существующих методов

Можно также переименовать уже существующие методы в более понятные имена. Например, к классу Array можно добавить два метода enqueue() и dequeue(), которые будут反复 вызывать уже существующие методы push() и shift():

Array.prototype.enqueue = function(vItem) {
  this.push(vItem);
};
Array.prototype.dequeue = function() {
  return this.shift();
};

TIY

Добавление методов, не связанных с уже существующими методами

Конечно, можно добавить методы, не связанные с уже существующими методами. Например, предположим, что нужно определить положение элемента в массиве, для чего нет локального метода. Легко создать следующий метод:

Array.prototype.indexOf = function (vItem) {
  for (var i=0; i<this.length; i++) {
    if (vItem == this[i]) {
	  return i;
	}
  }
  return -1;
}

Этот метод indexOf() сохраняет一致性 с соответствующим методом класса String, ищет каждый элемент в массиве до тех пор, пока не найдет элемент, равный переданному. Если такой элемент найден, возвращается его положение, в противном случае возвращается -1. С этой определенностью мы можем написать следующий код:

var aColors = new Array("red","green","blue");
alert(aColors.indexOf("green")); // Вывод "1"

TIY

Добавление нового метода для локальных объектов

В конце концов, чтобы добавить новый метод для каждого локального объекта в ECMAScript, его необходимо определить на свойстве prototype объекта Object. Как было сказано в предыдущих главах, все локальные объекты наследуют объект Object, поэтому любые изменения в объекте Object будут отражены во всех локальных объектах. Например, если нужно добавить метод, который выводит текущее значение объекта с помощью предупреждения, можно использовать следующий код:

Object.prototype.showValue = function () {
  alert(this.valueOf());
};
var str = "hello";
var iNum = 25;
str.showValue(); // Вывод "hello"
iNum.showValue(); // Вывод "25"

TIY

Здесь, объекты String и Number наследуют метод showValue() от объекта Object, и при вызове этого метода на их объектах будет выводиться "hello" и "25".

Переопределение существующего метода

Как и можно определить новый метод для существующего класса, так же можно переопределить существующий метод. Как было описано в предыдущих главах, имя функции является указателем на функцию, поэтому легко можно указать на другую функцию. Если изменить локальный метод, например toString(), что произойдет?

Function.prototype.toString = function() {
  return "Function code hidden";
}

Предыдущий код полностью合法, результаты выполнения полностью соответствуют ожиданиям:

function sayHi() {
  alert("hi");
}
alert(sayHi.toString()); // Вывод "Function code hidden"

TIY

Возможно, вы помните, что в главе о объекте Function была介绍ана метод toString() функции, которая обычно выводит исходный код функции. Переопределение этого метода позволяет вернуть другой строку (в этом примере, "Function code hidden"). Но что же происходит с исходной функцией, на которую указывает toString()? Она будет переработана программой, собирающей мусор, так как она полностью弃用了. Нет способа восстановить исходную функцию, поэтому перед переопределением исходного метода безопаснее всего сохранить его указатель для дальнейшего использования. В некоторых случаях вы даже можете вызвать исходный метод в новом методе:

Function.prototype.originalToString = Function.prototype.toString;
Function.prototype.toString = function() {
  if (this.originalToString().length > 100) {
    return "Функция слишком длинна для отображения.";
  }
    return this.originalToString();
  }
};

TIY

В этом фрагменте кода первое предложение сохраняет ссылку на текущий метод toString() в свойстве originalToString. Затем метод toString() заменяется на пользовательский метод. Новый метод проверяет, длина исходного кода функции больше 100 либ. Если да, он возвращает ошибку, указывающую на то, что функция слишком длинна,否则 вызывает метод originalToString() и возвращает исходный код функции.

Поздняя привязка (Very Late Binding)

Технически,完全没有晚绑。Эта книга использует этот термин для описания явления в ECMAScript, при котором можно определить методы объекта после его инсталлирования. Например:

var o = new Object();
Object.prototype.sayHi = function () {
  alert("hi");
};
o.sayHi();

TIY

В большинстве языков программирования必须在实例ированием объекта перед определением методов объекта. Здесь метод sayHi() добавлен после создания экземпляра класса Object. В традиционных языках не слышали о такой операции, и не слышали, что该方法 автоматически назначается экземплярам объекта Object и может быть использована немедленно (в следующей строке).

Внимание:Не рекомендуется использовать метод последнего времени привязки, так как его трудно отслеживать и записывать. Однако, все же следует знать о такой возможности.