今天的主题是写JS function bind函数
那么为什么要讲bind呢,因为其重要性是非常之大的,非常之实用的。
bind方法主要是在回调函数this上下文发生改变的时候使用,意思是将函数绑定到当前作用域对象上。
new init();
function init(){
$.ajax({
url:"data.json",
success: function(data){ //注意success是一个回调函数,关于回调函数我在之前博客里讲过,
//回调函数的时候,上下文会发生改变.
console.log(this); //这个this对象既不是init对象也不是window对象,而是一个jquery封装的一个对象。
this.createUI(data);//调用createUI时,会报错undefined is not a function ,没有createUI这个方法。
}
});
this.createUI = function(data){
console.log(data);
alert(data);
}
}
解决办法1
用self变量来保存上下文作用域,在回调函数(点击查看)那一节里我讲过:
new init();
function init(){
var self = this;//保存作用域
$.ajax({
url:"data.json",
success: function(data){
self .createUI(data);
}
});
this.createUI = function(data){
console.log(data); //成功执行,输出了返回值。
}
}
问题虽然解决了,可是每次都用var self= this;来操作,感觉不是很好看呀,这个解决办法并不完美耶。
那么好,我们再来用我们的function bind来尝试下吧,
2原生bind解决办法
关于原生的Function.prototype.bind基本支持浏览器IE8+ 和Chrome, Firefox, Opera,safari。
new init();
function init(){
$.ajax({
url:"data.json",
success: function(data){
console.log(this); //output > init object .
this.createUI(data);
}.bind(this) //将匿名function bind到this(init)对象上。
});
this.createUI = function(data){
console.log(data); //我很幸福激动的告诉你,成功执行,输出了返回值。
}
}
可是这个bind方法并不兼容所有的浏览器呀,这确实是个头疼的事情。
这么方便简洁的功能,有那么些变态浏览器,就是不给力。
那么为了解决这个不给力的问题,我们也有招去兼容所有浏览器。
3兼容所有浏览器的bind拓展解决办法:
首先讲解几个知识点:
1,关于function中的arguments对象,它是一个长得像数组的东西(它也可以遍历),但是arguments不是数组,无法对数组使用标准的数组方法。在这个bind方法里它的值包括function.bind(this)中的this(init)对象等。
2,既然不是一个数组,那么我们要把他转化成一个真正的数组,转化方法:Array.prototype.slice.call(arguments);
以下开始我们的code:
Function.prototype.bind = function() {var __method = this;//this是一个function,就是ajax里的success:function()
var args = Array.prototype.slice.call(arguments); //转化成数组。
var object=args.shift(); //删除第一个值,返回被删除值(this(init)对象)。原数组的值发生改变。
return function() {
return __method.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
}
//解析这个return步骤的意思:
// object是bind(this,2,3)方法里的参数
// Array.prototype.slice.call(arguments)的值是success里的回调参数。
// __method.apply()第一个参数就是我们的this对象,第二个参数就是bind(this,2,3)和success;function(4,5)
//的参数合并的一个数组[2,3,4,5],
//apply会把这个数组给拆分成2,3,4,5
};
使用方法:将这个拓展的bind方法代码复制到页面引入的所有js的最前面,重新定义覆盖了原生的bind,这样任何地方都能共享这个方法。一般我们都放在commn.js里面
举例:
bind不带参数
new init();
function init(){
$.ajax({
url:"data.json",
success: function(data){ //data是ajax的返回值
this.createUI(data);
}.bind(this)
});
this.createUI = function(data){
alert(data); //output 返回值
}
}
bind带参数: new init();
function init(){
$.ajax({
url:"data.json",
success: function(d1,d2,data){//data是ajax的返回值
alert(d1+d2);
this.createUI(data);
}.bind(this,"2","3") //这2和3将会传给d1,d2
});
this.createUI = function(data){
alert(data); //output 返回值
}
}
一个应用场景:
new test();
function test(){
this.clickHandler = function(index,id){
alert(index+id);//输出完全正确
}
var elements = $(".div");
for(var i=0; i<elements.length; i++){
var id = elements[i].id;
elements[i].onclick = this.clickHandler.bind(this,i,id); //这个也能用立即执行函数( 点击查看)来解决
}
}
写到这里基本结束了,看其原理也就是充分利用了javascript的apply方法。关于这个用法我都写有文章,请各位阅读。