this关键字只与函数的执行环境有关,而与声明环境没有关系。也就是这个this到底代表的是什么对象要等到函数运行时才知道,this关键字虽然会根据环境变化,但是它始终代表的是调用当前函数的那个对象。这就引出了JS中函数调用的问题。在JS中调用函数的模式可以分为4种: 方法调用模式、函数调用模式、构造器调用模式、apply/call/bind调用模式。这些模式在如何初始化关键参数this上存在差异。

(1)方法调用模式:将函数保存为某个对象的方法时,this被绑定在该对象上;

var name="window";//定义全局的变量name
var obj={
       name:"cwj",
       //作为对象属性的函数被称为方法
       sayName:() => {
              console.log(this.name);
              //这个函数是用箭头函数定义的,箭头函数没有this变量,只能往上层作用域链的this来继承,而obj是个对象没有作用域链,那么向上找到全局环境,即window对象
       },
        sayThisName:function(){
              console.log(this.name);
              //这个函数是用函数表达式定义的
       }
};
obj.sayName();//window
obj.sayThisName();//cwj

(2)函数调用模式: 

var name="window";
function sayName(){
            console.log(this.name);
}
sayName();//控制台输出”window”

//因为是在全局作用域下调用的sayName函数,所以this指向window对象

(3)构造器调用模式:在一个函数前面加上new关键字来调用,那么就会创建一个连接到该函数的prototype成员的新对象,同时,this会被绑定到这个新对象上。

function getName(){
         this.name="jjj";
 }
 var person=new getName();
 console.log(person.name);//控制台输出jjj

//把getName函数通过new关键字调用,复制给person对象,this被绑定为赋值的person对象。

(4)apply/call调用模式

apply()和call()是属性的方法,它们的作用是在特定的作用域中调用函数,改变函数的执行环境,实际上等于改变函数体内设置的this对象的值

var name="window";
var obj={
       name:"cwj",
       sayName:function(){
       console.log(this.name);
       }
 };
obj.sayName();//控制台输出cwj

function sayName(){
              console.log(this.name);

}
sayName();//控制台输出window
sayName.apply(obj);//控制台输出cwj

当仅调用sayName函数,this对象指向全局对象window,当调用apply(),并将obj对象作为参数传给apply()时,this对象就开始指向obj对象。

call()和apply()一样。bind()有点不同,bind()是永久性的改变函数的this对象,而apply()和call()方法只是改变一次,apply()和call()语句执行完后,this对象原来指向哪里还是会指向原来的对象。