Introducción
En muchos idiomas tradicionales (c/c ++/java/c#, etc.), existen funciones como ciudadanos de segunda clase. Solo puede declarar una función con las palabras clave del idioma y luego llamarla. Si necesita pasar la función como parámetro a otra función, o asignar un valor a una variable local, o como un valor de retorno, debe hacer un avance a través de métodos especiales como el puntero de la función y el proxy (delegado).
En el mundo de JavaScript, las funciones son ciudadanos de primera clase. No solo tienen todas las formas de usar funciones tradicionales (declaraciones y llamadas), sino que también pueden asignar valores, pasar parámetros y devolver como valores simples. Dichas funciones también se denominan funciones de primera clase. No solo eso, las funciones en JavaScript también actúan como constructores de clase, y también son casos de clase de función. Tales identidades múltiples hacen que las funciones de JavaScript sean muy importantes.
1. JavaScript Función de entrada de nivel
Al igual que los idiomas ordinarios, las funciones de JavaScript también siguen el principio de declaración primero y luego usan. Los nombres de las funciones solo pueden contener letras, números, subrayadores o $, y no pueden comenzar con los números. Hay dos formas comunes de declarar funciones:
La copia del código es la siguiente:
// Declarar la función myFunc directamente
función myFunc (/ * argumentos */) {
}
// asigna funciones anónimas a la variable local myfunc
var myFunc = function (/ * argumentos */) {
}
Tenga en cuenta que existen diferencias sutiles en los métodos de declaración de dos funciones anteriores: el primer método es una función nombrada cuando se declara, ya sea una función declarada antes, después de la llamada o incluso la ubicación donde no se ejecutará (por ejemplo, después de la declaración de devolución o en una rama que nunca será verdadera), es accesible en todo el alcance; El segundo método es asignar funciones anónimas a las variables. Estrictamente hablando, esta no es una declaración de función sino una expresión de función. Antes de la asignación, no se puede acceder a esta función a ningún código, lo que significa que la asignación debe completarse antes de la llamada, de lo contrario aparecerá un error al llamar: "TypeError: Undefined no es una función". Por ejemplo:
La copia del código es la siguiente:
myFunc1 (); // se puede llamar normalmente, porque myFunc1 usa un método de declaración directa
función myFunc1 () {
}
myFunc2 (); // Error TypeError: Undefined no es una función
var myFunc2 = function () {
};
El método de llamadas básicas de las funciones se llama de la misma manera que en los idiomas tradicionales: myFunc (). Las funciones de JavaScript también admiten llamadas recursivas directas o indirectas. Por ejemplo, la función clásica de Fibonacci se puede implementar en JavaScript como este:
La copia del código es la siguiente:
función fib (n) {
if (n == 1 || n == 2) {
regresar 1;
} demás {
return fib (n - 2) + fib (n - 1);
}
}
Las funciones en JavaScript pueden manejar parámetros de longitud variable. Todos tienen una variable local llamada argumentos dentro de la función. Es un objeto similar a una matriz que contiene todos los parámetros pasados al llamar y tiene un atributo de longitud para representar el número de parámetros. Por ejemplo:
La copia del código es la siguiente:
función test () {
alerta (argumentos.length);
}
prueba (1); // 1
prueba (1, 'a'); // 2
prueba (true, [], {}); // 3 Use argumentos para implementar funciones similares a PrintF en el lenguaje C, y también se pueden utilizar para implementar el polimorfismo de los métodos.
2. Funciones avanzadas de JavaScript
2.1 Funciones anónimas y anidadas
En JavaScript, puede declarar una función sin un nombre, llamada función anónima (función anónima). Al mismo tiempo, JavaScript también permite la declaración de funciones dentro de las funciones, llamadas funciones anidadas, y el alcance de las funciones anidadas es toda la función principal.
En la parte anterior de la Declaración de la función, vi un uso de funciones anónimas y funciones anidadas. Dado que las funciones anónimas no tienen nombre, no introducirán nuevas variables para contaminar el contexto y traerán nuevos alcances variables. Por lo tanto, las funciones anónimas a menudo se usan para prevenir la contaminación ambiental global.
Hay un objeto global especial en el tiempo de ejecución de JavaScript. Este objeto almacena funciones y variables globales. En el desarrollo real, a menudo se usan varias bibliotecas de terceros o múltiples archivos JS. Si introduce accidentalmente variables duplicadas o declaraciones de funciones en el objeto global, causará confusión en la ejecución del código. Por ejemplo, dos archivos JS se introducen sucesivamente, y su propio registro de funciones se define como uso interno. La segunda función introducida sobrescribirá la definición de la primera y no arrojará ningún error. Llamar a la función de registro en la ejecución posterior puede causar un error. En este momento, usar una función anónima para envolver la lógica en todo JS puede evitar este error. Este método ha sido utilizado por la mayoría de las bibliotecas JS de código abierto.
La copia del código es la siguiente:
(function () {// función anónima
Función log (msg) {
console.log (msg);
}
// otros códigos
} ()); // ejecutar inmediatamente
El código anterior es un ejemplo simple. El alcance de la función de registro se limita a esta función anónima. La función anónima se incluye en un par de corchetes () afuera para formar una expresión de función. El valor de la expresión es una función, seguido de un par de paréntesis para indicar que la función se ejecuta de inmediato, de modo que el código original se puede ejecutar normalmente. Sin embargo, las funciones declaradas de esta manera, las variables declaradas a través de VAR, etc. son internas y no pueden ser accedidas por ningún código que no sean funciones anónimas. Si necesita exponer algunas funciones como interfaces, existen varios métodos:
La copia del código es la siguiente:
var myLib = (function (global) {
Función log (msg) {
console.log (msg);
}
log1 = log; // Método 1: Use el comportamiento predeterminado de la declaración variable sin VAR para convertirse en una variable global en log1 (no recomendado)
global.log2 = log; // Método 2: Agregue directamente el atributo LOG2 al objeto global y asignarlo a una función de registro (recomendado)
return {// Método 3: Devuelve una serie de objetos de recopilación de funciones de interfaz a través de funciones anónimas y asignarlos a la variable global MyLib (recomendado)
Registro: registro
};
}(ventana));
2.2 Función de alto orden
Si una función se usa como parámetro o valor de retorno, se denomina función de orden superior. Las funciones en JavaScript se pueden usar como funciones de orden superior, que también es una característica del primer tipo de funciones. Analicemos estos dos métodos de uso a continuación.
La copia del código es la siguiente:
función negativa (n) {
return -n; // tomar el valor opuesto de n
}
función cuadrada (n) {
regresar n*n; // cuadrado de n
}
proceso de función (nums, devolución de llamada) {
resultado var = [];
para (var i = 0, longitud = nums.length; i <longitud; i ++) {
resultado [i] = devolución de llamada (nums [i]); // Pase todos los elementos en los números de la matriz a la devolución de llamada para el procesamiento, y guarde el valor de retorno como resultado
}
resultado de retorno;
}
var nums = [-3, -2, -1, 0, 1, 2, 3, 4];
var n_neg = proceso (nums, negativo);
// n_neg = [3, 2, 1, 0, -1, -2, -3, -4];
var n_square = proceso (nums, cuadrado);
// n_square = [9, 4, 1, 0, 1, 4, 9, 16];
El código anterior muestra un ejemplo de pasar una función como parámetro en otra llamada de proceso de función. En la implementación de la función de proceso, la devolución de llamada se considera un cuadro negro, responsable de pasarle el parámetro y luego obtener el valor de retorno. La implementación específica de la devolución de llamada no está clara antes de la llamada. Solo cuando se ejecutan 20 y 22 líneas, la devolución de llamada está representada por negativa o cuadrada, respectivamente, y cada elemento se toma con el valor opuesto o el valor cuadrado.
La copia del código es la siguiente:
function Generator () {
var i = 0;
Función de retorno () {
devolver i ++;
};
}
var gen1 = generador (); // Obtener un generador de números naturales
var gen2 = generador (); // Obtener otro generador de números naturales
var r1 = gen1 (); // r1 = 0
var r2 = gen1 (); // r2 = 1
var r3 = gen2 (); // r3 = 0
var r4 = gen2 (); // R4 = 1
El código anterior muestra un ejemplo de uso de una función como valor de retorno. El generador es una función de generador de números naturales, y el valor de retorno es una función de generador de números naturales. Cada tiempo se llama al generador, una función anónima se devolverá como resultado. Esta función anónima devuelve cada número natural a su vez cuando realmente se llama. La variable I en el generador aumentará en 1 cada vez que se llama a esta función anónima, que en realidad es un cierre. Introduzcamos los cierres a continuación.
2.3 Cierre
Los cierres no son un concepto nuevo, y muchos idiomas funcionales usan cierres. En JavaScript, cuando usa variables dentro del alcance de las funciones externas en una función integrada, usa cierres. Use una analogía comúnmente utilizada para explicar la relación entre un cierre y una clase: una clase es datos con funciones, y un cierre es una función con datos.
Las variables utilizadas en los cierres tienen la característica de que no se liberan cuando la función principal regresa, sino que terminan con el final del ciclo de vida de cierre. Por ejemplo, como en el ejemplo del generador en la sección anterior, Gen1 y Gen2 usan variables independientes, respectivamente (cuando Gen1 se incrementa en 1, Gen2 no se verá afectado, y viceversa). Mientras las dos variables Gen1 o Gen2 no sean recolectadas por el motor JavaScript, sus respectivas variables no serán liberadas. En la programación de JavaScript, los cierres se usan inconscientemente. Esta característica de los cierres es fácil de usar, pero también conduce fácilmente a problemas de fuga de memoria. Por ejemplo:
La copia del código es la siguiente:
var elem = document.getElementById ('test');
elem.addeventListener ('click', function () {
alerta ('Usted hizo clic' + elem.tagname);
});
El propósito de este código es mostrar su nombre de etiqueta al hacer clic en un nodo. Registra una función anónima como una función de manejo de eventos de clic de un nodo DOM. Se hace referencia a un objeto DOM en la función, que forma un cierre. Esto generará una referencia circular, es decir: DOM-> Closary-> Dom-> Closario ... El objeto DOM no se liberará antes de que se libere el cierre; y el cierre existe como la función de manejo de eventos del objeto DOM, por lo que el cierre no se lanzará antes de que se libere el objeto DOM. Incluso si el objeto DOM se elimina en el árbol DOM, debido a la existencia de esta referencia circular, ni el objeto DOM ni el cierre se liberarán. Esta fuga de memoria se puede evitar utilizando los siguientes métodos:
La copia del código es la siguiente:
var elem = document.getElementById ('test');
elem.addeventListener ('click', function () {
alerta ('Usted hizo clic' + this.tagname); // No más directamente hace referencia a la variable ELEM
});
En el código anterior, esto se usa en lugar de ELEM (este puntero apunta al elemento DOM en sí en la función de manejo de eventos DOM), de modo que el tiempo de ejecución de JS ya no cree que la función usa las variables de clase principal, por lo que ya no forman un cierre.
Los cierres también traerán muchos problemas de fuga de memoria similares. Solo puede prestar atención a los cierres al escribir código e intentar evitar tales problemas.
2.4 Constructor de clase
Las funciones de JavaScript también se usan como constructores de clase, por lo que puede usar la nueva palabra clave para crear una instancia de la clase siempre que declare una función.
La copia del código es la siguiente:
Función persona (nombre) {
this.name = name;
this.ToString = function () {
devuelve 'hola', + this.name + '!';
};
}
var p = nueva persona ('GhostTheaven');
alerta (p); // Hola, GhostTheaven! En el ejemplo anterior, la función de la persona se usa como constructor de clase. En este momento, esto apunta al objeto de instancia recientemente creado y puede agregar propiedades y métodos a la instancia. Para la programación detallada de JavaScript orientada a objetos, consulte este artículo. Lo que quiero decir aquí es el problema del valor de retorno cuando se usa funciones de JavaScript como constructores de clase.
La copia del código es la siguiente:
función myclass (nombre) {
this.name = name;
nombre de retorno; // El valor de retorno del constructor?
}
var obj1 = new myClass ('foo');
var obj2 = myClass ('foo');
var obj3 = new MyClass ({});
var obj4 = myClass ({});
El constructor anterior es bastante especial, con una declaración de devolución, entonces, ¿qué objetos apuntan obj1 ~ obj4? El resultado real es este:
La copia del código es la siguiente:
obj1 = objeto myclass
obj2 = 'foo'
obj3 = {}
obj4 = {}
Las razones específicas se explican en este artículo, y no lo repetiré en este artículo. Dado que los constructores con valores de retorno producirán resultados extraños, no llame a las declaraciones de retorno con valores de retorno en el constructor (se puede hacer un retorno vacío).
3. JavaScript Functions Monster Nivel
Bienvenido al área de enseñanza de la función a nivel de monstruo, donde se le dará cómo enfrentar al viejo monstruo con calma y libremente. . .
3.1 Clase de funciones
Hay una clase incorporada llamada función en el tiempo de ejecución de JavaScript. Declarar una función con la palabra clave de función es en realidad una abreviatura para crear objetos de clase de función. Todas las funciones tienen todos los métodos de la clase de función, como llamar, aplicar, vincular, etc., puede verificar esta declaración a través de la instancia de la palabra clave.
Dado que la función es una clase, su constructor es la función (es en sí mismo un objeto de la clase de función), y se debe generar un objeto de función a través de la nueva palabra clave. El primer monstruo está aquí, que es cómo construir una función utilizando la clase de función. La sintaxis de la función es la siguiente:
La copia del código es la siguiente:
nueva función ([arg1 [, arg2 [, ... argn]],] functionBody)
Donde Arg1, Arg2, ... Argn es una cadena, que representa el nombre del parámetro, y FunctionBody también es una cadena, que representa el cuerpo de la función. El nombre del parámetro anterior es más o menos. El constructor de funciones tratará el último parámetro como el cuerpo de la función y los anteriores como parámetros.
La copia del código es la siguiente:
var func1 = nueva función ('nombre', 'return "hola", + nombre + "!";');
func1 ('GhostTheaven'); // Hola, GhostTheaven!
El método anterior construye una función a través de la función, que es exactamente lo mismo que otras funciones declaradas con la palabra clave de función.
Al ver esto, muchas personas pueden preguntar por qué se necesita un monstruo así. "Lo que existe es razonable", la clase de funciones tiene su propósito único. Puede usarlo para generar dinámicamente diversas lógicas de funciones, o reemplazar las funciones de la función eval, y evitar que el entorno actual sea contaminado*.
3.2 Función auto-actualización
En muchos idiomas, una vez que se ha declarado una función, no puede declarar la función del mismo nombre nuevamente, de lo contrario ocurrirán errores de sintaxis. Las funciones en JavaScript no solo pueden declararse repetidamente, sino también actualizarse. ¡El monstruo que como está aquí!
La copia del código es la siguiente:
function selfUpdate () {
Window.SelfUpdate = function () {
alerta ('¡Segunda carrera!');
};
alerta ('¡First Run!');
}
selfUpdate (); // Primera carrera!
selfUpdate (); // ¡Segunda carrera! Esta función se puede usar para la lógica que se ejecuta solo una vez, y después de la primera ejecución, se reemplaza con una nueva pieza de lógica.
resumen
Las funciones de JavaScript son muy poderosas. Mientras resuelven muchos problemas maravillosamente, también traen muchos problemas negativos. Las funciones a nivel de monstruos generalmente se usan con un uso poco conocido. A menos que sea particularmente necesario, causará dificultades de lectura en código y afectará la eficiencia del desarrollo del equipo.
* Se introdujo un modo estricto en el nuevo ECMAScript. En el modo estricto, la función EVAL es muy restringida y puede garantizar que el entorno no esté contaminado.
¿Entiendes, es muy práctico? Si hay algún lugar faltante, dame algún consejo y avanza juntos.