ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

彻底弄懂bind,apply,call三者的区别 (转)

2022-08-29 23:36:12  阅读:195  来源: 互联网

标签:arr 指向 bind 参数 apply call


为什么要改变this指向?

我们知道bind,call,apply的作用都是用来改变this指向的,那为什么要改变this指向呢?请看下面的例子:

var name="lucy";
let obj={
 name:"martin",
 say:function () {
 console.log(this.name);
 }
};
obj.say(); //martin,this指向obj对象
setTimeout(obj.say,0); //lucy,this指向window对象

可以观察到,正常情况下 say 方法中的 this 是指向调用它的 obj 对象的,而定时器 setTimeout 中的 say 方法中的 this 是指向window对象的(在浏览器中),这是因为 say 方法在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,但我们需要的是 say 方法中 this 指向obj对象,因此我们需要修改 this 的指向。

apply方法

apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变thi指向一次。

日常用法:改变this指向

示例:

回调函数绑定this指向:

var name="martin";
var obj={
 name:"lucy",
 say:function(year,place){
 console.log(this.name+" is "+year+" born from "+place);
 }
};
var say=obj.say;
setTimeout(function(){
 say.apply(obj,["1996","China"])
} ,0); //lucy is 1996 born from China,this改变指向了obj
say("1996","China") //martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向

 

小技巧:改变参数传入方式

示例:

求数组中的最大值:

var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr)); //10

  

其中Math.max函数的参数是以参数列表,如:Math.max(1,10,5,8,3)的形式传入的,因此我们没法直接把数组当做参数,但是apply方法可以将数组参数转换成列表参数传入,从而直接求数组的最大值。

call方法

call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。

示例:

var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10

  

采纳以参数列表的形式传入,而apply以参数数组的形式传入。

bind方法

bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。

示例:

var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参

  

可以看出,bind方法可以分多次传参,最后函数运行时会把所有参数连接起来一起放入函数运行。

实现bind方法(面试题):

简易版

Function.prototype.bind=function () {
 var _this=this;
 var context=arguments[0];
 var arg=[].slice.call(arguments,1);
 return function(){
 arg=[].concat.apply(arg,arguments);
 _this.apply(context,arg);
 }
 };

  

完美版

//实现bind方法
 Function.prototype.bind = function(oThis) {
 if (typeof this !== 'function') {
 // closest thing possible to the ECMAScript 5
 // internal IsCallable function
 throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
 }
 var aArgs = Array.prototype.slice.call(arguments, 1),
 fToBind = this,
 fNOP = function() {},
 fBound = function() {
 // this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
 return fToBind.apply(this instanceof fBound
 ? this
 : oThis,
 // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
 aArgs.concat(Array.prototype.slice.call(arguments)));
 };
 // 维护原型关系
 if (this.prototype) {
 // 当执行Function.prototype.bind()时, this为Function.prototype 
 // this.prototype(即Function.prototype.prototype)为undefined
 fNOP.prototype = this.prototype; 
 }
 // 下行的代码使fBound.prototype是fNOP的实例,因此
 // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
 fBound.prototype = new fNOP();
 return fBound;
 };
 var arr=[1,11,5,8,12];
 var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3]);
 console.log(max(arr[4])); //12

  

apply,call,bind三者的区别

  • 三者都可以改变函数的this对象指向。
  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window。
  • 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
  • bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行

 

 

ref: https://zhuanlan.zhihu.com/p/82340026

标签:arr,指向,bind,参数,apply,call
来源: https://www.cnblogs.com/jane-panyiyun/p/16637780.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有