JS编程建议——12:避免使用with

建议12:避免使用with
with语句的语法如下:

  1. with ( Expression )
  2. Statement
    with会把由Expression计算出来的对象添加到当前执行上下文的作用域链的前面,然后使用这个扩大的作用域链来执行语句Statement,最后恢复作用域链。不管其中的语句是否正常退出,作用域链都会被恢复。

由于with会把额外的对象添加到作用域链的前面,因此使用with可能会影响性能,并造成难以发现的错误。由于额外的对象在作用域链的前面,当执行到with语句,需要对标识符求值时,会先沿着该对象的prototype链查找。如果找不到,才会依次查找作用域链中原来的对象。因此,如果在with语句中频繁引用不在额外对象的 prototype 链中的变量,查找的速度会比不使用with 慢,例如:

  1. function A() {
  2. this.a = "A";
  3. }
  4. function B() {
  5. this.b = "B";
  6. }
  7. B.prototype = new A();
  8. function C() {
  9. this.c = "C";
  10. }
  11. C.prototype = new B();
  12. (function() {
  13. var myVar = "Hello World";
  14. alert(typeof a); // "undefined"
  15. var a = 1;
  16. var obj = new C();
  17. with(obj) {
  18. alert(typeof a); //"string"
  19. alert(myVar); //查找速度比较慢
  20. }
  21. alert(typeof a); // "number"
  22. })();
    在上面代码中,先通过prototype方式实现了继承。在with语句中,执行alert(typeof a)时需要查找变量a,由于obj在作用域链的前面,而obj中也存在名为a的属性,因此obj中的a被找到。执行alert(myVar)需要查找变量myVal,而obj中不存在名为myVal的属性,会继续查找作用域链中后面的对象,因此使用with比不使用with的速度慢。需要注意的是,最后一条语句alert(typeof a)不在with中,因此查找到的a是之前声明的 number型的变量。

使用with语句可以快捷地访问对象的属性,然而,得到的结果有时可能是不可预料的,所以应该避免使用它。例如:

  1. with (obj) {
  2. a = b;
  3. }
    上面代码与下面的代码完成的是同样的事情。
  4. if (obj.a === undefined) {
  5. a = obj.b === undefined ? b : obj.b;
  6. } else {
  7. objobj.a = obj.b === undefined ? b : obj.b;
  8. }
    因此,前面代码等价以下语句中的任何一条。
  9. a = b;
  10. a = obj.b;
  11. obj.a = b;
  12. objobj.a = obj.b;
    直接阅读代码不可能辨别出会得到这些语句中的哪一条。a和b可能随着程序运行到下一步时发生变化,甚至可能在程序运行过程中就发生变化了。如果不能通过阅读程序来了解它将会做什么,就无法确信它是否会正确地执行我们要求的事情。

with语句在JavaScript语言中存在,本身就严重影响了JavaScript处理器的速度,因为它阻止了变量名的词法作用域绑定。它的本意是好的,但如果没有它,JavaScript语言可能会更好。

时间: 2024-07-30 02:25:51

JS编程建议——12:避免使用with的相关文章

JS编程建议——3:减少全局变量污染

建议3:减少全局变量污染定义全局变量有3种方式:在任何函数外面直接执行var语句. var f = 'value'; 直接添加一个属性到全局对象上.全局对象是所有全局变量的容器.在Web浏览器中,全局对象名为window. window.f = 'value'; 直接使用未经声明的变量,以这种方式定义的全局变量被称为隐式的全局变量. f = 'value'; 为方便初学者在使用前无须声明变量而有意设计了隐式的全局变量,然而不幸的是忘记声明变量成了一个非常普遍的现象.JavaScript的策略是让

JS编程建议——74:使用高阶函数

建议74:使用高阶函数高阶函数作为函数式编程众多风格中的一项显著特征,经常被使用.实际上,高阶函数即对函数的进一步抽象.高阶函数至少满足下列条件之一:接受函数作为输入.输出一个函数. 在函数式语言中,函数不但是一种特殊的对象,还是一种类型,因此函数本身是一个可以传来传去的值.也就是说,某个函数在刚开始执行的时候,总可以送入一个函数的参数.传入的参数本身就是一个函数.当然,这个输入的函数相当于某个函数的另外一个函数.当函数执行完毕之后,又可以返回另外一个新的函数,这个返回函数取决于return f

JS编程建议——8:谨慎使用运算符(1)

建议8:谨慎使用运算符(1)1.用===,而不用==JavaScript有两组相等运算符:===和!==.==和!=.===和!==这一组运算符会按照期望的方式工作.如果两个运算数类型一致且拥有相同的值,那么===返回true,而!==返回false.==和!=只有在两个运算数类型一致时才会做出正确的判断,如果两个运算数是不同的类型,会试图强制转换运算数的类型.转换的规则复杂且难以记忆,具体规则如下: '' == '0' // false 0 == '' // true 0 == '0' //

JS编程建议——21:推荐提高循环性能的策略(1)

建议21:推荐提高循环性能的策略(1)每次运行循环体时都会产生性能开销,增加总的运行时间,即使是循环体中最快的代码,累计迭代上千次,也将带来不小的负担.因此,减少循环的迭代次数可获得显著的性能提升.例如: var iterations = Math.floor(items.length / 8), startAt = items.length % 8, i = 0; do { switch(startAt) { case 0: process(items[i++]); case 7: proce

JS编程建议——29:准确使用循环体(1)

建议29:准确使用循环体(1)1.选择正确的循环体在大多数编程语言中,代码执行时间多数消耗在循环的执行上.在一系列编程模式中,循环是最常用的模式之一,因此也是提高性能必须关注的地方之一.理解JavaScript 中循环对性能的影响至关重要,因为死循环或长时间运行的循环会严重影响用户体验.JavaScript定义了4种类型的循环:第一种循环是标准的for循环,与C语言使用同样的语法: for (var i=0; i < 10; i++){ //循环体 } for循环是最常用的循环结构,它由4部分组

JS编程建议——50:正确检测数组类型

建议50:正确检测数组类型由于数组和对象的数据同源性,导致在JavaScript编程中经常会出现:在必须使用数组时使用了对象,或者在必须使用对象时使用了数组.选用数组或对象的规则很简单:当属性名是小而连续的整数时,应该使用数组,或者当对属性的位置和排列顺序有要求时,应该使用数组.否则,使用对象.JavaScript语言对数组和对象的区别是混乱的.typeof运算符检测数组的类型是"object",这没有什么意义,因此在正确检测数组和对象方面JavaScript没有提供很多的机制.这时可

JS编程建议——59:推荐动态调用函数

建议59:推荐动态调用函数调用函数更便捷的方式是使用Function对象的call和apply方法.apply与call方法在本质上没有太大区别,只不过它们传递给函数的参数方式不同, apply是以数组形式进行参数传递,而call方法可以同时传递多个值.如果某个函数仅能够接收多个参数列表,而现在希望把一个数组的所有元素作为参数进行传递,那么使用apply方法就显得非常便利.function max(){ var m = Number.NEGATIVE_INFINITY; // 声明一个负无穷大的

JS编程建议——58:灵活使用Arguments

建议58:灵活使用ArgumentsJavaScript函数的参数是不固定的,调用函数时传递给它的实参也很随意,为了有效管理参数,JavaScript支持Arguments机制.Arguments是一个伪数组,可以通过数组下标的形式获取该集合中传递给函数的参数值.例如,在下面这个函数中,没有指定形参,但在函数体内通过Arguments对象可以获取传递给该函数的每个实参值.function f(){ for(var i = 0; i < arguments.length; i ++ ){ aler

JS编程建议——65:比较函数的惰性求值与非惰性求值

建议65:比较函数的惰性求值与非惰性求值在JavaScript中,使用函数式风格编程时,应该对于表达式有着深刻的理解,并能够主动使用表达式的连续运算来组织代码.1)在运算元中,除了JavaScript默认的数据类型外,函数也作为一个重要的运算元参与运算.2)在运算符中,除了JavaScript的大量预定义运算符外,函数还作为一个重要的运算符进行计算和组织代码.函数作为运算符参与运算,具有非惰性求值特性.非惰性求值行为自然会对整个程序产生一定的负面影响.先看下面这个示例:var a = 2;fun