Seleccionar página
Recientemente nos hemos encontrado con la necesidad de identificar si una determinada función es una función nativa del lenguaje Javascript o ha sido creada por código. La cuestión parece sencilla, pero cuando nos ponemos a pensar como resolverlo vemos que en principio las funciones y métodos escritos por nosotros en Javascript y los proporcionados con por el lenguaje no se diferencian a primera vista. Las funciones nativas se pueden incluso reescribir por otras nuestras, por lo que no tienen ningún privilegio o diferencia que podamos observar fácilmente.

Ya nos enfrentamos a un problema similar cuando nos preguntamos cómo diferenciar arrow function de function. En esa ocasión descubrimos dos formas de actuar, analizando el prototipo (que finalmente resultó infructuosa) y analizando la cadena devuelta por .toString()

Lamentablemente no hay nada identificable en la cadena de prototipos para localizar las funciones nativas. Es cierto que las funciones nativas no tienen prototype, ya que no pueden ser utilizadas como constructores, pero tampoco lo tienen los métodos de nuestras clases o las arrow function. Por aquí no vamos a encontrar la solución.

Por lo tanto, no nos queda más remedio que analizar el código devuelto por .toString(). Comprobamos en diferentes navegadores y motores que siempre incluye la cadena [native code]:

console.log (parseInt.toString ());
 

function parseInt() { [native code] }

Por lo tanto, con una pequeña comprobación tenemos un sencillo medio para identificar si una función es nativa o está construida por código.

function isNative(fn) {
  return fn.toString().includes('[native code]');
}

Como primera aproximación no está mal, pero cualquier código que contenga el texto '[native code]' dará positivo. Es cierto que no es un texto muy habitual, pero nada impide que ese texto aparezca en el cuerpo de una función. Por ejemplo, si preguntamos si la propia función isNativeFunction() es nativa, obtendremos un falso positivo:

console.log(isNativeFunction(isNativeFunction)); // true

Con poco esfuerzo adicional podemos hacer una comprobación un poco más completa, incluyendo si es una función, las llaves y los posibles espacios en blanco entre los elementos, el final de la cadena y el propio nombre de la función.

function isNativeFunction (fn) {
  const str = fn.toString ();
  return typeof (fn) === 'function' &&
         /\{\s*\[\s*native code\s*\]\s*\}$/.test (str) &&
         str.includes (fn.name);
}
 

Ahora se puede ejecutar una batería de pruebas con diferentes opciones y comprobar que todo funciona correctamente:

console.assert (!isNativeFunction (function () {}));
console.assert (!isNativeFunction (function* () {}));
console.assert (!isNativeFunction (() => {}));

class C {m() {}}
console.assert (!isNativeFunction (C));
console.assert (!isNativeFunction (C.prototype.m));
console.assert (!isNativeFunction (isNativeFunction));
console.assert (!isNativeFunction ({
  toString () {
    return `function x { [native code] }`;
  }
}));
console.assert (!isNativeFunction (
  function x () {
    return "function x { [native code] }";
  }
));

Pero, ¿es seguro hacer uso de .toString()?. Lo cierto es que el estándar Javascript ha sido un poco confuso en cuanto a lo que tiene que devolver la función .toString() en el caso de las funciones. No obstante, todos los navegadores y motores de Javascript han realizado una implementación muy similar, aunque con mínimas variaciones.

Recientemente se ha propuesto una revisión de la estandarización de toString() para que no tenga ambigüedades, esta propuesta se encuentra en estos momentos en Stage 4, es decir, preparado para formar parte del estándar en la próxima edición. Por ello podemos estar bastante tranquilos en su utilización.

Aunque pueda parecer una solución un poco indirecta, lo cierto es que funciona. Podemos estar tranquilos al consultar el código de la función para analizar su tipología. Este es un recurso que tenemos a nuestra disposición y con la estandarización de facto y la nueva revisión de la estandarización formal de ECMAScript es seguro utilizarlo.

Novedades

Template a fondo

Hay dos formas estándar de crear contenido en un componente de forma flexible: la etiqueta template, que se considera como uno de los pilares de los Web Components y las template string de Javascript, que son una buena alternativa para generar el Shadow DOM con interpolación de datos.

Light DOM a fondo

El Light DOM es un espacio compartido entre nuestro componente web y el DOM general, que podemos utilizar para insertar contenido o configurar nuestro componente. Es una muy interesante característica que debemos conocer.

Shadow DOM a fondo

Para que los componentes web no colisionen unos con otros es muy útil utilizar el Shadow DOM para aislar el DOM y el CSS de cada componente. Esta característica se puede aplicar también a elementos HTML sin necesidad de utilizar Custom Elements, pero es con estos donde cobra todo su potencial. Demos un repaso profundo a las capacidades del Shadow DOM.

HTMLElement a fondo

HTMLElement es una pieza clave, ya que de él heredan todos los componentes web, pero en muchas ocasiones no conocemos bien sus características. Os invitamos a dar un repaso a fondo a sus capacidades y descubrir cómo sacarle todo el partido en nuestros componentes.