首先 ,理清一下js中的this,js中的this对象指向调用当前方法的对象,这个指向是在执行的时候才确定下来的,跟函数在何时何处声明是无关的。
但是,在实际使用过程中,我们经常会遇到要改变当前this指向的需求,一下的对绑定this方法的归纳
1、call和apply
这里把call和apply放在一起讲,是因为这两个方法及其相似,其作用都是直接调用一个函数,并使其具有一个指定的this,区别在于,就是call()
方法接受的是若干个参数的列表,而apply()
方法接受的是一个包含多个参数的数组。具体使用方法如下
function Product(name, price) {
this.name = name;
this.price = price;
}
function ProductExtra(from,to){
this.from=from;
this.to=to;
}
function Food(name, price,extra) {
Product.call(this, name, price);
ProductExtra.apply(this,extra);
this.category = 'food';
}
console.log(new Food('烤鸭', 5,['北京','广东']).name);//输出: "烤鸭"
console.log(new Food('烤鸭', 5,['北京','广东']).from);//输出: "北京"
通过对比我们可以看出,call函数第一个参数为要绑定的this,之后可以跟上无数个参数,这些参数会依次作为执行函数的参数传入,而apply则传入一个数组,这个数组中的内容则会按顺序作为执行函数的参数传入。
2、bind
bind函数时es5定义的一个函数,定义如下:func.bind(thisArg, arg1, arg2, ...),它与call和apply不同的是,bind不会直接执行要执行的函数,而是返回一个新的函数,我们称之为a,当执行a被调用执行时,arg1, arg2, ...这些参数,将置于实参之前传递给a,示例代码如下
function product(name, price) {
console.log(name);
console.log(price);
console.log(this.from);
console.log(this.to);
}
function test(price){
var extra={from:'北京',to:'广东'};
var productWithExtra =product.bind(extra,'烤鸭');
productWithExtra(price);
}
test(50);//输出:"烤鸭",50,"北京","广东"
有一点必须注意的是,对任何函数进行bind绑定之后返回的函数,如果再次进行bind绑定是不会有效果的,bind函数绑定后返回的函数,再次进行绑定依旧会指向第一次绑定的对象,具体原因可以了解bind函数的实现原理
3箭头函数
箭头函数是es6定义的一个写法,写法类似于()=>{console.log(test);}可以看做是匿名函数的另外一种写法,这里不对箭头函数的特性做详细的解读,仅对其绑定this方面做部分解析,箭头函数中的this跟正常的this不太一样,正常函数的this是在执行时确定下来的,指向调用当前方法的对象,而箭头函数则不同,箭头函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象,也就是所谓的词法作用域,在定义的时候就确定下来了,例如
var obj1 = {
birth: 1990,
getBirth: function () {
var b = this.birth; // 1990
var fn = function () {
return this.birth; // this指向window或undefined,this.birth的值不确定
};
return fn();
}
};
var obj2 = {
birth: 1990,
getBirth: function () {
var b = this.birth; // 1990
var fn = () => this.birth; // this指向obj对象,this.birth=1990
return fn();
}
};
console.log(obj1.getBirth())//无法获得预期效果
console.log(obj2.getBirth())//输出1990
正因为箭头函数的这个特性,我们可以利用它来改变当前函数的this指向
4双冒号::
双冒号属于es尚未通过的一个提案,但目前babel已经支持,可以把它理解为一个语法糖,可以用它来代替bind,具体使用方法如下
obj::func;
// 等同于
func.bind(obj);
obj::obj.func;
// 等同于
::obj.func;
使用方法其实很简单,双冒号后面是要执行的函数,双冒号前面是要绑定的对象,如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面,它跟bind一样,执行之后返回一个新的函数,而不是立即执行这个函数
参考资料:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply