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对象原来指向哪里还是会指向原来的对象。