令人心痛的血淋淋教训,再犯这些错误我不是人。setTimeout与console.log()执行顺序setTimeout延时为0时, setTimeout(function(){ console.log(2); },0); console.log(1); //输出顺序:1,2 setTimeout(function(){ console.log(4); },0); setTimeout(function(){ console.log(5); },0); console.log(1); console.log(2); console.log(3); //输出顺序:1,2,3,4,5原因:(记住喽,记不住打死你!!!):页面中所有由setTimeout定义的操作,都将放在同一个队列中依次执行。而这个队列的执行时间需要等到函数调用栈执行完毕后才会执行,也就是等待所有的可执行代码执行完毕,才会轮到setTimeout执行其内部操作,并且按照其时延时间长短顺序执行代码!再来个高深的:瞅着setTimeout(function(){ console.log(“a:"+a); },0); var a = 1; console.log(“b:"+b); var b = 2; var c = 3; var d = 4; var e = 5; function fx(c){ console.log(“c:"+c); } function fn(e,d){ console.log(“d:"+d); setTimeout(function(){ console.log(“e:"+e); },10); } setTimeout(function(){ console.log(“b2:"+b); },20); fn(e,d); fx(c); 输出结果: 原因:1、console.log()函数会在setTimeout函数之前执行,并且b在输出之前未被定义所以最先输出undefined;2、之后,会执行fn函数和fx函数,而fn函数内存在console.log函数,那么它将会先输出d的值4;3、然后,在fx函数内也存在console.log函数,同样会先输出c的值3;4、再来比较setTimeout函数时延长短,依次输出1,5,2。3)for (var i = 0; i < 3; i++) {setTimeout(function() { console.log(i);}, 0);console.log(i);}//0 1 2 3 3 3用到了闭包4)for (var i = 0; i < 3; i++) {}console.log(i); //3,也就说i可以在for循环体外访问到。所以是没有块级作用域。 5)var i = 0;setTimeout(function() { console.log(i);}, 0);console.log(i);i++;setTimeout(function() { console.log(i);}, 0);console.log(i);i++;setTimeout(function() { console.log(i);}, 0);console.log(i);i++; 等价于:var i = 0;console.log(i);i++;console.log(i);i++;console.log(i);i++;setTimeout(function() { console.log(i);}, 0);setTimeout(function() { console.log(i);}, 0);setTimeout(function() { console.log(i);}, 0); //弹出 0 1 2 3 3 3全局变量和局部变量的区别1) var a = “Hello”; function test(){ var a; alert(a); a = “World”; alert(a); } test();//undefined world2) var a = “Hello”; function test(){ alert(a); a = “World”; alert(a); } test();//Hello World 3) var a =1; function test(){ alert(a); var a = 2; alert(a); } test(); alert(a); //undefined 2 1 Javascript的变量的scope是根据方法块来划分的(也就是说以function的一对大括号{ }来划分)。是function块,而for、while、if块并不是作用域的划分标准,可以看看以下几个例子: function test2(){       alert (“before for scope:"+i);     // i未赋值(并不是未声明!使用未声明的变量或函数全抛出致命错误而中断脚本执行)       // 此时i的值是underfined       for(var i=0;i<3;i++){           alert(“in for scope:"+i);  // i的值是 0、1、2, 当i为3时跳出循环       }      alert(“after for scope:"+i);  // i的值是3,注意,此时已经在for scope以外,但i的值仍然保留为3             while(true){           var j = 1;           break;       }       alert(j);     // j的值是1,注意,此时已经在while scope以外,但j的值仍然保留为1         if(true){           var k = 2;       }       alert(k);  //k的值是1,注意,此时已经在if scope以外,但k的值仍然保留为1   }   test2();   //若在此时(function scope之外)再输出只存在于test2 这个function scope里的 i、j、k变量会发生神马效果呢?   alert(i); //error! 没错,是error,原因是变量i未声明(并不是未赋值,区分test2函数的第一行输出),导致脚本错误,程序到此结束!   alert(“这行打印还会输出吗?"+i); //未执行   alert(j); //未执行   alert(k); //未执行 Javascript在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),从而确定实变量的作用域。怎么理解呢?看下面一个例子: var a =1;      function test(){           alert(a); //a为undefined! 这个a并不是全局变量,这是因为在function scope里已经声明了(函数体倒数第4行)一个重名的局部变量,                        //所以全局变量a被覆盖了,这说明了Javascript在执行前会对整个脚本文件的定义部分做完整分析,所以在函数test()执行前,                        //函数体中的变量a就被指向内部的局部变量.而不是指向外部的全局变量. 但这时a只有声明,还没赋值,所以输出undefined。           a=4;                  alert(a);  //a为4,没悬念了吧? 这里的a还是局部变量哦!           var a;     //局部变量a在这行声明           alert(a);  //a还是为4,这是因为之前已把4赋给a了       }       test();       alert(a); //a为1,这里并不在function scope内,a的值为全局变量的值  当全局变量跟局部变量重名时,局部变量的scope会覆盖掉全局变量的scope,当离开局部变量的scope后,又重回到全局变量的scope,而当全局变量遇上局部变量时,怎样使用全局变量呢?用window.globalVariableName。 var a =1;       function test(){              alert(window.a);  //a为1,这里的a是全局变量哦!           var a=2;     //局部变量a在这行定义           alert(a);  //a为2,这里的a是局部变量哦!       }       test();       alert(a); //a为1,这里并不在function scope内,a的值为全局变量的值总结:(每个例子慢慢看,就全懂了)1、js有两级作用域,全局和局部,局部也叫函数作用域2、全局作用域的变量局部可以使用,局部作用域的变量只能在函数体内使用3、var和function声明的变量都声明提前,赋值留在原地4、如果局部和全局变量重名,优先使用局部变量5、第3条和第4条,解释了全局和局部都有相同变量名的时候,而在函数体内打印的变量是undefinedvar变量提升(这个问题我一直一知半解,现在懂了)一般情况下,是可以省略var的,但有两点值得注意:1、var a=1 与 a=1 ,这两条语句一般情况下作用是一样的。但是前者不能用delete删除。不过,绝大多数情况下,这种差异是可以忽略的。2、在函数内部,如果没有用var 进行申明,则创建的变量是全局变量,而不是局部变量了。所以,建议变量申明加上var关键字。瞅着: 1) var t = 1; function a(){ console.log(t); var t=2; } a();//undefined;输出undefined,原因:function()中相当于var t;console.log(t);t = 2;表示变量t已声明,但还未赋值,输出undefined。2)但是变量提升只对var命令声明的变量有效,如果一个变量不是用var命令声明的,就不会发生变量提升。console.log(aa);aa =1;以上代码将会报错:ReferenceError: aa is not defined。3)var t = 1; function a(){ console.log(t); t=2; } a();//14)函数声明变量提升foo();function foo(){ console.log(“aaa”);}//输出aaa原因:函数声明提升 (函数声明提升直接把整个函数提到执行环境的最顶端)它相当于function foo(){ console.log(“aaa”);}foo(); 5)foo();var foo = function(){ console.log(“aaa”);} 它相当于:var foo;console.log(foo); //undefinedfoo(); //foo is not a functionfoo = function(){ console.log(“aaa”); } 上面代码输出undefined 是因为变量提升后并没有赋值因此输出undefined输出foo is not a function 原因是:js解析遇到 foo()时会默认当做函数来解析6)最厉害的一个console.log(foo);var foo=10;console.log(foo);function foo(){ console.log(10);}console.log(foo);他相当于:function foo(){ console.log(10);}var foo;console.log(foo);console.log(foo);console.log(foo);函数提升在变量提升上面,第一个console.log(foo);为什么会输出函数题呢,原因在于 var foo; 并未有赋值只是声明,因此他会调用上面的值.this指向 全局环境中,this指向window console.log(this.document === document); // true // 在浏览器中,全局对象为 window 对象: console.log(this === window); // true this.a = 37; console.log(window.a); // 37函数调用 非严格模式下,this 默认指向全局对象window function f1(){ return this f1() === window; // true 而严格模式下, this为undefined function f2(){ “use strict”; // 这里是严格模式 return this; } f2() === undefined; // true1) 对象中的this var o = { user:“李钢铁”, fn:function(){ console.log(this.user); //李钢铁 } } o.fn();这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。2).var o = {user:“李钢铁”,fn:function(){ console.log(this.user); //李钢铁}}window.o.fn();this指向o3).var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); //12 } }}o.b.fn();总结:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。 4). var o = {a:10,b:{ // a:12, fn:function(){ console.log(this.a); //undefined } }}o.b.fn();this指向b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。5).特殊情况var o = {a:10,b:{ a:12, fn:function(){ console.log(this.a); //undefined console.log(this); //window }}}var j = o.b.fn;j();这里this指向的是window,,this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window。4.构造函数中thisfunction Fn(){this.user = “李钢铁”; }var a = new Fn();console.log(a.user); //李钢铁指向实例化对象a当this遇到return时,如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。function fn() { this.user = ‘李钢铁’; return undefined;}var a = new fn; console.log(a); //fn {user: “李钢铁”} function fn() { this.user = ‘李钢铁’; return 1;}var a = new fn; console.log(a.user); //李钢铁特殊情况:虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。function fn() { this.user = ‘李钢铁’; return null;}var a = new fn; console.log(a.user); //李钢铁