使人心痛的血淋淋教训,再犯这些错误我不是人。浏览器
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);
输出结果: this
缘由: 一、console.log()函数会在setTimeout函数以前执行,而且b在输出以前未被定义因此最早输出undefined; 二、以后,会执行fn函数和fx函数,而fn函数内存在console.log函数,那么它将会先输出d的值4; 三、而后,在fx函数内也存在console.log函数,一样会先输出c的值3; 四、再来比较setTimeout函数时延长短,依次输出1,5,2。
3)spa
for (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 0); console.log(i); } //0 1 2 3 3 3 用到了闭包
4)code
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)blog
var a = "Hello"; function test(){ var a; alert(a); a = "World"; alert(a); } test();//undefined world
2)队列
var a = "Hello"; function test(){ alert(a); a = "World"; alert(a); } test();//Hello World
3)ip
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、一、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的值为全局变量的值
**总结:(每一个例子慢慢看,就全懂了)
一、js有两级做用域,全局和局部,局部也叫函数做用域
二、全局做用域的变量局部可使用,局部做用域的变量只能在函数体内使用
三、var和function声明的变量都声明提早,赋值留在原地
四、若是局部和全局变量重名,优先使用局部变量
五、第3条和第4条,解释了全局和局部都有相同变量名的时候,而在函数体内打印的变量是undefined**
通常状况下,是能够省略var的,但有两点值得注意: 一、var a=1 与 a=1 ,这两条语句通常状况下做用是同样的。可是前者不能用delete删除。不过,绝大多数状况下,这种差别是能够忽略的。 二、在函数内部,若是没有用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();//1
4)
函数声明变量提高 foo(); function foo(){ console.log("aaa"); } //输出aaa 缘由:函数声明提高 (函数声明提高直接把整个函数提到执行环境的最顶端) 它至关于 function foo(){ console.log("aaa"); } foo();
5)
foo(); var foo = function(){ console.log("aaa"); } 它至关于: var foo; foo(); //foo is not a function foo = 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); foo=10; console.log(foo); console.log(foo);
函数提高在变量提高上面,第一个console.log(foo);为何会输出函数题呢,缘由在于 var foo; 并未有赋值只是声明,所以他会调用上面的值.
全局环境中,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; // true
1)
对象中的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指向o
3).
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.
构造函数中this function 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); //李钢铁