前言
with 语句 扩展一个语句的作用域链。
JavaScript 查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的 context 或者包含这个变量的函数有关。with
语句将某个对象添加到作用域链的顶部.
如果在 statement 中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出 ReferenceError 异常。
var obj = {
a: 123,
b: 321,
};
// 便捷写法
with (obj) {
var c = c; // ReferenceError
}
利与弊
那位微不足道的利
这里 with 括号中的值就是我们的公共对象,下面就是每个对象中的值
var a = obj.a;
var b = obj.b;
var c = obj.c;
// 便捷写法
with (obj) {
var a = a;
var b = b;
var c = c;
}
var qs1 = location.search.substring(1);
var hostname1 = location.hostname;
var url1 = location.href;
// 上面几行代码都包含了location对象,可使用with语句简写为以下形式
with (location) {
var qs2 = search.substring(1);
var hostname2 = hostname;
var url2 = href;
}
这样无疑会大大提高我们的效率(性能上却是一种丢失)
弊弊弊
-
意外创建全局变量
with (obj) { a = 2; } console.log(obj.a); // 输出 1 console.log(a); // 输出 2
这里的“输出 1”和“输出 2”的结果要看 obj 是否带有 a 这个属性。如果 obj 带有属性 a,那么会预期将 obj 的 a 属性赋予 2 的值,“输出 1”的结果为 2,“输出 2”会报错 a is not defined。如果 obj 不带有属性 a,我们可能会认为产生这样的效果 obj.a = 2,obj 将赋予属性 a 且 a 的值等于 2,但事实上并不会,而是会在全局作用域里创建一个全局变量 a,a 的值等于 2,也就是说,“输出 1”的结果为 undefined,“输出 2”的结果为 2。这种特性会意外地创建全局变量,从而污染全局作用域。
-
语义不明
当存在像以下这样的代码,如果我们不知道 b 里面有什么属性和方法,我们怎么知道 a 是 b 里的 a,还是 function 的入参 a 呢?
function f(a, b) { with (b) { console.log(a); } }
-
性能丢失
with (document.forms[0]) { name.value = "lee king"; address.value = "Peking"; zipcode.value = "10000"; } // 可以看出 with 语句的简洁明了,不过在代码的世界里是很难找到真正的完美。 document.forms[0].name.value = "lee king"; document.forms[0].address.value = "Peking"; document.forms[0].zipcode.value = "10000";
js 的解释器需要检查 with 块中的变量是否属于 with 包含的对象,没有的话作用域要关联到全局,这将使 with 语句执行速度大大下降,并且导致 js 语句很难被优化。所以在以后的高效代码开发中我们应该尽可能的避免使用 with 语句。
最后
with 语句就是一个没卵用的语句,w3school 和 MDN 都明确不推荐使用。在 js 的严格模式下,with 语句甚至是完全禁用的。