Javascript Avanzado en Español
  • Introducción
  • I- Up & Going
    • 0- Prefacio
    • 1- En la programación
      • 1.1 Código
      • 1.2 Inténtalo tú mismo
      • 1.3 Operadores
      • 1.4 Valores y Tipos
      • 1.5 Comentarios del Código
      • 1.6 Variables
      • 1.7 Bloques
      • 1.8 Condicionales
      • 1.9 Bucles
      • 1.10 Funciones
      • 1.11 Scope (Ámbito)
      • 1.12 Práctica
      • 1.13 - Revisión
    • 2- En Javascript
      • 2.1 Valores y Tipos
      • 2.2 Variables
      • 2.3 Condicionales
      • 2.4 Modo estricto
      • 2.5 Funciones como Valores
      • 2.6 Identificador This
      • 2.7 Prototypes
      • 2.8 Lo Viejo y Lo Nuevo
      • 2.9 Non-JavaScript
      • 2.10 Revisión
    • 3- En YDKJS
      • 3.1 Scope & Closures
      • 3.2 This & Object Prototypes
      • 3.3 Tipos & Gramática
      • 3.4 Async & Performance
      • 3.5 ES6 & Más allá
      • 3.6 Revisión
  • II- Scope & Closures
    • 0- Prefacio
    • 1- ¿Qué es el Scope?
      • 1.1 Teoría del Compilador
      • 1.2 Entendiendo el Scope
      • 1.3 Scopes Anidados
      • 1.4 Errores
      • 1.5 Revisión
    • 2- Lexical Scope
      • 2.1 Tiempo de Lex
      • 2.2 Trucos léxicos
      • 2.3 Revisión
    • 3- Function vs. Block Scope
      • 3.1 Ámbito de las funciones
      • 3.2 Ocultación en el ámbito común
      • 3.3 Funciones como ámbitos
      • 3.4 Bloques como ámbitos
      • 3.5 Revisión (TL; DR)
    • 4- Hoisting
      • 4.1 ¿El Huevo o la Gallina?
      • 4.2 El compilador pega de nuevo
      • 4.3 Funciones Primero
      • 4.4 Revisión
    • 5- Scope Closure
      • 5.1 Ilustración
      • 5.2 Nitty Gritty
      • 5.3 Ahora puedo ver
      • 5.4 Loops + Closure
      • 5.5 Módulos
      • 5.6 Revisión
    • 6- Scope Dinámico
    • 7- Ámbito de bloque de Polyfilling
      • 7.1 Traceur
      • 7.2 Bloques implícitos vs. explícitos
      • 7.3 Rendimiento
    • 8- Lexical-this
  • III- this & Object Prototypes
    • 0- Prefacio
    • 1- this o That?
      • 1.1 ¿Porque this?
      • 1.2 Confusiones
      • 1.3 ¿Que es this?
      • 1.4 Revisión
    • 2- this, todo tiene sentido ahora!
      • 2.1 Sitio de llamada
      • 2.2 Nada más que reglas
      • 2.3 Todo en orden
Powered by GitBook
On this page

Was this helpful?

  1. III- this & Object Prototypes
  2. 2- this, todo tiene sentido ahora!

2.3 Todo en orden

Por lo tanto, ahora hemos descubierto las 4 reglas para vincular this en las llamadas de función. Todo lo que necesita hacer es encontrar el sitio de llamada e inspeccionarlo para ver qué regla se aplica. Pero, ¿qué pasa si el sitio de llamada tiene múltiples reglas elegibles? Debe haber un orden de precedencia a estas reglas, por lo que demostraremos a continuación cuál es el orden para aplicar las reglas.

Debe quedar claro que la vinculación por defecto es la regla de prioridad más baja de las 4. Por lo tanto, vamos a dejarla de lado.

¿Cuál es más precedente, vinculación implícita o vinculación explícita? Vamos a probarlo:

function foo() {
    console.log( this.a );
}

var obj1 = {
    a: 2,
    foo: foo
};

var obj2 = {
    a: 3,
    foo: foo
};

obj1.foo(); // 2
obj2.foo(); // 3

obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2

Por lo tanto, la vinculación explicita tiene prioridad sobre la vinculacion implicita, lo que significa que debe preguntar primero si se aplica la vinculación explicita antes de comprobar la vinculación implícita.

Ahora, sólo necesitamos averiguar dónde se ajusta el nuevo vinculo en la precedencia.

function foo(something) {
    this.a = something;
}

var obj1 = {
    foo: foo
};

var obj2 = {};

obj1.foo( 2 );
console.log( obj1.a ); // 2

obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3

var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4

OK, la nueva vinculación es más precedente que la vinculación implícita. Pero ¿crees que la nueva vinculación es más o menos precedente que la vinculación explícita?

Nota: new y call / apply no se pueden usar juntos, por lo que no se permite new foo.call(obj1), para probar el nuevo vinculo directamente contra el vinculo explícito. Pero todavía podemos usar una vinculación dura (hard binding) para probar la precedencia de las dos reglas.

Antes de explorar eso en un listado de código, piense en cómo funciona físicamente el vinculo duro, que es Function.prototype.bind(..) crea una nueva función de encapsulamiento que está codificada para ignorar su propia vinculación (lo que sea), y utilizar un manual que proporcionamos.

Por ese razonamiento, parecería obvio asumir que la vinculación dura (que es una forma de vinculación explícita) es más precedente que una nueva vinculación, y por lo tanto no puede ser reemplazada por una nueva.

Vamos a revisar:

function foo(something) {
    this.a = something;
}

var obj1 = {};

var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2

var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3

Whoa! bar está limitado contra obj1, pero new bar(3) no cambió obj1.a para ser 3 como habríamos esperado. En su lugar, la llamada a bar(..) con límite rígido (a obj1) puede ser reemplazada por new. Desde que se aplicó new, obtuvimos el objeto recién creado, que denominamos baz, y vemos de hecho que baz.a tiene el valor 3.

Esto debería ser sorprendente si vuelves a nuestro "falso" bind helper:

function bind(fn, obj) {
    return function() {
        fn.apply( obj, arguments );
    };
}

Si razonas sobre cómo funciona el código del ayudante, no tiene una forma para que una llamada new de operador anule la vinculación de hard-obj como acabamos de observar.

Pero el built-in Function.prototype.bind(...) como ES5 es más sofisticado, un poco así, de hecho. Aquí está el polyfill (ligeramente reformateado) proporcionado por la página MDN para bind(..):

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;
    };
}

Nota: El bind() polyfill mostrado anteriormente difiere del built-in bind(..) en ES5 con respecto a las funciones enlazadas que se usarán con new (vea más adelante por qué es útil). Debido a que el polyfill no puede crear una función sin un .prototypecomo lo hace la utilidad incorporada, hay alguna indirección matizada para aproximar el mismo comportamiento. Pise con cuidado si va a utilizar el new con una función de hard-bound y confía en este polyfill.

La parte que está permitiendo el new overriding es:

this instanceof fNOP &&
oThis ? this : oThis

// ... and:

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

vamos aqui 2 de septiembre 2017

Previous2.2 Nada más que reglas

Last updated 6 years ago

Was this helpful?