JavaScript 严格模式下 arguments 的区别

标签:#前端 #JavaScript #严格模式 #arguments #学习笔记

一、arguments 是什么?

arguments 是函数内部的类数组对象(Array-like),包含了函数调用时传入的所有实参。

javascript 复制代码
function foo() {
  console.log(arguments);       // [1, 2, 3]
  console.log(arguments[0]);    // 1
  console.log(arguments.length); // 3
}
foo(1, 2, 3);

⚠️ 它不是真正的数组 ,没有 pushmapforEach 等方法(除非用 Array.from() 转换)。

二、如何开启严格模式

javascript 复制代码
// 全局严格模式
'use strict';

// 函数级严格模式
function bar() {
  'use strict';
  // 此函数内启用严格模式
}

三、严格模式 vs 非严格模式的核心区别

🔴 区别一:arguments 不可被修改来影响命名参数(最重要)

非严格模式(二者联动)

scss 复制代码
function foo(a, b) {
  console.log(a, b);        // 1, 2
  arguments[0] = 100;
  console.log(a, b);        // 100, 2  ← a 被改变了!
}
foo(1, 2);

非严格模式下,修改 arguments[n] 会同步修改对应的命名参数。

严格模式(二者独立)

javascript 复制代码
'use strict';
function foo(a, b) {
  console.log(a, b);        // 1, 2
  arguments[0] = 100;
  console.log(a, b);        // 1, 2  ← a 没变!
}
foo(1, 2);

严格模式下,arguments 和命名参数完全独立,互不影响。

🔴 区别二:arguments.callee 被禁用

非严格模式(可用)

javascript 复制代码
function factorial(n) {
  if (n <= 1) return 1;
  return n * arguments.callee(n - 1);  // ✅ 正常执行
}
console.log(factorial(5)); // 120

arguments.callee 指向当前正在执行的函数本身,常用于匿名函数递归。

严格模式(报错)

javascript 复制代码
'use strict';
function factorial(n) {
  if (n <= 1) return 1;
  return n * arguments.callee(n - 1);  // ❌ TypeError!
}

严格模式下访问 arguments.callee 会直接抛出 TypeError

✅ 替代方案

kotlin 复制代码
// 方案1:命名函数直接调用自身
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

// 方案2:使用箭头函数 + 函数名(尾递归友好)
const factorial = (n) => {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
};

// 方案3:用函数表达式赋给变量
const factorial = function f(n) {
  if (n <= 1) return 1;
  return n * f(n - 1);
};

🔴 区别三:arguments.caller 被禁用

非严格模式

scss 复制代码
function inner() {
  console.log(arguments.caller);  // 返回调用 inner 的外部函数
}
function outer() {
  inner();
}
outer();

严格模式

javascript 复制代码
'use strict';
function inner() {
  console.log(arguments.caller);  // ❌ TypeError!
}

arguments.callerarguments.callee 在严格模式下都被禁止,原因是它们存在安全隐患(可以访问调用栈)。

🟡 区别四:arguments 不会追踪剩余参数(Spread Rest)

严格模式引入了 ...rest 语法,它与 arguments 的行为完全不同:

javascript 复制代码
'use strict';

function foo(a, ...rest) {
  console.log(arguments.length); // 实参个数
  console.log(rest.length);      // 剩余参数个数
}

foo(1, 2, 3, 4);
// arguments.length → 4(所有实参)
// rest.length → 3(去掉 a 之后的部分:[2, 3, 4])

关键区别

  • arguments:类数组,包含所有实参
  • ...rest真正的数组 ,只包含未匹配命名参数的部分

四、完整对比表

特性

非严格模式

严格模式

修改 arguments[n] 影响命名参数

✅ 会影响

❌ 不影响

arguments.callee

✅ 可用

❌ TypeError

arguments.caller

✅ 可用

❌ TypeError

arguments 与 rest 参数共存

✅ 可共存

✅ 可共存(但行为独立)

五、为什么严格模式要限制 arguments?

1. 性能优化

非严格模式下,JS 引擎必须维护 arguments 和参数之间的双向绑定关系,这导致无法对函数参数进行某些优化。严格模式下二者独立,引擎可以更高效地处理参数。

2. 安全性

arguments.calleearguments.caller 允许访问调用栈,存在被利用来进行安全攻击的风险。

3. 代码可读性

现代 JS 推荐使用命名函数rest 参数 替代 arguments 的各种黑魔法,代码更清晰。

六、现代推荐写法

javascript 复制代码
'use strict';

// ❌ 旧写法:依赖 arguments
function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

// ✅ 新写法:使用 rest 参数
function sum(...nums) {
  return nums.reduce((acc, n) => acc + n, 0);
}

// ✅ 新写法:rest + 命名参数结合
function log(prefix, ...messages) {
  messages.forEach(msg => console.log(prefix, msg));
}
log('[INFO]', 'hello', 'world');

总结

严格模式的核心改变 :将 arguments 从一个"神奇的对象"变成了一个普通的类数组,切断了它与命名参数的隐式绑定,并禁用了不安全的 callee/caller 属性。在现代 JS 开发中,推荐使用 ...rest 参数替代 arguments

相关推荐
顺颂时绥_110 分钟前
前端大图片压缩与安卓/苹果设备矫正实践
前端
Allshadow11 分钟前
Nest.js - 目录结构
javascript·nestjs
Csvn13 分钟前
JSON.parse 大数精度丢失:一个让前后端互相甩锅的 Bug
前端
张元清19 分钟前
React useCookie Hook:把 Cookie 变成响应式状态(2026)
javascript·react.js
Helen_cai31 分钟前
OpenHarmony 项目统一全局样式、尺寸、色彩主题封装 ThemeUtil(API23)
开发语言·前端·javascript·华为·harmonyos
郑州光合科技余经理32 分钟前
家政O2O平台解析:从0搭建上门预约小程序解决方案
android·java·开发语言·前端·小程序·架构·php
小徐_233344 分钟前
AI 写 wot-ui 总在猜 API?我们把 Skills、MCP 和 CLI 都配好了
前端·uni-app·ai编程
winfredzhang1 小时前
用 wxPython + ECharts + 阿里矢量地图,做一个可离线兜底的上海雨量看板
前端·javascript·echarts
索西引擎1 小时前
【React】Immer.js 在现代 Redux 生态中的角色:不可变性保障的工程化实现与开发体验优化
前端·javascript·react.js
kisshyshy1 小时前
《川剧变脸 × React 状态管理?我在浏览器里跑了个端侧大模型》
前端·react.js·架构