JS 严格模式为什么会禁用 with 语句?

作者备注:

这是我无意中看到一个小伙伴的面试题。 实话实说, 这个问题真的很冷门。 如果有面试官问到这个问题了,那么不是坏就是蠢。不能考核出候选人的水平。

但是作为一个知识点儿, 还是有一点而意思。 所以顺手就记录下来了。

在 JavaScript 中,严格模式禁用了 with 语句,主要是出于以下三个原因:

  1. 性能问题:使用 with 语句会为 JavaScript 解释器带来优化难题。当使用 with 语句时,解释器在编译阶段无法确定对象属性的作用域,因此无法在编译时进行优化。这意味着在执行时需要做额外的作用域查找,可能会降低代码的执行效率。

  2. 代码可读性和维护性:with 语句可以将一个对象的所有属性和方法直接引入到当前作用域中,这可能会带来潜在的命名冲突。如果一个属性在 with 语句内部和外部作用域都有定义,编写和维护代码的人员可能会对此感到困惑。因此,这种语句的使用可以使代码的可读性和维护性降低。

  3. 编码错误可能性:with 语句改变了正常的作用域链查找规则,这可能会导致意外的变量分配。例如,如果 with 对象不包含某个属性,那么它可能意外地引用或创建一个全局变量,导致难以追踪的错误。

其中前两个原因还是比较好理解的,第三个原因, 「编码错误可能性」就需要好好解释下了:

这里 with 语法, 我就不过多讲解了哈。 如果不知道语法的同学, 我这儿丢一个传送门:developer.mozilla.org/zh-CN/docs/...

下面的例子展示了with语句如何导致潜在的编码错误:

考虑下面的对象和with语句:

javascript 复制代码
var person = {
  name: "Alice",
  age: 25,
};

function updatePerson(person) {
  with (person) {
    name = "Bob"; // 意图是更新person的name属性
    age = 30; // 意图是更新person的age属性
  }
}

updatePerson(person);

console.log(person); // 输出: { name: 'Bob', age: 30 },这里看起来没问题

看起来这段代码没有问题,并且确实更新了person对象;但问题出现在如果with中的属性并不存在于对象中:

javascript 复制代码
var person = {
  name: "Alice",
  age: 25,
};

function createNewPerson() {
  var name = "Charlie";
  var age = 20;

  with (person) {
    name = "David"; // 本意是更新person的name属性
    age = 35; // 本意是更新person的age属性
    // 由于person没有phone属性,所以这将创建一个全局变量phone
    phone = "123-456-7890";
  }

  // 调用者可能预期这里的name和age还是'Charlie'和20 - 因为 with 预期是更改 person 的属性;
  console.log(name, age); // 输出: 'David' 35,而非'Charlie', 20
}

createNewPerson();

console.log(window.phone); // 输出: '123-456-7890'

在这个例子里:

  • nameage都是局部变量,但它们被with(person)覆盖了,因为person对象确实有这样的属性。
  • phone属性不在person对象中,with语句创建了一个全局变量phone

这展示了with语句如何引入两个潜在的陷阱:

  1. 局部变量被意外覆盖: 函数内部的nameage变量被覆盖,因为with语句使得person对象的属性在作用域链中的优先级高于局部变量。

  2. 意外的全局变量: 因为person对象中没有phone属性,所以phone变成了一个全局变量。

这些情况可能会导致难以追踪的错误和未预期的副作用,这正是为何严格模式中不允许使用with语句的原因之一。在严格模式中,代码会因试图使用with而抛出语法错误,上述的误导性行为就不会发生。

相关推荐
布列瑟农的星空9 小时前
Playwright使用体验
前端·单元测试
卤代烃9 小时前
🦾 可为与不可为:CDP 视角下的 Browser 控制边界
前端·人工智能·浏览器
_XU10 小时前
AI工具如何重塑我的开发日常
前端·人工智能·深度学习
C_心欲无痕10 小时前
vue3 - defineExpose暴露给父组件属性和方法
前端·javascript·vue.js·vue3
鹿人戛10 小时前
HarmonyOS应用开发:相机预览花屏问题解决案例
android·前端·harmonyos
萌萌哒草头将军10 小时前
绿联云 NAS 安装 AudioDock 详细教程
前端·docker·容器
贺今宵11 小时前
安装better-sqlite3报错electron-vite
javascript·sql·sqlite·sqlite3
GIS之路11 小时前
GIS 数据转换:使用 GDAL 将 GeoJSON 转换为 Shp 数据
前端
2501_9444460011 小时前
Flutter&OpenHarmony文件夹管理功能实现
android·javascript·flutter
朴shu12 小时前
Luckysheet 远程搜索下拉 控件开发 : 揭秘二开全流程
前端