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而抛出语法错误,上述的误导性行为就不会发生。

相关推荐
10年前端老司机1 小时前
什么!纯前端也能识别图片中的文案、还支持100多个国家的语言
前端·javascript·vue.js
摸鱼仙人~1 小时前
React 性能优化实战指南:从理论到实践的完整攻略
前端·react.js·性能优化
程序员阿超的博客2 小时前
React动态渲染:如何用map循环渲染一个列表(List)
前端·react.js·前端框架
magic 2452 小时前
模拟 AJAX 提交 form 表单及请求头设置详解
前端·javascript·ajax
小小小小宇7 小时前
前端 Service Worker
前端
只喜欢赚钱的棉花没有糖7 小时前
http的缓存问题
前端·javascript·http
小小小小宇7 小时前
请求竞态问题统一封装
前端
loriloy7 小时前
前端资源帖
前端
源码超级联盟7 小时前
display的block和inline-block有什么区别
前端
GISer_Jing8 小时前
前端构建工具(Webpack\Vite\esbuild\Rspack)拆包能力深度解析
前端·webpack·node.js