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

作者备注:
这是我无意中看到一个小伙伴的面试题。 实话实说, 这个问题真的很冷门。 如果有面试官问到这个问题了,那么不是坏就是蠢。不能考核出候选人的水平。
但是作为一个知识点儿, 还是有一点而意思。 所以顺手就记录下来了。

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

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

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

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

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

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

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

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

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中的属性并不存在于对象中:

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

原文链接:https://juejin.cn/post/7356878329003671552 作者:晴小篆

(0)
上一篇 2024年4月14日 上午10:00
下一篇 2024年4月14日 上午10:11

相关推荐

发表回复

登录后才能评论