JS中call、apply、bind的区别
2017-11-24 13:39
661 查看
为什么需要这些?主要是因为this,来看看this干的好事。
2
3
4
5
6
我们原本以为这里面的this指向的是box,然而却是Window。一般我们这样解决:
2
3
4
5
6
7
将this保存下来。
还有一些情况,有时我们想让伪数组也能够调用数组的一些方法,这时call、apply、bind就派上用场了。
我们先来解决第一个问题修复this指向。
2
3
4
5
6
改成如下:
2
3
4
5
6
很神奇吧,call的作用就是改变this的指向的,第一个传的是一个对象,就是你要借用的那个对象。
fn.call(this);
这里的意思是让this去调用fn这个函数,这里的this是box,这个没有意见吧?如果这个你不清楚,很可能你是javscript的新朋友。box调用fn,这句话非常重要,我们知道this它始终指向一个对象,刚好box就是一个对象。那么fn里面的this就是box。
2
3
4
5
6
这句话在某些情况下是可以简写的,比如:
2
3
4
5
或者这样:
2
3
4
5
又或者这样:
2
3
4
5
6
7
8
call和apply、bind都是用来改变this的指向的,但也有一些小小的差别。下面我们来看看它们的差别在哪:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
前面说过第一个参数传的是一个你要借用的对象,但这么我们不需要,所有就传了一个null,当然你也可以传其他的,反正在这里没有用到,除了第一个参数后面的参数将作为实际参数传入到函数中。
call就是挨个传值,apply传一个数组,bind也是挨个传值,但和call和apply还有一些不同,使用call和apply会直接执行这个函数,而bind并不直接执行,而是将绑定好的this重新返回一个新函数,什么时候调用由你自己决定。
2
3
4
5
6
7
8
这里也就是为什么我要用bind的原因,如果用call的话就会报错了。自己想想这个sayHello在obj都已经执行完了,就根本没有sayHello这个函数了。
这几个方法使用的好的话可以帮你解决不少问题比如:
正常情况下Math.max只能这样用
Math.max(10,6)
但如果你想传一个数组的话你可以用apply
2
又或者你想让伪数组调用数组的方法
2
3
4
5
再者:
2
实际上浏览器内部根本就不在乎你是谁,它只关心你传给我的是不是我能够运行的,如下:
正常情况
2
而这种情况其实做的事情和上面一模一样,看我来拆解。
2
这句话就是说让arr调用字符串的indexOf方法,前面说过了浏览器内部不在乎你是谁,所以谁都可以来调用,但不是100%成功,具体看如下。
这里的arr就是[‘aaabc’],内部很可能拆成了’aaabc’,因此就成了下面的这段代码。
这里得说一下bind在某些浏览器下不兼容。我们来模拟一个玩玩。
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
这个方法和实际上的bind还是差别很大的,如
box.onclick = function(){ function fn(){ alert(this); } fn(); };1
2
3
4
5
6
我们原本以为这里面的this指向的是box,然而却是Window。一般我们这样解决:
box.onclick = function(){ var _this = this; function fn(){ alert(_this); } fn(); };1
2
3
4
5
6
7
将this保存下来。
还有一些情况,有时我们想让伪数组也能够调用数组的一些方法,这时call、apply、bind就派上用场了。
我们先来解决第一个问题修复this指向。
box.onclick = function(){ function fn(){ alert(this); } fn(); };1
2
3
4
5
6
改成如下:
box.onclick = function(){ function fn(){ console.log(this); } fn.call(this); };1
2
3
4
5
6
很神奇吧,call的作用就是改变this的指向的,第一个传的是一个对象,就是你要借用的那个对象。
fn.call(this);
这里的意思是让this去调用fn这个函数,这里的this是box,这个没有意见吧?如果这个你不清楚,很可能你是javscript的新朋友。box调用fn,这句话非常重要,我们知道this它始终指向一个对象,刚好box就是一个对象。那么fn里面的this就是box。
box.onclick = function(){ function fn(){ console.log(this); } fn.call(this); };1
2
3
4
5
6
这句话在某些情况下是可以简写的,比如:
box.onclick = function(){ var fn = function(){ console.log(this); //box }.call(this); };1
2
3
4
5
或者这样:
box.onclick = function(){ (function(){ console.log(this); }.call(this)); //box };1
2
3
4
5
又或者这样:
var objName = {name:'JS2016'}; var obj = { name:'0 _ 0', sayHello:function(){ console.log(this.name); }.bind(objName) }; obj.sayHello();//JS20161
2
3
4
5
6
7
8
call和apply、bind都是用来改变this的指向的,但也有一些小小的差别。下面我们来看看它们的差别在哪:
function fn(a,b,c,d){ console.log(a,b,c,d); } //call fn.call(null,1,2,3); //apply fn.apply(null,[1,2,3]); //bind var f = fn.bind(null,1,2,3); f(4); 结果如下: 1 2 3 undefined 1 2 3 undefined 1 2 3 41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
前面说过第一个参数传的是一个你要借用的对象,但这么我们不需要,所有就传了一个null,当然你也可以传其他的,反正在这里没有用到,除了第一个参数后面的参数将作为实际参数传入到函数中。
call就是挨个传值,apply传一个数组,bind也是挨个传值,但和call和apply还有一些不同,使用call和apply会直接执行这个函数,而bind并不直接执行,而是将绑定好的this重新返回一个新函数,什么时候调用由你自己决定。
var objName = {name:'JS2016'}; var obj = { name:'0 _ 0', sayHello:function(){ console.log(this.name); }.bind(objName) }; obj.sayHello();//JS20161
2
3
4
5
6
7
8
这里也就是为什么我要用bind的原因,如果用call的话就会报错了。自己想想这个sayHello在obj都已经执行完了,就根本没有sayHello这个函数了。
这几个方法使用的好的话可以帮你解决不少问题比如:
正常情况下Math.max只能这样用
Math.max(10,6)
但如果你想传一个数组的话你可以用apply
var arr = [1,2,30,4,5]; console.log(Math.max.apply(null,arr));1
2
又或者你想让伪数组调用数组的方法
function fn(){ [].push.call(arguments,3); console.log(arguments); //[1, 2, 3] } fn(1,2);1
2
3
4
5
再者:
var arr = ['aaabc']; console.log(''.indexOf.call(arr,'b')); //31
2
实际上浏览器内部根本就不在乎你是谁,它只关心你传给我的是不是我能够运行的,如下:
正常情况
var str = 'aaabc'; console.log(str.indexOf('b'));1
2
而这种情况其实做的事情和上面一模一样,看我来拆解。
var arr = ['aaabc']; ''.indexOf.call(arr);1
2
这句话就是说让arr调用字符串的indexOf方法,前面说过了浏览器内部不在乎你是谁,所以谁都可以来调用,但不是100%成功,具体看如下。
''.indexOf.call(arr,'b')1
这里的arr就是[‘aaabc’],内部很可能拆成了’aaabc’,因此就成了下面的这段代码。
'aaabc'.indexOf('b');1
这里得说一下bind在某些浏览器下不兼容。我们来模拟一个玩玩。
Function.prototype.$bind = function(obj){ //保存当前this var _this = this; //截取除了第一个以外的所有实际参数 var a = [].slice.call(arguments,1); //返回一个新函数 return function(){ //让当前那个调用的函数的this指向obj,并且把实参传给它,这里用了concat是因为,我们可能在绑定以后还传递参数,所以才把他们合并起来。如f(4)这个是在绑定以后传的参数,a这个argument是绑定时的。 _this.apply(obj,a.concat([].slice.call(arguments))); }; };1
2
3
4
5
6
7
8
9
10
11
function fn(a,b,c,d){ console.log(a,b,c,d); } var f = fn.$bind(null,1,2,3); f(4);1
2
3
4
5
6
这个方法和实际上的bind还是差别很大的,如
var arr = ['JSS']; var index = ''.indexOf.$bind(arr,'S'); console.log(index()) ------------------ function fff(){ [].push.$bind(arguments,1); console.log(arguments); } fff();
相关文章推荐
- js中call,apply和bind方法的区别和使用场景
- js中apply、call和bind的区别
- js---js中的继承方法call、bind、apply,以及三者之间的区别总结。
- apply, call, bind在js中的区别
- JS之apply,call,bind区别
- js apply/call/caller/callee/bind使用方法与区别分析
- js apply/call/caller/callee/bind使用方法与区别分析
- js中call() apply() bind()的用法及三者区别
- JS 中的this指向问题和call、apply、bind的区别
- JS中call、apply、bind大概区别
- js中的call()、apply()和bind()方法的区别
- js apply/call/caller/callee/bind使用方法与区别分析
- js中bind、call、apply区别和简单应用
- js中的bind、apply、call、callee、caller的区别
- js中call、apply、bind区别以及个别用例
- js apply/call/caller/callee/bind使用方法与区别分析
- JS中call、apply、bind大概区别
- js apply/call/caller/callee/bind使用方法与区别分析
- js apply/call/caller/callee/bind使用方法与区别分析
- js中call()、apply()、bind()方法的区别