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
|
---
title: Function.prototype.bind()
slug: Web/JavaScript/Referencia/Objetos_globales/Function/bind
translation_of: Web/JavaScript/Reference/Global_Objects/Function/bind
---
<div>{{JSRef("Global_Objects", "Function")}}</div>
<h2 id="Summary" name="Summary">Resumen</h2>
<p>El método <code><strong>bind()</strong></code> crea una nueva función, que cuando es llamada, asigna a su operador <em>this</em> el valor entregado, con una secuencia de argumentos dados precediendo a cualquiera entregados cuando la función es llamada. </p>
<p>El valor de <em>this</em> es ignorado cuando la función es llamada con el operador <em>new</em>.</p>
<h2 id="Syntax" name="Syntax">Sintaxis</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">Parametros</h3>
<dl>
<dt><code>thisArg</code></dt>
<dd>Es un valor que será enviado a la función destino cuando se llame a la función de enlace. Este valor será ignorado si la función de enlace es construida usando el operador {{jsxref("Operators/new", "new")}}.</dd>
<dt><code>arg1, arg2, ...</code></dt>
<dd>Son los argumentos que se enviarán además de los provistos a la función de enlace cuando se invoque la función destino.</dd>
</dl>
<h3 id="Valor_de_retorno">Valor de retorno</h3>
<p>Una copia de la función entregada con el valor especificado <code>this </code>y los argumentos iniciales.</p>
<h2 id="Description" name="Description">Descripción</h2>
<p>La función <code>bind()</code> crea una nueva función (<strong>función ligada</strong>) con el mismo cuerpo (propiedad interna {{jsxref("Function.prototype.call", "call")}} en términos de ECMAScript 5) como la función que será llamada (la <strong>función objetivo</strong> de la función ligada) con la referencia <code>this</code> asociada al primer argumento de <code>bind()</code>, el cual no podrá ser sobreescrito. <code>bind()</code> también acepta parámetros predeterminados que antecederán al resto de los parámetros específicos cuando la función objetivo sea llamada. Una función ligada también puede ser construída utilizando el operador {{jsxref("Operators/new", "new")}}: al hacerlo, actuará como si en su lugar hubiera sido construída la función objetivo.</p>
<p>En este último caso, el parámetro correspondiente para <code>this</code> será ignorado, aunque los parámetros predeterminados que antecederán al resto sí serán provistos para la función emulada.</p>
<h2 id="Examples" name="Examples">Ejemplos</h2>
<h3 id="Ejemplo_Crear_una_función_ligada">Ejemplo: Crear una función ligada</h3>
<p>El uso más simple de <code>bind()</code> es hacer que una función que, sin importar cómo es llamada, siempre apunte al mismo objeto con la referencia <code>this</code>. Un error común para nuevos programadores de JavaScript es que obtienen una referencia a un método de un objeto, posteriormente ejecutan ese método desde la referencia externa y esperan que la referencia de <code>this</code> siga apuntando al objeto original de donde se obtuvo el método (v.g. cuando se usa ese método en un callback). Sin el debido cuidado, el objeto original es comúnmente perdido. Creando una función ligada desde la función empleando el objeto original, resuelve limpiamente este problema:</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, porque en este caso, "this" apunta al objeto global
// Crear una nueva función con 'this' asociado al objeto original 'module'
var boundGetX = getX.bind(module);
boundGetX(); // 81</pre>
<h3 id="Ejemplo_Funciones_Parciales">Ejemplo: Funciones Parciales</h3>
<p>El siguiente uso simple de <code>bind()</code> es definir una función con argumentos predeterminados que precederán a los argumentos finales de la función ligada. Estos argumentos iniciales (en caso de haberlos) se definen a continuación de lo que será la referencia de <code>this</code> y son entonces enviados como argumentos de la función objetivo, seguidos por los argumentos enviados a la función ligada cada vez que dicha función sea llamada.</p>
<pre class="brush: js">function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// Crear funcion (sin referencia this) con argumento inicial predeterminado
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
</pre>
<h3 id="Ejemplo_Con_setTimeout">Ejemplo: Con setTimeout</h3>
<p>De manera predeterminada, dentro de {{ domxref("window.setTimeout()") }}, la palabra reservada <code>this</code> será setteada al objeto {{ domxref("window") }} (o a global). Cuando se esté trabajando con métodos de clase que requieran que <code>this</code> se refiera a instancias de clase, usted puede explícitamente ligar <code>this</code> a la función callback para mantener la referencia de la instancia.</p>
<pre class="brush: js">function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
};
</pre>
<h3 id="Ejemplo_Funciones_ligadas_usadas_como_constructores">Ejemplo: Funciones ligadas usadas como constructores</h3>
<div class="warning">
<p><strong>Advetencia:</strong> Esta sección demuestra las capacidades de JavaScript y documenta algunos usos extremos del método <code>bind()</code>. Los métodos mostrados a continuación no son la mejor forma de hacer las cosas y probablemente no deberían ser utilizados en ningún ambiente productivo.</p>
</div>
<p>Las funciones ligadas son automáticamente adecuadas para usarse con el operador {{jsxref("Operators/new", "new")}} para construir nuevas instancias creadas por la función objetivo. Cuando una función ligada es utilizada para construir un valor, el parámetro enviado para reemplazar la referencia <code>this</code> es ignorado. De cualquier forma, los argumentos iniciales sí son tomados en consideración y antecederán a los parámetros que se envíen al constructor:</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*/);
// not supported in the polyfill below,
// works fine with native 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>Note que no necesita hacer nada especial para crear una función ligada para usarse con {{jsxref("Operators/new", "new")}}. El razonamiento es que usted no necesita hacer nada especial para crear una función ligada para ser llamada planamente, aún si usted prefiriera requerir que la función ligada sea llamada únicamente utilizando {{jsxref("Operators/new", "new")}}.</p>
<pre class="brush: js">// Ejemplo que puede ser ejecutado directamente en tu consola JavaScript
// ...continúa de arriba
// Aún puede ser invocada como una función normal
// (aunque es usualmente indeseable)
YAxisPoint(13);
emptyObj.x + ',' + emptyObj.y;
// > '0,13'
</pre>
<p>Si desea utilizar una función ligada únicamente usando {{jsxref("Operators/new", "new")}}, o únicamente mediante una llamada directa, la función objetivo debe forzar esa restricción.</p>
<h3 id="Example:_Creating_shortcuts" name="Example:_Creating_shortcuts">Ejemplo: Crear atajos</h3>
<p><code>bind()</code> también es útil en casos en los que desea crear un atajo para una función que requiere una referencia específica para <code>this</code>.</p>
<p>Tomando {{jsxref("Array.prototype.slice")}}, por ejemplo, el cual se desearía utilizar para convertir un objeto tipo array a un arreglo real. Podría crear un atajo como el siguiente:</p>
<pre class="brush: js">var slice = Array.prototype.slice;
// ...
slice.call(arguments);
</pre>
<p>Con <code>bind()</code>, esto puede ser simplificado. En el siguiente fragmento de código, <code>slice</code> es una función ligada a la función {{jsxref("Function.prototype.call()", "call()")}} de {{jsxref("Function.prototype")}}, con la referencia <code>this</code> setteada a la función {{jsxref("Array.prototype.slice()", "slice()")}} de {{jsxref("Array.prototype")}}. Esto significa que llamadas adicionales a <code>call()</code> pueden omitirse:</p>
<pre class="brush: js">// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
// ...
slice(arguments);
</pre>
<h2 id="Polyfill" name="Polyfill">Polyfill</h2>
<p>La función <code>bind()</code> fue añadida a la especificación ECMA-262, 5a edición; por lo tanto podría no estar presente en todos los navegadores. Usted puede parcialmente simularla al insertar el siguiente código al inicio de sus scripts, permitiendo emplear muchas de las funcionalidades de <code>bind()</code> en implementaciones que no la soportan nativamente.</p>
<pre class="brush: js">if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
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 && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
</pre>
<p>Algunas de las muchas diferencias (bien podría haber otras, en tanto la siguiente lista no intenta ser exhaustiva) entre este algoritmo y el algoritmo de la especificación son:</p>
<ul>
<li>La implementación parcial se basa en {{jsxref("Array.prototype.slice()")}}, {{jsxref("Array.prototype.concat()")}}, {{jsxref("Function.prototype.call()")}} y {{jsxref("Function.prototype.apply()")}}, métodos incorporados para tener sus valores originales.</li>
<li>La implementación parcial crea funciones que no tienen "poison pills" inmutables {{jsxref("Function.caller", "caller")}} y las propiedades de los <code>argumentos</code> que lanzan una {{jsxref("Global_Objects/TypeError", "TypeError")}} sobre get, set, o deletion. (Esto podría ser añadido si la implementación soportara {{jsxref("Object.defineProperty")}}, o parcialmente implementada [sin el comportamiento throw-on-delete] si la implementación soportara las extensiones {{jsxref("Object.defineGetter", "__defineGetter__")}} y {{jsxref("Object.defineSetter", "__defineSetter__")}} ).</li>
<li>La implementación parcial crea funciones que tienen una propiedad <code>prototype</code>. (Las funciones ligadas no tienen ninguna).</li>
<li>La implementación parcial crea funciones ligadas cuya propiedad {{jsxref("Function.length", "length")}} no coincide con la indicada por ECMA-262: ésta crea funciones con longitud 0, mientras que la implementación completa, dependiendo de la longitud de la función objetivo y del número de argumentos pre-especificados, podría regresar una longitud mayor a zero.</li>
</ul>
<p>Si elige usar esta implementación parcial,<strong> no debe de utilizarla en los casos en los que el comportamiento es distinto al de la especificación ECMA-262, 5th edition!</strong> Con un poco de cuidado, de cualquier manera (y tal vez con algunas modificaciones adicionales para adecuarse a sus necesidades específicas), esta implementación parcial podría ser un puente razonable al momento en que <code>bind()</code> sea ampliamente implementada acorde a a la especificación.</p>
<p>Por favor checa <a href="https://github.com/Raynos/function-bind">https://github.com/Raynos/function-bind</a> para ver una solución más profunda.</p>
<h2 id="Especificaciones">Especificaciones</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Especificación</th>
<th scope="col">Estado</th>
<th scope="col">Comentarios</th>
</tr>
<tr>
<td>{{SpecName('ES5.1', '#sec-15.3.4.5', 'Function.prototype.bind')}}</td>
<td>{{Spec2('ES5.1')}}</td>
<td>Definición inicial. Implementado en 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="Compatibilidad_de_navegadores">Compatibilidad de navegadores</h2>
<div>{{CompatibilityTable}}</div>
<div id="compat-desktop">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Chrome</th>
<th>Firefox (Gecko)</th>
<th>Internet Explorer</th>
<th>Opera</th>
<th>Safari</th>
</tr>
<tr>
<td>Basic support</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>Feature</th>
<th>Android</th>
<th>Chrome for Android</th>
<th>Firefox Mobile (Gecko)</th>
<th>IE Mobile</th>
<th>Opera Mobile</th>
<th>Safari Mobile</th>
</tr>
<tr>
<td>Basic support</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>Basado en <a class="external" href="http://kangax.github.com/es5-compat-table/">Kangax's compat tables</a>.</p>
<h2 id="See_also" name="See_also">Ver también</h2>
<ul>
<li>{{jsxref("Function.prototype.apply()")}}</li>
<li>{{jsxref("Function.prototype.call()")}}</li>
<li>{{jsxref("Functions_and_function_scope", "Functions and function scope", "", 1)}}</li>
</ul>
|