[ Web Proxy ]
URL:
Viewing: https://es.javascript.info/function-object [Back]  [Original]

Funcin como objeto, NFE
ES

Queremos que este proyecto de cdigo abierto est disponible para personas de todo el mundo.

Ayuda a traducir el contenido de este tutorial a tu idioma!

    Buscar en Javascript.info:
    Buscar en el tutorial:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    Funcin como objeto, NFE

    Como ya sabemos, una funcin en JavaScript es un valor.

    Cada valor en JavaScript tiene un tipo. Qu tipo es una funcin?

    En JavaScript, las funciones son objetos.

    Una buena manera de imaginar funciones es como objetos de accin invocables. No solo podemos llamarlos, sino tambin tratarlos como objetos: agregar/eliminar propiedades, pasar por referencia, etc.

    La propiedad name

    Las funciones como objeto contienen algunas propiedades utilizables.

    Por ejemplo, el nombre de una funcin es accesible mediante la propiedad name:

    function sayHi() {
      alert("Hi");
    }
    
    alert(sayHi.name); // sayHi

    Lo que es divertido, es que la lgica de asignacin de nombres es inteligente. Tambin da el nombre correcto a una funcin, incluso si se cre sin uno:

    let sayHi = function() {
      alert("Hi");
    };
    
    alert(sayHi.name); // sayHi (hay un nombre!)

    Tambin funciona si la asignacin se realiza mediante un valor predeterminado:

    function f(sayHi = function() {}) {
      alert(sayHi.name); // sayHi (funciona!)
    }
    
    f();

    En la especificacin, esta caracterstica se denomina nombre contextual. Si la funcin no proporciona una, entonces en una asignacin se deduce del contexto.

    Los mtodos de objeto tambin tienen nombres:

    let user = {
    
      sayHi() {
        // ...
      },
    
      sayBye: function() {
        // ...
      }
    
    }
    
    alert(user.sayHi.name); // sayHi
    alert(user.sayBye.name); // sayBye

    Sin embargo, no hay magia. Hay casos en que no hay forma de encontrar el nombre correcto. En ese caso, la propiedad name est vaca, como aqu:

    // funcin creada dentro de un array
    let arr = [function() {}];
    
    alert( arr[0].name ); // <empty string>
    // el motor no tiene forma de establecer el nombre correcto, por lo que no asigna ninguno

    En la prctica, sin embargo, la mayora de las funciones tienen un nombre.

    La propiedad length

    Hay una nueva propiedad length incorporada que devuelve el nmero de parmetros de una funcin, por ejemplo:

    function f1(a) {}
    function f2(a, b) {}
    function many(a, b, ...more) {}
    
    alert(f1.length); // 1
    alert(f2.length); // 2
    alert(many.length); // 2

    Aqu podemos ver que los parmetros rest no se cuentan.

    La propiedad length a veces se usa para introspeccin en funciones que operan en otras funciones.

    Por ejemplo, en el siguiente cdigo, la funcin ask , acepta una question y un nmero arbitrario de funciones controladoras o handler para llamar.

    Una vez que un usuario proporciona su respuesta, la funcin llama a los controladores. Podemos pasar dos tipos de controladores:

    • Una funcin de cero argumentos, que solo se llama cuando el usuario da una respuesta positiva.
    • Una funcin con argumentos, que se llama en cualquier caso y devuelve una respuesta.

    Para llamar a handler de la manera correcta, examinamos la propiedad handler.length.

    La idea es que tenemos una sintaxis de controlador simple y sin argumentos para casos positivos (la variante ms frecuente), pero tambin podemos admitir controladores universales:

    function ask(question, ...handlers) {
      let isYes = confirm(question);
    
      for(let handler of handlers) {
        if (handler.length == 0) {
          if (isYes) handler();
        } else {
          handler(isYes);
        }
      }
    
    }
    
    // para una respuesta positiva, se llaman ambos controladores
    // para respuesta negativa, solo el segundo
    ask("Question?", () => alert('You said yes'), result => alert(result));

    Este es un caso particular llamado polimorfismo tratar los argumentos de manera diferente segn su tipo o, en nuestro caso, segn la longitud. La idea tiene un uso en las bibliotecas de JavaScript.

    Propiedades personalizadas

    Tambin podemos agregar nuestras propias propiedades.

    Aqu agregamos la propiedad counter para registrar el recuento total de llamadas:

    function sayHi() {
      alert("Hi");
    
      //vamos a contar las veces que se ejecuta
      sayHi.counter++;
    }
    sayHi.counter = 0; // valor inicial
    
    sayHi(); // Hi
    sayHi(); // Hi
    
    alert( `Called ${sayHi.counter} times` ); //  Llamamos 2 veces
    Una propiedad no es una variable

    Una propiedad asignada a una funcin como sayHi.counter = 0 no define una variable local counter dentro de ella. En otras palabras, una propiedad counter y una variable let counter son dos cosas no relacionadas.

    Podemos tratar una funcin como un objeto, almacenar propiedades en ella, pero eso no tiene ningn efecto en su ejecucin. Las variables no son propiedades de la funcin y viceversa. Estos solo son dos mundos paralelos.

    Las propiedades de la funcin a veces pueden reemplazar las clausuras o closures. Por ejemplo, podemos reescribir el ejemplo de la funcin de contador del captulo mbito de Variable y el concepto "closure" para usar una propiedad de funcin:

    function makeCounter() {
      // en vez de:
      // let count = 0
    
      function counter() {
        return counter.count++;
      };
    
      counter.count = 0;
    
      return counter;
    }
    
    let counter = makeCounter();
    alert( counter() ); // 0
    alert( counter() ); // 1

    count ahora se almacena en la funcin directamente, no en su entorno lxico externo.

    Es mejor o peor que usar una clausura (closure)?

    La principal diferencia es que si el valor de count vive en una variable externa, entonces el cdigo externo no puede acceder a l. Solo las funciones anidadas pueden modificarlo. Y si est vinculado a una funcin, entonces tal cosa es posible:

    function makeCounter() {
    
      function counter() {
        return counter.count++;
      };
    
      counter.count = 0;
    
      return counter;
    }
    
    let counter = makeCounter();
    
    counter.count = 10;
    alert( counter() ); // 10

    Por lo tanto, la eleccin de la implementacin depende de nuestros objetivos.

    Expresin de Funcin con Nombre

    Named Function Expression, o NFE, es un trmino para Expresiones de funciones que tienen un nombre.

    Por ejemplo, tomemos una expresin de funcin ordinaria:

    let sayHi = function(who) {
      alert(`Hello, ${who}`);
    };

    Y agrgale un nombre:

    let sayHi = function func(who) {
      alert(`Hello, ${who}`);
    };

    Logramos algo aqu? Cul es el propsito de ese nombre adicional de "func"?

    Primero, tengamos en cuenta que todava tenemos una Expresin de Funcin. Agregar el nombre "func" despus de function no lo convirti en una Declaracin de Funcin, porque todava se crea como parte de una expresin de asignacin.

    Agregar ese nombre tampoco rompi nada.

    La funcin todava est disponible como sayHi():

    let sayHi = function func(who) {
      alert(`Hello, ${who}`);
    };
    
    sayHi("John"); // Hello, John

    Hay dos cosas especiales sobre el nombre func, que le hacen til:

    1. Permite que la funcin se haga referencia internamente.
    2. No es visible fuera de la funcin

    Por ejemplo, la funcin sayHi a continuacin se vuelve a llamar a s misma con "Guest" si no se proporciona who:

    let sayHi = function func(who) {
      if (who) {
        alert(`Hello, ${who}`);
      } else {
        func("Guest"); // usa func para volver a llamarse a s misma
      }
    };
    
    sayHi(); // Hello, Guest
    
    // Pero esto no funcionar.
    func(); // Error, func no est definido (no visible fuera de la funcin)

    Por qu usamos func? Quizs solo usa sayHi para la llamada anidada?

    En realidad, en la mayora de los casos podemos:

    let sayHi = function(who) {
      if (who) {
        alert(`Hello, ${who}`);
      } else {
        sayHi("Guest");
      }
    };

    El problema con ese cdigo es que sayHi puede cambiar en el cdigo externo. Si la funcin se asigna a otra variable, el cdigo comenzar a dar errores:

    let sayHi = function(who) {
      if (who) {
        alert(`Hello, ${who}`);
      } else {
        sayHi("Guest"); // Error: sayHi no es una funcin
      }
    };
    
    let welcome = sayHi;
    sayHi = null;
    
    welcome(); // Error, la llamada sayHi anidada ya no funciona!

    Eso sucede porque la funcin toma sayHi de su entorno lxico externo. No hay sayHi local, por lo que se utiliza la variable externa. Y en el momento de la llamada, ese sayHi externo es nulo.

    El nombre opcional que podemos poner en la Expresin de funcin est destinado a resolver exactamente este tipo de problemas.

    Usmoslo para arreglar nuestro cdigo:

    let sayHi = function func(who) {
      if (who) {
        alert(`Hello, ${who}`);
      } else {
        func("Guest"); // Ahora todo va bien
      }
    };
    
    let welcome = sayHi;
    sayHi = null;
    
    welcome(); // Hello, Guest (la llamada anidada funciona)

    Ahora funciona, porque el nombre "func" es una funcin local. No se toma desde el exterior (y no es visible all). La especificacin garantiza que siempre har referencia a la funcin actual.

    El cdigo externo todava tiene su variable sayHi o welcome. Y func es el nombre de funcin interna con el que la funcin puede llamarse a s misma de manera confiable.

    No existe tal cosa para la Declaracin de funciones

    La caracterstica nombre interno descrita aqu solo est disponible para Expresiones de funciones, no para Declaraciones de funciones. Para las declaraciones de funciones, no hay sintaxis para agregar un nombre interno.

    A veces necesitamos un nombre interno confiable, este es un motivo para reescribir una Declaracin de funcin en una Expresin de funcin con nombre.

    Resumen

    Las funciones son objetos.

    Aqu cubrimos sus propiedades:

    • name El nombre de la funcin. Por lo general, se toma de la definicin de la funcin, pero si no hay ninguno, JavaScript intenta adivinarlo por el contexto (por ejemplo, una asignacin).
    • length El nmero de argumentos en la definicin de la funcin. Los parmetros rest no se cuentan.

    Si la funcin se declara como una Expresin de funcin (no en el flujo de cdigo principal), y lleva el nombre, se llama Expresin de Funcin con Nombre (Named Function Expression). El nombre se puede usar dentro para hacer referencia a s mismo, para llamadas recursivas o similares.

    Adems, las funciones pueden tener propiedades adicionales. Muchas bibliotecas de JavaScript conocidas hacen un gran uso de esta funcin.

    Crean una funcin principal y le asignan muchas otras funciones auxiliares. Por ejemplo, la biblioteca jQuery crea una funcin llamada $. La biblioteca lodash crea una funcin _, y luego agrega _.clone, _.keyBy y otras propiedades (mira los docs cuando quieras aprender ms sobre ello). En realidad, lo hacen para disminuir su contaminacin del espacio global, de modo que una sola biblioteca proporciona solo una variable global. Eso reduce la posibilidad de conflictos de nombres.

    Por lo tanto, una funcin puede hacer un trabajo til por s misma y tambin puede tener muchas otras funcionalidades en las propiedades.

    Tareas

    importancia: 5

    Modifique el cdigo de makeCounter() para que el contador tambin pueda disminuir y establecer el nmero:

    • counter() debe devolver el siguiente nmero (como antes).
    • counter.set(value) debe establecer el contador a value.
    • counter.decrease() debe disminuir el contador en 1.

    Consulte el cdigo en el entorno de pruebas para ver el ejemplo de uso completo.

    P.D. Puedes usar un closure o la propiedad de funcin para mantener el recuento actual. O escribe ambas variantes.

    Abrir en entorno controlado con pruebas.

    solucin

    La solucin usa count en la variable local, pero los mtodos de suma se escriben directamente en el counter. Comparten el mismo entorno lxico externo y tambin pueden acceder al count actual.

    function makeCounter() {
      let count = 0;
    
      function counter() {
        return count++;
      }
    
      counter.set = value => count = value;
    
      counter.decrease = () => count--;
    
      return counter;
    }

    Abrir la solucin con pruebas en un entorno controlado.

    importancia: 2

    Escriba la funcin sum que funcionara as:

    sum(1)(2) == 3; // 1 + 2
    sum(1)(2)(3) == 6; // 1 + 2 + 3
    sum(5)(-1)(2) == 6
    sum(6)(-1)(-2)(-3) == 0
    sum(0)(1)(2)(3)(4)(5) == 15

    P.D. Sugerencia: es posible que deba configurar una conversin personalizada objeto a primitiva en su funcin.

    Abrir en entorno controlado con pruebas.

    solucin
    1. Para que todo funcione de cualquier forma, el resultado de sum debe ser una funcin.
    2. Esa funcin debe mantener en la memoria el valor actual entre llamadas.
    3. Segn la tarea, la funcin debe convertirse en el nmero cuando se usa en ==. Las funciones son objetos, por lo que la conversin se realiza como se describe en el captulo Conversin de objeto a valor primitivo, y podemos proporcionar nuestro propio mtodo para devolver el nmero.

    Ahora el cdigo:

    function sum(a) {
    
      let currentSum = a;
    
      function f(b) {
        currentSum += b;
        return f;
      }
    
      f.toString = function() {
        return currentSum;
      };
    
      return f;
    }
    
    alert( sum(1)(2) ); // 3
    alert( sum(5)(-1)(2) ); // 6
    alert( sum(6)(-1)(-2)(-3) ); // 0
    alert( sum(0)(1)(2)(3)(4)(5) ); // 15

    Tenga en cuenta que la funcin sum en realidad solo funciona una vez. Devuelve la funcin f.

    Luego, en cada llamada posterior, f agrega su parmetro a la sumacurrentSum, y se devuelve.

    No hay recursividad en la ltima lnea de f.

    As es como se ve la recursividad:

    function f(b) {
      currentSum += b;
      return f(); // <-- llamada recursiva
    }

    Y en nuestro caso, solo devolvemos la funcin, sin llamarla:

    function f(b) {
      currentSum += b;
      return f; // <-- no se llama a s mismo, se devuelve
    }

    Esta f se usar en la prxima llamada, nuevamente se devolver, tantas veces como sea necesario. Luego, cuando se usa como un nmero o una cadena, el toString devuelve el currentSum. Tambin podramos usar Symbol.toPrimitive o valueOf para la conversin.

    Abrir la solucin con pruebas en un entorno controlado.

    Mapa del Tutorial

    Comentarios

    lea esto antes de comentar
    • Si tiene sugerencias sobre qu mejorar, por favor enviar una propuesta de GitHub o una solicitud de extraccin en lugar de comentar.
    • Si no puede entender algo en el artculo, por favor explique.
    • Para insertar algunas palabras de cdigo, use la etiqueta <code>, para varias lneas envolverlas en la etiqueta <pre>, para ms de 10 lneas utilice una entorno controlado (sandbox) (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page