函数内部的this指向以及call(),apply(),bind()的梳理
函数内部this的指向,是调用函数的时候确定的.调用方式的不同决定this指向不同.
| 调用方式 | 普通函数调用 | 构造函数调用 | 对象方法调用 | 事件绑定方法 | 定时器函数 | 立即执行函数 |
| this指向 | window | 实例对象,原型对象方法也指向实例 | 方法所属对象 | 绑定事件对象 | window | window |
call(),bind(),apply()的作用与其分别的写法和作用机制
var person = {
FirstName:'Bill',
LastName:'Gates',
FullName:function(){
return this.FirstName +"" +this.LastName;
}
}
person.fullName();
FullName属性是一个方法.person对象是该方法的拥有者.
FullName属于person对象.
call(方法是预定义的JS方法.它可以用来调用所有者对象作为参数的方法.
通过call(),您能使用属于另一个对象的方法.
举个来自W3的例子:调用上面person的FullName(),并用于person1;
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates",
}
var person2 = {
firstName:"Steve",
lastName: "Jobs",
}
person.fullName.call(person1); // 将返回 "Bill Gates"
或者调用 person 的 fullName 方法,并用于 person2;
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"John",
lastName: "Doe",
}
var person2 = {
firstName:"Steve",
lastName: "Jobs",
}
person.fullName.call(person2); // 将返回 "Steve Jobs"
然后通常在实际运用中,call()方法都会带上参数.
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"LiLei",
lastName: "HanMeimei"
}
person.fullName.call(person1, "ShangHai", "China");//"Lilei HanMeimei,ShangHai,China."//指向对象.call(被指向对象,参数1,参数2)&&this原本对象.call(this接受对象,参数1,参数2);
个人理解是,call()函数,就是用于跨函数调用属性值,无论这个属性是函数是字符串还是其他形式,然后返回结果.
然后是比较相似的apply(),apply()和call()属性差不多,不同之处在于call()分别接受参数,apply()接受以数组形式的参数.
所以更适合接受参数为数组的调用环境,如果内部参数不是数组形式,就会报错.
同样的例子:
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName: "Bill",
lastName: "Gates",
}
person.fullName.apply(person1); // 将返回 "Bill Gates"
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"John",
lastName: "Doe"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);//apply()的调用方法
person.fullName.call(person1, "Oslo", "Norway");//call()的调用方法
在W3中,关于apply()的具体应用有提到Math.max搭配的用法.涉及到利用数学内置对象求最大值.
var arr = [1,66,3,99,4]; var max = Math.max.apply(null,arr);//也可以写成Math.max.apply(Math,arr); console.log(max);//99 //这里的null是不改变this指向 //apply要求非this指向的参数为数组形式,其实并没有直接限制,而是在处理时进行检查.
Math.max能调用apply(),说明其他函数也能调用apply()并对数组进行增删改查升降序处理.
最后一个bind(),MDN的描述中是这样的:
bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。
同时DEMO举出了下面这个案例:
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); // 这个函数事实上是没有获取到的,中间的赋值过程其实并不成立
// expected output: undefined
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());//当绑定上一个函数时,this指向被bind()改变,于是赋值过程就成立了
// expected output: 42
是不是感觉和前面的call()很像,感觉就一样?我们接着往下看MDN的描述.
首先是语法:
function.bind(thisArg[,arg1[,arg2[, ...]]])
thisArg是调用bind绑定的函数,this参数传递给目标函数的值.如果简单理解,就是输出方对象想绑定的输入方函数对象.
arg1和arg2是目标函数(输入方)被调用时,预先添加到绑定函数的参数.
返回值返回一个原函数的拷贝,也就是说返回的是原函数改变this之后产生的新函数.指向并拥有指定的this值和初始参数.
举个简单例子:
var o = {
name:'andy'
};
function fn(a,b){
console.log(this);
console.log(a+b);
};
var f = fn.bind(o,1,2);
f();//{name:'andy'},3;
但上面都是基本的应用,实际中的常用环境更复杂一些.以常用的短信验证码发送按钮举例:
var btn = document.querySelector('button');
btn.onclick = function(){
this.disabled = true;//这个this指向的是btn这个按钮
var that = this;
setTimeout(function(){
that.disabled = false;//定时器函数里面的this指向的是window对象,所以用that
},3000)
}
如果用bind,就可以用this接着这样用:
var btn = document.querySelector('button');
btn.onclick = function(){
this.disabled = true;//这个this指向的是btn这个按钮
setTimeout(function(){
this.disabled = false;
}.bind(this),3000);//此时this指向btn
}
多按钮的写法:
var btns = document.querySelectorAll('button');
for(var i=0;i<btns.length;i++){
btns[i].onclick = fuction(){
this.disabled = true;
setTimeout(function(){
this.disabled = false;
}.bind(this),60000);
}
}
总结一下.
call(),apply(),bind().相同点都是能改变函数内部的this指向.
区别点:
1.call和apply会调用函数,并且改变函数内部this指向;
2.call与apply传递的参数不一样,call传递参数aru1,aru2,apply必须以数组形式接受参数;
3.bind不会调用函数内部的this指向,但是会拷贝从而改变指向;
浙公网安备 33010602011771号