天天看点

JS函数中的this指向问题

今天我要说的是JS中的this指向,首先我们应该知道在js中函数的几种调用方式:

  1. 普通函数调用
  2. 作为方法来调用
  3. 作为构造函数来调用
  4. 使用apply/call方法来调用
  5. Function.prototype.bind方法
  6. es6箭头函数

不管是通过哪种方式函数调用,我们都应该明确一点谁调用这个函数或方法,this关键字就指向谁。

1.普通函数调用

function person(){
    this.name="lx";
    console.log(this);//window
    console.log(this.name);//lx
}
person();
console.log(window.name);//lx
           

在这段代码中person函数作为普通函数调用,实际上person是作为全局对象window的一个方法来进行调用的,即window.person(),所以这个地方是window对象调用了person方法,那么person函数当中的this即指window,同时window还拥有了另外一个属性name,值为lx,我在最后也输出了window.name即lx。

2.作为方法来调用

var name="lx";
var person={
    name:"jay",
    showName1:function(){
        console.log(this.name);
    }
}
person.showName1();//jay
var showName2=person.showName1;
showName2();//lx
第一个是的person对象调用showName1方法,所以this指向person对象,所以输出jay,第二个将person.showName1方法赋值给showName2变量,此时showName2变量相当于window对象的一个属性,相当于window.showName2,所以this指向的是window,输出lx
           
var personA={
    name:"lx",
       showName:function(){
           console.log(this.name);//jay
       }
}
var personB={
    name:"jay",
    sayName:personA.showName
}    
personB.sayName();
           

这里的showName方法肃然是在personA这个对象中定义,但是调用的时候却是在personB这个对象中调用,因此this对象指向的是personB

3.作为构造函数调用

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

new操作符

function person11(name){
    var o={};
    o.__proto__=Person.prototype;  //原型继承
    Person.call(o,name);
    return o;
}
var personB=person11("lx");
console.log(personB.name);  // 输出  lx
           

上面这段代码模拟了new操作符(实例化对象)的内部过程

4.call/apply方法的调用

在JS里,函数也是对象,因此函数也有方法,从Function.prototype上继承到Function.prototype.call/Function.prototype.apply方法。

call/apply方法最大的作用就是能改变this关键字的指向。

var name="jay";
var Person={
    name:"lx",
    showName:function(){
        console.log(this.name);
    }
}
    Person.showName.call(Person); //输出lx
    Person.showName.call();//输出 jay
           

虽然showName方法定义在Person对象里面,但是使用call方法后,将showName方法里面的this指向了window,因此最后会输出jay,这里call方法里面的参数为空,默认指向window。

5. Function.prototype.bind方法

var name="jay";
function Person(name){
    this.name=name;
    this.sayName=function(){
        setTimeout(function(){
            console.log("my name is "+this.name);
        },)
    }
}
var person=new Person("lx");
person.sayName(); //输出my name is jay
//这里的setTimeout()定时函数,相当于window.setTimeout(),由window这个全局对象对调用,因此this的指向为window, 则this.name则为jay
           

难么该怎么输出my name is lx?

var name="jay";
function Person(name){
    this.name=name;
    this.sayName=function(){
        setTimeout(function(){
            console.log("my name is "+this.name);
        }.bind(this),)//这个地方使用的bind()方法,绑定setTimeout里面的匿名函数的this一直指向Person对象
    }
}
var person=new Person("lx");
person.sayName(); //输出my name is lx
           

这里setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函数使用bind(this)方法后创建了新的函数,这个新的函数不管在什么地方执行,this都指向的Person,而非window,因此最后的输出为my name is lx而不是my name is jay。

这里的第六种方法是 es6箭头函数,es6的内容看的稍微有点少,理解的不是很全面,所以我就不再做详细的书写了,感兴趣的大牛可以度娘了解一下。

继续阅读