JavaScript中的this指向问题

注意:函数定义无法确定this指向,函数执行的才可以,因此需要知道函数的调用方式。


1、普通函数调用

        var a='hello world';
        function f1(){
            console.log(this);//window
            console.log(this.a);//hello world
        }
        window.f1(); 
      

  解析:window是js中的全局对象,我们创建的变量实际上是给window添加属性。一般情况下,普通函数调用前边的window省略不写。这里window调用了f1函数,所以this指向了window,a是全局变量,相当于window的属性,因此当普通函数被调用,this指向window的时候,是可以访问到a这个变量的。当然了,下边的写法是一样的意思。

       function f1(){
            this.a='hello world';
            console.log(this);//window
            console.log(this.a);//hello world
        }
        window.f1();    

2、作为方法来调用

    var name='张三';
    var person={
    name:'李四',
    f1:function(){
    console.log(this);
    console.log(this.name);
    }
    };
    person.f1();//this指向person,name是李四
    var f2=person.say;
    f2();//this指向window,name是张三

  解析:这里将person.f1方法赋给f2变量,此时f2变量相当于window对象的一个属性,因此f2执行的时候相当于window.f2(),即window对象调用f2这个方法,所以this关键字指向window,再换一种情况进行说明,即使personB中的方法是将personA中的方法进行赋值给了f2,但是在掉用的时候,因为是person进行了调用,所有this依然指向的是personB

        var personA={
            name:'张三',
            f1:function(){
                console.log(this)
                console.log(this.name);
            }
        };
        var personB={
            name:'李四',
            f2:personA.f1
        };
        personB.f2();//this指向personB,输出名字是李四

3、作为构造函数进行调用

        function  Person(name){
            this.name=name;
        }
        var personA=Person("xl");
        console.log(personA.name); // 输出  undefined
        console.log(window.name);//输出  xl
        //上面代码没有进行new操作,相当于window对象调用Person("xl")方法,那么this指向window对象,并进行赋值操作window.name="xl".

        var personB=new Person("xl");
        console.log(personB.name);// 输出 xl

4、call和apply方法的调用

        var name='HELLO WORLD';
        var animal={
            name:'hello world',
            run:function(){
                console.log(this);
                console.log(this.name);
            }
        };
        animal.run();//this指向animal这个对象,this.name输出hello world
        animal.run.call();//call参数为空的情况下,this改变之后指向window.this.name输出HELLO WORLD


        /*FruitA是一个构造函数,有属性n1和n2以及change方法,change方法可以传递的参数为属性赋值*/
        function FruitA(n1,n2){
            this.n1=n1;
            this.n2=n2;
            this.change=function(x,y){
                this.n1=x;
                this.n2=y;
            }
        }

        /*构造函数实例化对象并传入参数*/
        var fruitA=new FruitA("cheery","banana");

        /*另外一个对象FruitB*/
        var FruitB={
            n1:"apple",
            n2:"orange"
        };

        /*FruitB对象调用FruitA构造函数的方法,将FruitA中change方法中的this指向了FruitB对象,并传入参数,*/
        fruitA.change.call(FruitB,"pear","peach");
        
        console.log(FruitB.n1); //输出 pear
        console.log(FruitB.n2);// 输出 peach

  解析:FruitB调用fruitAchange方法,将fruitA中的this绑定到对象FruitB上。

        var name='张三';
        function Person(name){
            this.name=name;
            this.sayName=function(){
                setTimeout(function(){
                    console.log(this.name)
                },2000)
            };
            this.sayNameBind=function(){
                setTimeout(function(){
                    console.log(this.name)
                }.bind(this),2000)
            }
        }
        var person=new Person('李四');
        person.sayName();//此时输出的是张三,因为setTimeout相当window.setTimeout,是window在调用这个方法,而window.name就是张三
        person.sayNameBind();//此时输出的是李四,因为bind(this)调整了setTimeout中this的指向

  解析这里setTimeout(function(){console.log(this.name)}.bind(this),2000);,匿名函数使用bind(this)方法后创建了新的函数,这个新的函数不管在什么地方执行,this都指向的Person,而非window,因此最后的输出为"李四"而不是"张三",另外几个需要注意的地方setTimeout/setInterval/匿名函数执行的时候,this默认指向window对象,除非手动改变this的指向

5、箭头函数

    function Timer() {
        this.seconds = 0;
        setInterval( () => this.seconds ++, 1000);
    } 
    
    var timer = new Timer();
    
    setTimeout( () => console.log(timer.seconds), 3100);
    
    // 3
   // 在构造函数内部的setInterval()内的回调函数,this始终指向实例化的对象,并获取实例化对象的seconds的属性,每1s这个属性的值都会增加1。否则最后在3s后执行setTimeOut()函数执行后输出的是0

  解析:es6里面this指向固定化,始终指向外部对象,因为箭头函数没有this,因此它自身不能进行new实例化,同时也不能使用call, apply, bind等方法来改变this的指向

 

posted @ 2021-04-07 15:41  sct春天  阅读(129)  评论(0)    收藏  举报