JavaScript. Подробное руководство, 6-е издание, стр. 122

Заимствоваться могут не только методы класса

<b>Array</b>
: мы можем реализовать собственные универсальные методы. В примере 9.9 определяются обобщенные методы
<b>toString()</b>
и
<b>equals(),</b>
которые с успехом могут использоваться в таких классах, как
<b>Range, Complex</b>
и
<b>Card</b>
. Если бы класс Range не имел собственного метода
<b>equals(),</b>
мы могли бы заимствовать обобщенный метод
<b>equals()</b>
, как показано ниже:

<b>Range.prototype.equals = generic.equals;</b>

Обратите внимание, что метод

<b>generic.equals()</b>
выполняет лишь поверхностное сравнение и не подходит для использования в классах, свойства экземпляров которых ссылаются на объекты с их собственными методами
<b>equals().</b>
Отметьте также, что этот метод включает специальный случай для обработки свойства, добавляемого к объектам при включении их в множество Set (пример 9.6).

Пример 9.9. Обобщенные методы, пригодные для заимствования

<b>var generic = {</b>

<b>  // Возвращает строку, включающую имя функции-конструктора, если доступно,</b>

<b>  // и имена и значения всех неунаследованных свойств, не являющихся функциями.</b>

<b>  toString: function() {</b>

<b>    var s = '[';</b>

<b>    // Если объект имеет конструктор и конструктор имеет имя, использовать</b>

<b>    // это имя класса как часть возвращаемой строки. Обратите внимание, что</b>

<b>    // свойство name функций является нестандартным и не поддерживается повсеместно,</b>

<b>    if (this.constructor &amp;&amp; this.constructor.name) s += this.constructor.name + &quot;;</b>

<b>    // Теперь обойти все неунаследованные свойства, не являющиеся функциями</b>

<b>    var n = 0;</b>

<b>    for(var name in this) {</b>

<b>      if (!this.hasOwnProperty(name)) continue; // пропустить унаслед.</b>

<b>      var value = this[name];</b>

<b>      if (typeof value === ’function&quot;) continue; // пропустить методы</b>

<b>      if (n++) s += &quot;, &quot;;</b>

<b>      s += name + '=' + value;</b>

<b>    }</b>

<b>    return s + ']';</b>

<b>  },</b>

<b>  // Проверить равенство, сравнив конструкторы и свойства экземпляров объектов this</b>

<b>  // и that. Работает только с классами, свойства экземпляров которых являются</b>

<b>  // простыми значениями и могут сравниваться с помощью оператора ===.</b>

<b>  // Игнорировать специальное свойство, добавляемое классом Set.</b>

<b>  equals: function(that) {</b>

<b>    if (that == null) return false;</b>

<b>    if (this.constructor !== that.constructor) return false;</b>

<b>    for(var name in this) {</b>

<b>      if (name === &quot;|**objectid**|&quot;) continue; // пропустить спец. св.</b>

<b>      if (!this.hasOwnProperty(name)) continue; // пропустить унасл. св.</b>

<b>      if (this[name] !== that[name]) return false; // сравнить значения</b>

<b>    }</b>

<b>    return true; // Объекты равны, если все свойства равны.</b>

<b>  }</b>

<b>};</b>

9.6.6. Частные члены

В классическом объектно-ориентированном программировании зачастую целью инкапсуляции, или сокрытия данных объектов внутри объектов, является обеспечение доступа к этим данным только через методы объекта и запрет прямого доступа к важным данным. Для достижения этой цели в таких языках, как Java, поддерживается возможность объявления «частных» (

<b>private</b>
) полей экземпляров класса, доступных только через методы экземпляров класса и невидимые за пределами класса.

Реализовать частные поля экземпляра можно с помощью переменных (или аргументов), хранящихся в замыкании, образуемом вызовом конструктора, который создает экземпляр. Для этого внутри конструктора объявляются функции (благодаря чему она получает доступ к аргументам и локальным переменным конструктора), которые присваиваются свойствам вновь созданного объекта. Этот прием демонстрируется в примере 9.10, где он используется для создания инкапсулированной версии класса

<b>Range</b>
. Вместо простых свойств
<b>from</b>
и
<b>to</b>
, определяющих границы диапазона, экземпляры этой новой версии класса предоставляют методы
<b>from</b>
и
<b>to</b>
, возвращающие значения границ. Методы
<b>from()</b>
и
<b>to()</b>
не наследуются от прототипа, а определяются отдельно для каждого объекта
<b>Range</b>
. Остальные методы класса
<b>Range</b>
определяются в прототипе как обычно, но изменены так, чтобы вместо чтения значений границ напрямую из свойств они вызывали бы методы
<b>from()</b>
и
<b>to().</b>

Пример 9.10. Класс Range со слабо инкапсулированными границами

<b>function Range(from, to) {</b>