Fui a una entrevista anteayer y un gg me preguntó sobre algunos conocimientos de js. Había una pregunta sobre el uso de call y apply. Aunque había usado el método call hace 365 días, todavía no podía responderla. En ese momento, lo resumiré en profundidad hoy.
llamar y aplicar, su función es vincular la función a otro objeto para ejecutar.
El formato y las definiciones de parámetros de ambos:
call( thisArg [, arg1, arg2, ... ] ); // Lista de parámetros, arg1, arg2, ...
aplicar(thisArg [, argArray] ); // matriz de parámetros, argArray
Al puntero this dentro de las dos funciones anteriores se le asignará thisArg, que puede realizar el propósito de ejecutar la función como un método de otro objeto.
1. Uso sencillo de la llamada.
Primero, veamos un ejemplo simple (llamada):
Copie el código de código de la siguiente manera:
<!tipo de documento html>
<html>
<cabeza>
<título> solicitud de llamada </título>
</cabeza>
<cuerpo>
<tipo de entrada="texto" id="idTxt" valor="texto de entrada">
<tipo de script="texto/javascript">
valor var = "var global";
función mFunc()
{
this.value = "var miembro";
}
función gFunc()
{
alerta (este valor);
}
window.gFunc();// muestra gFunc, var global
gFunc.call(ventana);// muestra gFunc, var global
gFunc.call(new mFunc());// muestra mFunc, miembro var
gFunc.call(document.getElementById('idTxt'));// mostrar elemento, ingresar texto
</script>
<lenguaje de escritura="javascript">
var func = nueva función()
{
this.a = "función";
}
var func2 = función(x)
{
var a = "func2";
alerta(this.a);
alerta(x);
}
func2.call(func, "func2");// muestra func y func2
</script>
</cuerpo>
</html>
Entonces, los resultados de ejecución son los siguientes:
variable globalvariable global
var miembro
texto de entrada
función
func2
Entorno de prueba: Google Chrome10.0.648.45
Finalmente, analiza los resultados.
1. La ventana del objeto global llama a la función gFunc, y esto apunta al objeto de la ventana, por lo que este valor es var global.
2. La función gFunc llama al método de llamada. Esto apunta al primer objeto de ventana de parámetro de forma predeterminada, por lo que this.value también es una var global.
3. La función gFunc llama al método de llamada. Este valor predeterminado es el primer parámetro nuevo mFunc (), que es el objeto de mFunc. Por lo tanto, this.value es la variable miembro de mFunc.
4. La función gFunc llama al método de llamada. De forma predeterminada, esto apunta al primer control de texto de entrada de parámetro, es decir, el control con id = 'idTxt'. Por lo tanto, this.value es el texto de entrada de valor del control de entrada.
5. La función func2 llama al método de llamada. Este valor predeterminado es el primer objeto de función func de parámetro, por lo que this.value es this.a, que es func.
6. La función func2 llama al método de llamada. El segundo parámetro pertenece al parámetro del objeto de función func2, por lo que alerta (x) es el segundo parámetro func2.
2. Uso y mejora de la herencia de llamadas
js usa llamadas para simular herencia
Código de prueba:
Copie el código de código de la siguiente manera:
<!tipo de documento html>
<html>
<cabeza>
<title> llamar - solicitar heredar </title>
</cabeza>
<cuerpo>
<tipo de script="texto/javascript">
función baseA()// base Clase A
{
this.member = "miembro baseA";
this.showSelfA = función()
{
ventana.alerta(este.miembro);
}
}
función baseB()// base Clase B
{
this.member = "miembro baseB";
this.showSelfB = función()
{
ventana.alerta(este.miembro);
}
}
función extendAB()// Heredar clase de A y B
{
baseA.call(this);// llamada para A
baseB.call(this);// llamar a B
}
ventana.onload = función()
{
var extender = nueva extenderAB();
extend.showSelfA();// mostrar A
extend.showSelfB();// mostrar B
}
</script>
</cuerpo>
</html>
Los resultados de ejecución son los siguientes:miembro baseB
miembro baseB
Entorno de prueba: Google Chrome10.0.648.45
Análisis de resultados:
El resultado esperado debería ser generar el miembro baseA y el miembro baseB, pero la salida real es el miembro baseB y el miembro baseB.
(Ha sido probado en IE9, 8, 6, Maxthon, Chrome, FF, Opera, Safari, 360 y otros navegadores, y el resultado es este último: miembro baseB)
En este punto, la máquina no está equivocada, lo que requiere que realicemos un análisis en profundidad.
Podemos pensar fácilmente que esto se debe a esto. Esto apunta al objeto baseB dos veces, pero ¿es realmente así?
Para explorar la esencia, utilizamos la herramienta de depuración del navegador Chrome para establecer puntos de interrupción y depurar, y descubrimos que:
Cuando se llama a extend.showSelfA(); esto apunta a extendAB (no al objeto baseB como especulamos dos veces)
La verdadera razón es que el miembro variable miembro del objeto extendAB es sobrescrito por el miembro miembro de baseB cuando baseB.call (this) lo crea una instancia, es decir, el miembro miembro de extendAB se asigna desde el miembro baseA al miembro baseB.
Por supuesto, también podemos modificar ligeramente el código baseA anterior para verificar la exactitud de nuestro análisis de depuración:
Copie el código de código de la siguiente manera:
función baseA()// base Clase A
{
this.memberA = "miembro baseA"; // el miembro se cambia a miembroA para distinguir el miembro en baseB
this.showSelfA = función()
{
window.alert(this.memberA); // Mostrar miembroA;
}
}
Ejecute navegadores como Chrome nuevamente, los resultados son los siguientes:
miembro baseA
miembro baseB
Los resultados son los mismos que nuestras expectativas y la información de depuración de Chrome también verifica nuestra corrección:
Mejoras de herencia (prototipo)
El método de herencia simulada anterior no es el mejor después de un análisis cuidadoso.
Debido a que cada vez que se define un método miembro en una función (clase), se generará una copia de la instancia, por lo que puede usar el prototipo para realizar mejoras.
Ejemplos de mejoras son los siguientes:
Copie el código de código de la siguiente manera:
<!tipo de documento html>
<html>
<cabeza>
<title> convocatoria - solicitar prototipo </title>
</cabeza>
<cuerpo>
<tipo de script="texto/javascript">
varClase = {
crear: función()// crear función
{
función de retorno()
{
this.initialize.apply(esto, argumentos);
}
}
};
var Persona = Class.create();// Crear persona de clase
Persona.prototype = {// inicializar prototipo
inicializar: función (obj1, obj2)
{
this.obj1 = obj1;
this.obj2 = obj2;
},
mostrarse a sí mismo: función()
{
alert("obj: " + this.obj1 + " y " + this.obj2);
}
}
// clase de instancia
var persona = nueva Persona("hombre", "mujer");// dos parámetros
persona.showSelf();// mostrar persona
</script>
</cuerpo>
</html>
Los resultados de ejecución son los siguientes:
objeto: hombres y mujeres