aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/global_objects/object/nosuchmethod/index.html
blob: 6f0827751f2fa389dae0490db02ac1752bb38b9e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
---
title: Object.prototype.__noSuchMethod__
slug: Web/JavaScript/Reference/Global_Objects/Object/noSuchMethod
tags:
  - JavaScript
  - Non-standard
  - Object
  - Property
  - Prototype
  - Reference
translation_of: Archive/Web/JavaScript/Object.noSuchMethod
---
<div>{{JSRef("Global_Objects", "Object")}} {{non-standard_header}}</div>

<div>Хотя свойство <strong><code>__noSuchMethod__</code></strong> и нестандартно, спецификация ECMAScript Harmony (ES6) содержит объект <strong>{{jsxref("Proxy")}}</strong>, с помощью которого вы можете сделать всё тоже самое, что и при использовании этого свойством (и даже больше).</div>

<h2 id="Summary" name="Summary">Сводка</h2>
<p>Свойство <strong><code>__noSuchMethod__</code></strong> ссылается на функцию, выполняющуюся каждый раз при вызове на объекте несуществующего метода.</p>

<h2 id="Syntax" name="Syntax">Синтаксис</h2>
<pre class="syntaxbox"><code><var>obj</var>.__noSuchMethod__ = <var>fun</var></code></pre>

<h3 id="Parameters" name="Parameters">Параметры</h3>
<dl>
 <dt><code>fun</code></dt>
 <dd>Функция, имеющая вид</dd>
 <dd>
  <pre><code>function(<var>id</var>, <var>args</var>) { . . . }</code></pre>
  <dl>
   <dt><code>id</code></dt>
   <dd>Имя вызванного несуществующего метода</dd>
   <dt><code>args</code></dt>
   <dd>Массив аргументов, переданный в метод</dd>
  </dl>
 </dd>
</dl>

<h2 id="Description" name="Description">Описание</h2>
<p>По умолчанию, при попытке вызвать не существующий в объекте метод, будет выброшено исключение {{jsxref("Global_Objects/TypeError", "TypeError")}}. Это поведение можно обойти, определив функцию <code>__noSuchMethod__</code> в качестве члена объекта. Функция принимает два аргумента, первый является именем метода, который попытались вызвать, а второй — массивом аргументов, которые были переданы в метод при его вызове. Второй аргумент является настойщим массивом (то есть, он наследуется через цепочку прототипов от {{jsxref("Array.prototype")}}), а не массивоподобным <a href="/ru/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments">объектом arguments</a>.</p>
<p>Если данный метод не может быть вызван, либо по причине того, что он установлен в {{jsxref("Global_Objects/undefined", "undefined")}} по умолчанию, либо удалён, либо вручную установлен в не-функцию, движок JavaScript вернётся к выбрасыванию исключения {{jsxref("Global_Objects/TypeError", "TypeError")}}.</p>

<h2 id="Examples" name="Examples">Примеры</h2>

<h3 id="Example:_Simple_test_of___noSuchMethod__" name="Example:_Simple_test_of___noSuchMethod__">Пример: простая проверка свойства <code>__noSuchMethod__</code></h3>
<pre class="brush: js">var o = {
    __noSuchMethod__: function(id, args) { console.log(id, '(' + args.join(', ') + ')'); }
};

o.foo(1, 2, 3);
o.bar(4, 5);
o.baz();

// Вывод
// foo (1, 2, 3)
// bar (4, 5)
// baz ()
</pre>

<h3 id="Example:_Using___noSuchMethod___to_simulate_multiple_inheritance" name="Example:_Using___noSuchMethod___to_simulate_multiple_inheritance">Пример: использование свойства <code>__noSuchMethod__</code> для симуляции множественного наследования</h3>
<p>Ниже показан пример кода, реализующего примитивную форму множественного наследования.</p>
<pre class="brush: js">// Не работает с множественным наследованием объектов в качестве родителей
function noMethod(name, args) {
    var parents = this.__parents_;

    // Пройдёмся по всем родителям
    for (var i = 0; i &lt; parents.length; i++) {
        // Если нашли функцию в родителе, вызовем её
        if (typeof parents[i][name] == 'function') {
            return parents[i][name].apply(this, args);
        }
    }

    // Если мы здесь, метод не был найден
    throw new TypeError;
}

// Используется для добавления родителя при множественном наследовании
function addParent(obj, parent) {
    // Если объект ещё не инициализирован, инициализируем его
    if (!obj.__parents_) {
        obj.__parents_ = [];
        obj.__noSuchMethod__ = noMethod;
    }

    // Добавляем родителя
    obj.__parents_.push(parent);
}
</pre>
<p>Ниже показан пример использования этой идеи.</p>
<pre class="brush: js">// Пример первого базового класса

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

NamedThing.prototype = {
    getName: function() { return this.name; },
    setName: function(newName) { this.name = newName; }
}

// Пример второго базового класса

function AgedThing(age){
    this.age = age;
}

AgedThing.prototype = {
    getAge: function() { return this.age; },
    setAge: function(age) { this.age = age; }
}

// Дочерний класс. Наследуется от NamedThing и AgedThing, а также определяет свойство address

function Person(name, age, address) {
    addParent(this, NamedThing.prototype);
    NamedThing.call(this, name);
    addParent(this, AgedThing.prototype);
    AgedThing.call(this, age);
    this.address = address;
}

Person.prototype = {
    getAddr: function() { return this.address; },
    setAddr: function(addr) { this.address = addr; }
}

var bob = new Person('Боб', 25, 'Нью-Йорк');

console.log('getAge лежит ' + (('getAge' in bob) ? 'в' : 'не в') + ' объекте bob');
console.log('возраст Боба: ' + bob.getAge());
console.log('getName лежит ' + (('getName' in bob) ? 'в' : 'не в') + ' объекте bob');
console.log('имя Боба: ' + bob.getName());
console.log('getAddr лежит ' + (('getAddr' in bob) ? 'в' : 'не в') + ' объекте bob');
console.log('адрес Боба: ' + bob.getAddr());
</pre>
<p>Вывод примера будет следующим:</p>
<pre>getAge лежит не в объекте bob
возраст Боба: 25
getName лежит не в объекте bob
имя Боба: Боб
getAddr лежит в объекте bob
адрес Боба: Нью-Йорк
</pre>

<h2 id="Specifications" name="Specifications">Спецификации</h2>
<p>Не является частью какой-либо спецификации.</p>

<h2 id="Browser_compatibility" name="Browser_compatibility">Совместимость с браузерами</h2>
<div>{{CompatibilityTable}}</div>
<div id="compat-desktop">
 <table class="compat-table">
  <tbody>
   <tr>
    <th>Возможность</th>
    <th>Chrome</th>
    <th>Firefox (Gecko)</th>
    <th>Internet Explorer</th>
    <th>Opera</th>
    <th>Safari</th>
   </tr>
   <tr>
    <td>Базовая поддержка</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatGeckoDesktop("1.0")}}</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatNo}}</td>
   </tr>
  </tbody>
 </table>
</div>
<div id="compat-mobile">
 <table class="compat-table">
  <tbody>
   <tr>
    <th>Возможность</th>
    <th>Android</th>
    <th>Chrome для Android</th>
    <th>Firefox Mobile (Gecko)</th>
    <th>IE Mobile</th>
    <th>Opera Mobile</th>
    <th>Safari Mobile</th>
   </tr>
   <tr>
    <td>Базовая поддержка</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatGeckoMobile("1.0")}}</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatNo}}</td>
    <td>{{CompatNo}}</td>
   </tr>
  </tbody>
 </table>
</div>