aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/global_objects/function/bind/index.html
blob: 325c24fa0b010864eb6ab4484cc4fd5090c06bbb (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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
---
title: Function.prototype.bind()
slug: Web/JavaScript/Reference/Global_Objects/Function/bind
tags:
  - ECMAScript5
  - ECMAScript6
  - Function
  - JavaScript
  - Method
  - Reference
  - polyfill
translation_of: Web/JavaScript/Reference/Global_Objects/Function/bind
---
<div>{{JSRef("Global_Objects", "Function")}}</div>

<h2 id="Summary" name="Summary">Сводка</h2>

<p>Метод <code><strong>bind()</strong></code> создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения <code>this</code> предоставленное значение. В метод также передаётся набор аргументов, которые будут установлены перед переданными в привязанную функцию аргументами при её вызове.</p>

<h2 id="Syntax" name="Syntax">Синтаксис</h2>

<pre class="syntaxbox"><code><var>fun</var>.bind(<var>thisArg</var>[, <var>arg1</var>[, <var>arg2</var>[, ...]]])</code></pre>

<h3 id="Parameters" name="Parameters">Параметры</h3>

<dl>
 <dt><code>thisArg</code></dt>
 <dd>Значение, передаваемое в качестве <code>this</code> в целевую функцию при вызове привязанной функции. Значение игнорируется, если привязанная функция конструируется с помощью оператора {{jsxref("Operators/new", "new")}}.</dd>
 <dt><code>arg1, arg2, ...</code></dt>
 <dd>Аргументы целевой функции, передаваемые перед аргументами привязанной функции при вызове целевой функции.</dd>
</dl>

<h2 id="Description" name="Description">Описание</h2>

<p>Метод <code>bind()</code> создаёт новую "<strong>привязанную функцию</strong>" (<strong>ПФ</strong>).  <strong>ПФ</strong> <span class="translation-chunk">- это "необычный </span> <span class="translation-chunk">функциональный объект" ( термин из </span> <strong>ECMAScript 6</strong> <span class="translation-chunk"> ), который является оберткой над исходным </span> <span class="translation-chunk">функциональным объектом. Вызов </span> <strong>ПФ</strong> <span class="translation-chunk">  приводит к исполнению кода обернутой функции.</span></p>

<p><strong>ПФ</strong> <span class="translation-chunk"> имеет следующие внутренние ( скрытые ) свойства:</span></p>

<ul>
 <li><span class="translation-chunk"><strong>[[BoundTargetFunction]]</strong> - оборачиваемый  (целевой ) </span> <span class="translation-chunk">функциональный </span><span class="translation-chunk">объект</span></li>
 <li><span class="translation-chunk"><strong>[[BoundThis]]</strong> - значение, которое всегда передается в качестве значения   <strong>this </strong>при вызове обернутой функции.</span></li>
 <li><span class="translation-chunk"><strong>[[BoundArguments]] </strong>- список значений, элементы которого используются в качестве первого аргумента при вызове оборачиваемой функции.</span></li>
 <li><strong><span class="translation-chunk">[[</span>Call</strong><span class="translation-chunk"><strong>]] </strong>- внутренний метод. Выполняет код (функциональное выражение), связанный с функциональным объектом. </span></li>
</ul>

<p><span class="translation-chunk">Когда <strong>ПФ </strong>вызывается, исполняется ее внутренний метод </span> <strong>[[Call]]</strong> <span class="translation-chunk"> со следующими аргументами </span> <strong>Call(<em>target</em>, <em>boundThis</em>, <em>args</em>).</strong></p>

<ul>
 <li><strong><em>target</em></strong> <span class="translation-chunk">  -    <strong>[[BoundTargetFunction]]</strong>;</span></li>
 <li><span class="translation-chunk"><em><strong>boundThis </strong></em></span><em><strong> <span class="translation-chunk"> </span> </strong></em><span class="translation-chunk"><em><strong>  </strong></em>-    </span><strong> </strong><span class="translation-chunk"><strong>[[BoundThis]]</strong>;</span></li>
 <li><em><strong>args  </strong></em> -  <strong> <span class="translation-chunk">[[BoundArguments]].</span></strong></li>
</ul>

<p>Привязанная функция также может быть сконструирована с помощью оператора {{jsxref("Operators/new", "new")}}: это работает так, как если бы вместо неё конструировалась целевая функция. Предоставляемое значение <code>this</code> в этом случае игнорируется, хотя ведущие аргументы всё ещё передаются в эмулируемую функцию.</p>

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

<h3 id="Example:_Creating_a_bound_function" name="Example:_Creating_a_bound_function">Пример: создание привязанной функции</h3>

<p>Простейшим способом использования <code>bind()</code> является создание функции, которая, вне зависимости от способа её вызова, вызывается с определённым значением <code>this</code>. Обычным заблуждением для новичков в JavaScript является извлечение метода из объекта с целью его дальнейшего вызова в качестве функции и ожидание того, что он будет использовать оригинальный объект в качестве своего значения <code>this</code> (например, такое может случиться при использовании метода как функции обратного вызова). Однако, без специальной обработки, оригинальный объект зачастую теряется. Создание привязанной функции из функции, использующей оригинальный объект, изящно решает эту проблему:</p>

<pre class="brush: js">this.x = 9;
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var getX = module.getX;
getX(); // 9, поскольку в этом случае this ссылается на глобальный объект

// создаём новую функцию с this, привязанным к module
var boundGetX = getX.bind(module);
boundGetX(); // 81
</pre>

<h3 id="Example:_Partial_Functions" name="Example:_Partial_Functions">Пример: частичные функции</h3>

<p>Следующим простейшим способом использования <code>bind()</code> является создание функции с предопределёнными аргументами. Эти аргументы (если они есть) передаются после значения <code>this</code> и вставляются перед аргументами, передаваемыми в целевую функцию при вызове привязанной функции.</p>

<pre class="brush: js">function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Создаём функцию с предустановленным ведущим аргументом
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
</pre>

<h3 id="Example:_With_setTimeout" name="Example:_With_setTimeout">Пример: с <code>setTimeout</code></h3>

<p>По умолчанию, внутри {{domxref("window.setTimeout()")}} контекст <code>this</code> устанавливается в объект {{domxref("window")}} (или <code>global</code>). При работе с методами класса, требующими <code>this</code> для ссылки на экземпляры класса, вы можете явно привязать <code>this</code> к функции обратного вызова для сохранения экземпляра.</p>

<pre class="brush: js">function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// Объявляем цветение с задержкой в 1 секунду
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log('Я прекрасный цветок с ' +
    this.petalCount + ' лепестками!');
};
</pre>

<h3 id="Example:_Bound_functions_used_as_constructors" name="Example:_Bound_functions_used_as_constructors">Пример: привязывание функций, используемых в качестве конструкторов</h3>

<div class="warning">
<p><strong>Предупреждение:</strong> этот раздел демонстрирует возможности JavaScript и документирует некоторые граничные случаи использования метода <code>bind()</code>. Показанные ниже методы не являются лучшей практикой и, вероятно, их не следует использовать в рабочем окружении.</p>
</div>

<p>Привязанные функции автоматически подходят для использования вместе с оператором {{jsxref("Operators/new", "new")}} для конструирования новых экземпляров, создаваемых целевой функцией. Когда привязанная функция используется для конструирования значения, предоставляемое значение <code>this</code> игнорируется. Однако, предоставляемые аргументы всё так же вставляются перед аргументами конструктора:</p>

<pre class="brush: js">function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() {
  return this.x + ',' + this.y;
};

var p = new Point(1, 2);
p.toString(); // '1,2'


var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// не поддерживается полифиллом, приведённым ниже,
// но отлично работает с родным bind:
var YAxisPoint = Point.bind(null, 0/*x*/);

var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true
</pre>

<p>Обратите внимание, что вам не нужно делать ничего особенного для создания привязанной функции, используемой с оператором {{jsxref("Operators/new", "new")}}. В итоге, для создания явно вызываемой привязанной функции, вам тоже не нужно делать ничего особенного, даже если вам требуется, чтобы привязанная функция вызывалась только с помощью оператора {{jsxref("Operators/new", "new")}}.</p>

<pre class="brush: js">// Пример может быть запущен прямо в вашей консоли JavaScript
// ...продолжение примера выше

// Всё ещё можно вызывать как нормальную функцию
// (хотя обычно это не предполагается)
YAxisPoint(13);

emptyObj.x + ',' + emptyObj.y;
// &gt;  '0,13'
</pre>

<p>Если вы хотите поддерживать использование привязанной функции только с помощью оператора {{jsxref("Operators/new", "new")}}, либо только с помощью прямого вызова, целевая функция должна предусматривать такие ограничения.</p>

<h3 id="Example:_Creating_shortcuts" name="Example:_Creating_shortcuts">Пример: создание сокращений</h3>

<p>Метод <code>bind()</code> также полезен в случаях, если вы хотите создать сокращение для функции, требующей определёное значение <code>this</code>.</p>

<p>Возьмём, например, метод {{jsxref("Array.prototype.slice")}}, который вы можете использовать для преобразования массивоподобного объекта в настоящий массив. Вы можете создать подобное сокращение:</p>

<pre class="brush: js">var slice = Array.prototype.slice;

// ...

slice.call(arguments);
</pre>

<p>С помощью метода <code>bind()</code>, это сокращение может быть упрощено. В следующем куске кода <code>slice</code> является функцией, привязанной к функции {{jsxref("Function.prototype.call()", "call()")}} объекта {{jsxref("Function.prototype")}}, со значением <code>this</code>, установленным в функцию {{jsxref("Array.prototype.slice()", "slice()")}} объекта {{jsxref("Array.prototype")}}. Это означает, что дополнительный вызов <code>call()</code> может быть устранён:</p>

<pre class="brush: js">// Тоже самое, что и slice в предыдущем примере
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

// ...

slice(arguments);
</pre>

<h2 id="Polyfill" name="Polyfill">Полифилл</h2>

<p>Функция <code>bind</code> является дополнением к стандарту ECMA-262 5-го издания; поэтому она может присутствовать не во всех браузерах. Вы можете частично обойти это ограничение, вставив следующий код в начало ваших скриптов, он позволяет использовать большую часть возможностей <code>bind()</code> в реализациях, не имеющих его родной поддержки.</p>

<pre class="brush: js">if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // ближайший аналог внутренней функции
      // IsCallable в ECMAScript 5
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP &amp;&amp; oThis
                 ? this
                 : oThis,
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}
</pre>

<p>Некоторые из многих отличий (так же могут быть и другие, данный список далеко не исчерпывающий) между этой реализацией и реализацией по умолчанию:</p>

<ul>
 <li>Частичная реализация предполагает, что методы {{jsxref("Array.prototype.slice()")}}, {{jsxref("Array.prototype.concat()")}}, {{jsxref("Function.prototype.call()")}} и {{jsxref("Function.prototype.apply()")}} являются встроенными, имеют своё первоначальное значение.</li>
 <li>Частичная реализация создаёт функции, не имеющие неизменяемых свойств «отравленной пилюли» — {{jsxref("Function.caller", "caller")}} и <code>arguments</code> — которые выбрасывают исключение {{jsxref("Global_Objects/TypeError", "TypeError")}} при попытке получить, установить или удалить эти свойства. (Такие свойства могут быть добавлены, если реализация поддерживает {{jsxref("Object.defineProperty")}}, либо частично реализованы [без поведения исключение-при-попытке-удаления], если реализация поддерживает расширения {{jsxref("Object.defineGetter", "__defineGetter__")}} и {{jsxref("Object.defineSetter", "__defineSetter__")}}.)</li>
 <li>Частичная реализация создаёт функции, имеющие свойство <code>prototype</code>. (Правильная привязанная функция его не имеет.)</li>
 <li>Частичная реализация создаёт привязанные функции, чьё свойство {{jsxref("Function.length", "length")}} не соответствует с определением в ECMA-262; оно равно 0, в то время, как полная реализация, в зависимости от значения свойства <code>length</code> целевой функции и количества предопределённых аргументов, может вернуть значение, отличное от нуля.</li>
</ul>

<p>Если вы решили использовать частичную реализацию, <strong>не рассчитывайте на корректную работу в тех случаях, когда реализация отклоняется от спецификации ECMA-262 5-го издания!</strong> Однако, в определённых случаях (и, возможно, с дополнительными модификациями для отдельных нужд), применение данной частичной реализации может быть вполне оправданным до тех пор, пока <code>bind()</code> не станет широко реализован в соответствии со спецификацией.</p>

<h2 id="Specifications" name="Specifications">Спецификации</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Спецификация</th>
   <th scope="col">Статус</th>
   <th scope="col">Комментарии</th>
  </tr>
  <tr>
   <td>{{SpecName('ES5.1', '#sec-15.3.4.5', 'Function.prototype.bind')}}</td>
   <td>{{Spec2('ES5.1')}}</td>
   <td>Изначальное определение. Реализована в JavaScript 1.8.5.</td>
  </tr>
  <tr>
   <td>{{SpecName('ES6', '#sec-function.prototype.bind', 'Function.prototype.bind')}}</td>
   <td>{{Spec2('ES6')}}</td>
   <td> </td>
  </tr>
 </tbody>
</table>

<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>{{CompatChrome("7")}}</td>
   <td>{{CompatGeckoDesktop("2")}}</td>
   <td>{{CompatIE("9")}}</td>
   <td>{{CompatOpera("11.60")}}</td>
   <td>{{CompatSafari("5.1.4")}}</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>{{CompatAndroid("4.0")}}</td>
   <td>{{CompatChrome("0.16")}}</td>
   <td>{{CompatGeckoMobile("2")}}</td>
   <td>{{CompatUnknown}}</td>
   <td>{{CompatOperaMobile("11.50")}}</td>
   <td>{{CompatSafari("6.0")}}</td>
  </tr>
 </tbody>
</table>
</div>

<p>На основе <a href="http://kangax.github.com/es5-compat-table/">таблицы совместимости Kangax</a>.</p>

<h2 id="See_also" name="See_also">Смотрите также</h2>

<ul>
 <li>{{jsxref("Function.prototype.apply()")}}</li>
 <li>{{jsxref("Function.prototype.call()")}}</li>
 <li>{{jsxref("Functions_and_function_scope", "Функции и их область видимости", "", 1)}}</li>
</ul>