ICode9

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

手写简单call,apply,bind

2021-09-24 17:32:57  阅读:226  来源: 互联网

标签:function hycall bind sum call thisArg apply fn


分析一下call的使用方法:call是显示绑定this指向,然后第一个参数是你所指向的this对象,后面跟着多个参数,以逗号隔开 

function sum(num1,num2){
  return num1 + num2 
} 
sum.call({},1,2)  //  3

上面是一个最简单的call使用方法,call的第一个参数,可以是对象,可以是数字,可以是空对象

当call的第一个参数是undefined或者是null时,他的指向是window


接下来就一步步的开始手写一个简单的call

首先第一步,我们需要在Function内添加一个原型对象hycall

Function.prototype.hycall=function(){
  console.log('我是新的hycall对象');
}
sum.hycall() // 我是新的hycall对象

 然后我们需要在内部执行sum的函数,但是由于这个hycall是通用式,不能写死内部的函数调用

这时候会有个问题:如何知道是谁调用了hycall??

其实很清楚的一个事情,对于this指向熟悉的都知道,sum.hycall是一个隐式绑定,此时的hycall内部的this就是当前的sum对象,我们用一个参数去接收this,再将其运行即可

Function.prototype.hycall=function(thisArg){
  var fn = this // 外部的对象 sum,或者{}等等
  fn()
}
function foo(){
  console.log('我是foo对象',this);
}
sum.hycall({})

 这里实现了一个最简单的call调用方式,接下来第二步,call的第一个参数是存在this指向的,此时的hycall需要接收一个参数对象thisArg,又因为这个参数是this的指向

问题二:如何让传来的this指向绑定到对象上?

对于传来的this指向,可以给其本身添加一个函数对象,再让其自身运行,相当于间接性的调用了函数

Function.prototype.hycall=function(thisArg){
  var fn = this // 外部的对象 sum,或者{}等等
  thisArg.fn=fn // thisArg身上添加一个fn
  thisArg.fn() // 再将其调用即可
  delete thisArg.fn // 调用完成之后再将其删除即可
}
function foo(){
  console.log('我是foo对象',this);
}
sum.hycall({})

 这里看似完成了对this参数的调用,但是此处又有问题出现:call是可以传入number等参数进入的,但是代码中不可能给一个数字添加函数例如123.fn(),此处又该如何解决?

这里有一个例子,当123要变成对象类型时,只需要new Number(123) ,便成为了一个对象。

以上例子说明,我们可以对thisArg进行对象转化

thisArg=Object(thisArg)

 再考虑到call传入undefined或者null的时候,指向的this是window

我们对thisArg做出判断

thisArg=(thisArg !== null && thisArg !== undefined) ? thisArg=Object(thisArg) : window 

第三步,对于传值,call除了能传递this指向,后方还可以跟多个传值,对于我们的hycall的接收,此处可以使用es6的rest参数语法 ...

Function.prototype.hycall=function(thisArg,...args){
  var fn = this // 外部的对象 sum,或者{}等等
  thisArg=(thisArg !== null && thisArg !== undefined) ? thisArg=Object(thisArg) : window // 判断thisArg是否存在,存在将其转换,不存在让其指向window
  thisArg.fn=fn // thisArg身上添加一个fn
  thisArg.fn(...args) // 再将其调用即可 spread--展开运算符
  delete thisArg.fn // 调用完成之后再将其删除即可
}
function sum(a,b){
  return a+b
}
sum.hycall({},1,2)

 最后一步,接收返回值并返回出去

Function.prototype.hycall=function(thisArg,...args){
  var fn = this // 外部的对象 sum,或者{}等等
  thisArg=(thisArg !== null && thisArg !== undefined) ? thisArg=Object(thisArg) : window // 判断thisArg是否存在,存在将其转换,不存在让其指向window
  thisArg.fn=fn // thisArg身上添加一个fn
  var result = thisArg.fn(...args) // 再将其调用即可 spread--展开运算符
  delete thisArg.fn // 调用完成之后再将其删除即可
  return result
}
function sum(a,b){
  return a+b
}
sum.hycall({},1,2)

 以上是对call的一个简单的手写,如果对call的手写熟悉了,apply和bind其实也大同小异,apply第一个参数和call一样,但是第二个参数是以数组的方式进行传递


function sum(num1,num2){
  console.log("sum被调用",this,num1,num2);
  return num1+num2
}

// 系统调用
var result=sum.apply("abc",[20,30])
console.log(result);

 上方是一个正常的系统调用,apply第二个参数不传值时会和call有些不一样

Function.prototype.hyapply=function(thisArg,argArray){
  var fn = this // 外部的对象 sum,或者{}等等
  thisArg=(thisArg !== null && thisArg !== undefined) ? thisArg=Object(thisArg) : window // 判断thisArg是否存在,存在将其转换,不存在让其指向window
  argArray=argArray || []
  thisArg.fn=fn // thisArg身上添加一个fn
  var result = thisArg.fn(...argArray) // 再将其调用即可 spread--展开运算符
  delete thisArg.fn // 调用完成之后再将其删除即可
  return result
}
function sum(a,b){
  return a+b
}
sum.hyapply({},1,2)

 这里又有人要提问了:为什么call那里就可以不用判断第二个参数的值,你这里就需要呢?

因为在hycall中的第二个参数是...args 倘若我们未传值过来,...args的值=[],所以不需要对call的第二参数做出判断


下面开始对bind进行分析,bind是以返回一个函数的方法进行使用的

function sum(num1,num2,num3,num4){
  console.log(num1,num2,num3.num4)
}
function bar(){
  console.log("我是bar")
}
// 方式一
var newBar=bar.bind("aaa")
newBar()

// 方式二
var newSum=sum.bind("aaa",10,20,30,40)
newSum()

// 方式三
var newSum=sum.bind("aaa",10)
newSum(20,30,40)

手写bind函数

Function.prototype.hybind=function(thisArg,...argArray){
  var fn = this // 外部的对象 sum,或者{}等等
  thisArg=(thisArg !== null && thisArg !== undefined) ? thisArg=Object(thisArg) : window 
  function proxyFn(){
  	thisArg.fn=fn
    var result=thisArg.fn()
    deletr thisArg.fn
    return result
  }
  return proxyFn
}
function sum(a,b){
  return a+b
}
var newSum=sum.hybind("aaa")
newSum()

接下来需要考虑上方的一种情况

// 方式三
var newSum=sum.bind("aaa",10)
newSum(20,30,40)

由于我们的hybind只有两个参数,但你传第三个参数的时候,就需要内部调用

Function.prototype.hybind=function(thisArg,...argArray){
  var fn = this // 外部的对象 sum,或者{}等等
  thisArg=(thisArg !== null && thisArg !== undefined) ? thisArg=Object(thisArg) : window 
  function proxyFn(...args){ //此处接收第三个参数
  	thisArg.fn=fn
    var finalArgs=[...argArray,...args]//拼接两个数组
    var result=thisArg.fn(...finalArgs)
    deletr thisArg.fn
    return result
  }
  return proxyFn
}
function sum(a,b){
  return a+b
}
var newSum=sum.hybind("aaa",10)
newSum(20,30,40)

 以上就是对三个显示绑定的简单手写,其实对于上面的边界判断其实还不是很完善,例如=0的时候(优化边界判断),例如fn本身就存在然后给覆盖(使用ES6-symbol语法定义解决)等等

 如有更好的意见和完善的地方欢迎补充留言,感谢coderwhy老师的指导

标签:function,hycall,bind,sum,call,thisArg,apply,fn
来源: https://www.cnblogs.com/lemonnnnz/p/15331165.html

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

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

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

ICode9版权所有