this、call和apply
一、this
this的四种绑定方式:隐式绑定、显式绑定、window绑定、new绑定
隐式绑定:使用对象来调用其内部的一个方法,该方法的this是指向对象本身的,this永远指向最后调用它的那个对象。
显式绑定:通过call来设置函数执行上下文的this指向。
window绑定:在ES5严格模式中,JavaScript不会默认this指向window对象,而会正确地把this保持为underfined。
new绑定:用new调用函数时,JavaScript解释器都会在底层创建一个全新地对象并把这个对象当做this
改变this指向:
使用ES6箭头函数
在函数内部使用_this = this
使用apply、call、bind
new一个实例化对象
this的指向
作为对象方法调用
当函数作为对象地方法被调用时,this指向该对象
var obj = {
a: 1,
getA: function(){
alert(this === obj); // true
alert(this.a); // 1
}
}
obj.getA();作为普通函数调用
作为普通函数调用,this指向全局对象
window.name = 'globalName';
var getName = function(){
return this.name;
}
console.log(getName());或者
window.name = 'globalName';
var myObject = {
name: 'seven',
getName: function(){
return this.name;
}
};
var getName = myObject.getName;
console.log(getName());箭头函数注意:
函数体内this就是定义时所的对象,而非调用时的所在对象,和普通函数相反
箭头函数无法用做构造器,即不能使用new调用
不能使用arguments对象,不存在
不可以使用yield命令,即无法用做Generator命令
构造器调用
JavaScript中没有类,但是可以从构造器中创建对象,同时也提供了new运算符,使得构造函数看起来更像一个类。
除了宿主提供的一些内置函数,大部分JavaScript函数都可以当作构造器使用。构造器的外表跟普通函数一摸一样,它们的区别在于被调用的方式。当用new运算符调用函数时,该函数总是返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。
Function.prototype.call
或Function.prototype.apply
调用跟普通函数相比,用
Function.prototype.call
或Function.prototype.apply
可以动态地改变传入函数地this。var obj1 = {
name:'sven',
getName: function(){
return this.name;
}
};
var obj2 = {
name: 'anne'
};
console.log(obj1.getName()); // sven
console.log(obj1.prototype.call(obj2)); // anne
丢失的this
var obj = {
myName: 'sven',
getName: function(){
return this.myName;
}
};
console.log(obj.getName()); // sven
var getName2 = obj.getName;
console.log(getName2()); // underfined当调用obj.getName时,getName方法是作为obj对象地属性被调用时,此时的this指向obj对象,所以
obj.getName()
输出sven。当另外一个变量getName2来引用
obj.getName
,并且调用getName2时,此时时普通函数调用方式,this是指向全局window的,所以程序执行结果是underfined。
二、call 和 apply
bind是创建一个新对象
call和apply是立即执行,bind则是返回了一个绑定的this的新函数,只有调用了这个新函数才真正的调用了目标函数。
bind函数存在多次绑定问题,如果多次绑定this,则以第一次为准
bind函数实际上是显式绑定(call、apply)的一个变种,称为硬绑定,ES5中提供了内置的方法
Function。prototype.bind
call和apply的区别
apply接受两个参数,第一个参数指定了函数体内的this对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数。
call传入的参数量不固定,跟apply不同的是,第一个参数也是代表函数体内的this指向,从第二个参数往后,每个参数被依次传入函数。
当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主对象,在浏览器中则是window。
但如果是在严格模式下,函数体内的this还是为null
call和apply的用途
改变this指向
call和apply最常见的用途是改变函数内部的this指向
在实际开发中,经常会遇到this指向被不经意改变的场景,比如有一个div节点,div节点的onclick事件中的this本来是指向这个div的:嵌套中的this不会从外层函数中继承
document.getElementById('div1').onclick = function(){
alert(this.id); // div1
}假如该事件函数中有一个内部函数func,在事件内部调用func函数时,func函数体内的this就指向window,而不是我们预期的div:
document.getElementById('div1').onclick = function(){
alert(this.id); // div1
var func = function(){
alert(this.id); // underfined
}
}这时候我们用call来修正func函数内的this,使其依然指向div:
document.getElementById('div').onclick = function(){
var func = function(){
alert(this.id);
}
func.call(this);
}Function.prototype.bind
大部分高级浏览器都实现了内置的
Function.prototype.bind
,用来指定函数内部的this指向借用其他对象的方法
我们知道,杜鹃既不会筑巢,也不会孵椆,而是把自己的蛋寄托给云雀等其他鸟类,让它们代为孵化和养育。