setTimeout与console.log()执行顺序,局部变量和全局变量,var变量提高,this指向, 看不懂你来打我

使人心痛的血淋淋教训,再犯这些错误我不是人。浏览器

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);

输出结果:
clipboard.pngthis

缘由:
一、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的,但有两点值得注意:
一、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);

clipboard.png

函数提高在变量提高上面,第一个console.log(foo);为何会输出函数题呢,缘由在于 var foo; 并未有赋值只是声明,所以他会调用上面的值.

this指向

  1. 全局环境中,this指向window
       console.log(this.document === document); // true
       
       // 在浏览器中,全局对象为 window 对象:
       console.log(this === window); // true
       
       this.a = 37;
       console.log(window.a); // 37
  2. 函数调用
    非严格模式下,this 默认指向全局对象window

    function f1(){
         return this
       f1() === window; // true
    
       而严格模式下, this为undefined
       function f2(){
         "use strict"; // 这里是严格模式
         return this;
       }    
       f2() === undefined; // true
  3. 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); //李钢铁
相关文章
相关标签/搜索