let 块语句和等价的 with 语句有啥区别?

Posted

技术标签:

【中文标题】let 块语句和等价的 with 语句有啥区别?【英文标题】:What is the difference between a let block statement and an equivalent with statement?let 块语句和等价的 with 语句有什么区别? 【发布时间】:2011-09-23 00:02:28 【问题描述】:

已过时

let 语句的块版本在最终确定之前已从 ES6 中删除,并且已从支持它的浏览器中删除。这个问题现在只具有历史意义。

使用 ECMAScript 6 let block statement 和使用带有等效对象字面量的 with 语句之间有什么区别吗?

使用let 语句

var x = 10;
let (x = x * 10,
     y = x + 5) 
    console.log("x is " + x + ", y is " + y);

使用with 语句

var x = 10;
with (x: x * 10,
       y: x + 5) 
    console.log("x is " + x + ", y is " + y);
    // writes "x is 100, y is 15"

【问题讨论】:

这个问题是为了娱乐,还是您正在认真考虑使用with 进行范围界定? 如果答案最终是“没有区别”,那么我会考虑,但我主要是好奇,因为我预计会有区别,但找不到。 【参考方案1】:

您可以同时使用withlet 语句来实现相同的目标,但我在这里看到了两个显着差异。最后,let 语句是with 语句的新版本,去掉了后者的缺点。

性能:在with 语句的情况下,您将额外的javascript 对象添加到作用域链中。这不是一个小成本,您必须记住对象可能有一个很长的原型链,因此要查找变量,JavaScript 引擎首先必须搜索对象及其所有原型。另一方面,对于let 语句,引擎最多只需要搜索一个附加对象。 let 语句确实可以在没有任何开销的情况下实现,因为在 let 语句中声明的所有变量在编译时都是已知的,并且 JavaScript 引擎可以轻松优化代码,例如通过基本上将您的示例视为:

var x = 10;
var let1x = x * 10;
var let1y = x + 5;

    console.log("x is " + let1x + ", y is " + let1y);

代码可读性:正如上面已经提到的,let 语句总是使所有声明在编译时可见,这可以防止这样的代码:

with (foo)

    console.log("x is " + x + ", y is " + y);

如果你看上面的代码,x 是什么,y 是什么?它们是对象foo 的函数变量或属性吗?如果不知道foo 是什么,你就无法说出它——而且对于同一函数的不同调用,它可能会有所不同。这是 with 声明已被弃用的主要原因。虽然您可以按照您在问题中所做的方式使用它(这很好),但它也允许非常有问题和不可读的代码结构。 let 声明没有 - 灵活性较低有时是一个优势。

【讨论】:

【参考方案2】:

我能想到的最好的办法是with 也会泄漏Object 原型的任何属性:

with (x: 10) 
    hasOwnProperty = 3;
    console.log(hasOwnProperty);  // 3

console.log(hasOwnProperty);  // [native code]; this is window.hasOwnProperty

在实践中不太可能成为问题,但仍然是一个潜在的问题。

我还怀疑with 比词法稍慢,因为它添加了另一个必须搜索的命名空间。

老实说,我只是避免这两种结构; with 风格的隐式属性访问不适合我,如果我真的需要像这样的紧凑范围,那么带有 let 表达式的裸块比 let 块读起来更尴尬。

【讨论】:

请注意,ECMAScript 5 允许我们创建一个没有原型的对象 Object.create(null),因此实际上使用它似乎没有副作用。但是,ES5 的严格模式禁用了with,所以这只能在 ES5 的默认模式下实现,在 ES6 中是不可能的。 请参阅Was there a way to create an object without a prototype prior to ES5? 了解 ES3 的可能(尽管非常不切实际)替代方案。【参考方案3】:

以下是每个语句的不同范围规则。

与:

with 语句使对命名引用的访问效率低下,因为这种访问的范围直到运行时才能计算出来

让:

使用 let 定义的变量的范围是 let 块本身,以及包含在其中的任何内部块,除非这些块以相同的名称定义变量。

let 语句是非标准的,而with 语句在严格模式下不可用。

参考文献

ECMA-327:ECMAScript 3rd Edition Compact Profile (pdf) Resurrecting the with Statement ECMAScript Harmony: Object Extension Literal let: block scoping ECMAScript-6 Draft

【讨论】:

以上是关于let 块语句和等价的 with 语句有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

[ES6] let和var区别

var,let,const的区别和用法

sql语句中join、left join 、right join有啥区别?

python with语句有啥用

python以啥划分语块?

在 if 语句块中使用 let 定义尚未定义的变量的替代方法是啥?