函数内部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指向,但是会拷贝从而改变指向;