JavaScript动态执行JS代码的四种方法

 更新时间:2025年06月17日 08:27:54   作者:程序员小寒  
这篇文章主要介绍了JavaScript动态执行代码的四种方法:eval、new Function、setTimeout及script标签,并提及webpack中eval用于devtool配置,new Function优化插件机制,强调安全性和性能差异,需要的朋友可以参考下

今天来聊一聊javascript如何动态执行js代码,我总结了以下四种方法。

第一种方式:eval

eval函数会将传入的字符串作为js代码执行,并且返回最后一个表达式的值。

eval('console.log(1)') // 1

eval的特点:

  • 同步执行;
  • 执行环境为当前作用域
let a = 1;
function test() {
  let a = 2;
  eval('console.log(a)'); // 2
}
test();

使用eval需要注意:

  • 安全风险:任何时候都不要把用户的输入放入eval中执行,可能被注入恶意代码(如 eval('alert("XSS")'))。
  • 性能差:eval 会中断 JavaScript 引擎的优化,导致执行速度变慢。
  • 可读性和维护性差:动态生成的代码难以调试和维护。

第二种方式:new Function

可以通过构造函数Function动态创建一个函数,然后主动执行它。

Function的函数签名如下:

new Function([arg1, arg2, ...argN], functionBody)

其中,arg1, arg2, ...argN 是参数名,functionBody 是函数体。

let a = 1;
function test() {
  let a = 2;
  let fn = new Function('console.log(a)');
  fn(); // 1
}
test();

new Function的特点:

  • 同步执行;
  • 执行环境为全局作用域

第三种方式:setTimeout

平常我们使用setTimeout第一个传递的是一个函数,第二个参数是延迟执行的时间。

setTimeout(functionRef, delay);

但其实,setTimeout的第一个参数也可以是一个字符串,表示要执行的代码。

setTimeout('console.log(1)', 1000); // 1

来看看setTimeout执行的作用域:

let a = 1;
function test() {
  let a = 2;
  setTimeout('console.log(a)', 1000); // 1
}
test();

所以setTimeout的特点如下:

  • 异步执行;
  • 执行环境为全局作用域

第四种方式:script标签

在浏览器环境中,我们可以动态创建script标签来执行代码。

var a = 1;
let script = document.createElement('script');
script.textContent = 'console.log(1)';
document.body.appendChild(script); // 1

这个都不用多说了,肯定是全局作用域,所以script动态执行的特点如下:

  • 同步执行;
  • 执行环境为全局作用域

应用场景

动态执行js这个功能在业务开发几乎不用用到,但在一些打包工具中会用到,比如webpack

1. devtool使用eval

webpack的配置文件webpack.config.js,有一项关于devtool的配置。

// webpack.config.js
module.exports = {
  devtool: 'eval-source-map',
}

当把devtool设置为eval-source-map时,webpack打包出来的代码会使用eval进行包裹。

打包前的代码:

// ./src/index.js
console.log(1)

打包后的产物长这样,这里我使用的是webpack5

// bundle.js
(() => {
  var __webpack_modules__ = ({
    "./src/index.js":
      (() => {
        eval("console.log(1)//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvaW5kZXguanMiLCJtYXBwaW5ncyI6IkFBQUEiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly93ZWJwYWNrLWRlbW8vLi9zcmMvaW5kZXguanM/YjYzNSJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zb2xlLmxvZygxKSJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./src/index.js\n");

      })

  });
  var __webpack_exports__ = {};
  __webpack_modules__["./src/index.js"]();
})();

这样的好处是:

  • source-map映射内置在打包后的js文件中,不会生产单独的source-map文件;
  • 由于是用eval直接包裹,所以构建速度快,适合开发环境调试使用。

顺便提一下,开发环境一般会使用eval-cheap-module-source-map,相比于eval-source-map

  • cheap: 不生成列映射,只生成行映射,生成的映射文件体积更小;
  • module: 生成映射文件时,会保留模块的路径信息,方便调试。

生产环境如果需要调试的话,一般会使用全量的最完整的sourcemap,也就是devtool: 'source-map',这样生成的映射文件虽然体积最大,但调试体验最好。

2. tapable中使用 new Function

webpack的编译过程中,tapable 实现了在编译过程中的一种发布订阅者模式的插件 Plugin 机制。在tapable的源码中,就用到了new Function

简单举个例子:

// Tapable 动态生成的调用函数(伪代码)
const hook = new SyncHook(["arg1", "arg2"]);
hook.tap("plugin1", (arg1, arg2) => console.log(arg1, arg2));
hook.tap("plugin2", (arg1, arg2) => console.log(arg2, arg1));

这里用到了SyncHook做了一个监听,按传统的发布订阅的实现的话,内部会用callbacks.forEach(fn => fn(...args)))进行调用,每次触发事件都需要动态遍历回调数组,性能较低,所以tapablenew Function做了优化。

// 动态生成的调用逻辑
const compiledFn = new Function("arg1", "arg2", `
 plugin1Fn(arg1, arg2);
 plugin2Fn(arg2, arg1);
`);
compiledFn("a", "b");

这里直接用new Function把逻辑进行动态组装成一个函数,节省了上下文开销,实现更加高效的事件触发逻辑,尤其是在处理大量钩子(Hooks)和插件时。

总结

主要介绍了四种动态执行js的方法:

  • eval: 同步,当前作用域;
  • new Function: 同步,全局作用域;
  • script标签: 同步,全局作用域;
  • setTimeout: 异步,全局作用域。

还简单介绍了动态执行的应用场景,比如webpackdevtool配置使用到了evaltapable中使用new Function

以上就是JavaScript动态执行JS代码的四种方法的详细内容,更多关于JavaScript动态执行JS代码的资料请关注脚本之家其它相关文章!

相关文章

  • Javascript 圆角div的实现代码

    Javascript 圆角div的实现代码

    为什么要做圆角的div: 圆角div平滑美观,某些情况下有比较不错的效果。比如说要做一个报message的消息框,那么动态的生成一个圆角div则很有意义。而对html样式控制的css本身是不直接支持圆角div的。
    2009-10-10
  • 小程序实现瀑布流动态加载列表

    小程序实现瀑布流动态加载列表

    这篇文章主要为大家详细介绍了小程序实现瀑布流动态加载列表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • uniapp中微信小程序与H5相互跳转以及传参详解(webview)

    uniapp中微信小程序与H5相互跳转以及传参详解(webview)

    在单位做项目的时候碰到一个需求,需要从微信小程序跳转到H5页面,下面这篇文章主要给大家介绍了关于uniapp中微信小程序与H5相互跳转以及传参的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • 原生js实现的金山打字小游戏(实例代码详解)

    原生js实现的金山打字小游戏(实例代码详解)

    这篇文章主要介绍了原生js实现的金山打字小游戏,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • javascript笛卡尔积算法实现方法

    javascript笛卡尔积算法实现方法

    这篇文章主要介绍了javascript笛卡尔积算法实现方法,实例分析了笛卡尔积算法的javascript实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • JavaScript的Object.defineProperty详解

    JavaScript的Object.defineProperty详解

    本篇文章给大家详细讲述了JavaScript的Object.defineProperty的相关知识点内容,有兴趣的朋友参考学习下。
    2018-07-07
  • 前端知识点之Javascript选择输入框confirm用法

    前端知识点之Javascript选择输入框confirm用法

    这篇文章主要介绍了JavaScript中的confirm方法的基本用法、功能特点、注意事项及常见用途,文中通过代码介绍的非常详细,对大家学习或者使用js具有一定的参考借鉴价值,需要的朋友可以参考下
    2025-02-02
  • OpenLayer学习之自定义测量控件

    OpenLayer学习之自定义测量控件

    这篇文章主要为大家详细 介绍了OpenLayer学习之自定义测量控件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • 微信小程序五子棋游戏AI实现方法【附demo源码下载】

    微信小程序五子棋游戏AI实现方法【附demo源码下载】

    这篇文章主要介绍了微信小程序五子棋游戏AI实现方法,结合实例形式分析了五子棋游戏中人机对战的AI原理及相关实现技巧,并附带demo源码供读者下载参考,需要的朋友可以参考下
    2019-02-02
  • Firefox 无法获取cssRules 的解决办法

    Firefox 无法获取cssRules 的解决办法

    Firefox 无法获取cssRules 的解决办法...
    2006-10-10

最新评论