手写自己的call,我们要先通过call的使用,了解都需要完成些什么功能?

call()进行了调用,是个方法,已知是建立在原型上的,使用了多个参数(绑定的对象+传递的参数)。

我们把手写的函数起名为myCall,obj作为形参承载传过来的第一个参数(即绑定的对象)。

Function.prototype.myCall = function(obj){}

call的调用对this的指向进行了改变,而this是函数,这是前提(对this进行判断)。

Funtion.prototype.myCall = function(obj){
  // 判断调用对象是否为函数
  if(typeof this !== 'function'){
    console.error('type error')
  }
}

同理应当判断是否传入了参数,如果没有传入参数,则绑定的对象设置为window。

Funtion.prototype.myCall = function(obj){
  if(typeof this !== 'function'){
    console.error('type error')
}
  // 判断绑定的对象
  obj = obj || window;
}

要调用这个this方法,我们可以先将其作为对象的属性方法,然后调用。

Function.prototype.myCall = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!');
  }
  obj = obj || window;
  // 添加属性方法,并调用
  obj.fn = this;
  obj.fn();
}

call调用完后,拥有使用完方法后的返回值,所以肯定要将方法的执行结果保存并返回。

Function.prototype.mycall = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  obj.fn = this;
  // 将执行结果保存,并返回
  let result = obj.fn();
  return result;
}

在原对象中,并没有obj.fn属性,所以我们要将其进行删除。

Function.prototype.mycall = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  obj.fn = this;
  let result = obj.fn();
  // 删除context.fn属性
  delete obj.fn;
  return result;
}

最后考虑下方法中使用的参数(从传递过来的第二个参数开始),通过slice()进行切割,并拼凑为数组。

Function.prototype.mycall = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  // 获取正确参数
  let args = [...arguments].slice(1)
  obj = obj || window;
  obj.fn = this;
  let result = obj.fn(...args);
  delete obj.fn;
  return result;
}

最后通过一个例子,来验证是否达到call()的功能要求。

Function.prototype.myCall = function(obj) {
  if (typeof this !== 'function') {
    console.error('type error!');
  }
  obj = obj || window;
  let args = [...arguments].slice(1);
  obj.fn = this;
  let result = obj.fn(...args)
  delete obj.fn;
  return result;
}
let dog = {
  name: '狗',
  eat(food1, food2) {
    console.log(this.name + '爱吃' + food1 + food2);
  }
}
let cat = {
  name: '猫',
}
dog.eat.call(cat, '鱼', '肉'); // 猫爱吃鱼肉
dog.eat.myCall(cat, '鱼', '肉'); // 猫爱吃鱼肉

另外两篇:'对apply()函数的分析' 和 '对bind()函数的分析' 。

理解并手写 call() 函数的更多相关文章

  1. 理解并手写 bind() 函数

    有了对call().apply()的前提分析,相信bind()我们也可以手到擒来. 参考前两篇:'对call()函数的分析' 和 '对apply()函数的分析',我们可以先得到以下代码: Functi ...

  2. 理解并手写 apply() 函数

    apply()函数,在功能上类似于call(),只是传递参数的格式有所不同. dog.eat.call(cat, '鱼', '肉'); dog.eat.apply(cat, ['鱼', '肉']); ...

  3. WPF启动流程-自己手写Main函数

    WPF一般默认提供一个MainWindow窗体,并在App.Xaml中使用StartupUri标记启动该窗体.以下通过手写实现WPF的启动. 首先先介绍一下VS默认提供的App.Xaml的结构,如下图 ...

  4. python 精华梳理(已理解并手写)--全是干货--已结

    基础部分 map,reduce,filter,sort,推导式,匿名函数lambda , 协程,异步io,上下文管理 自定义字符串转数字方法一不使用reduce import re def str2i ...

  5. 前端面试题整理——手写bind函数

    var arr = [1,2,3,4,5] console.log(arr.slice(1,4)) console.log(arr) Function.prototype.bind1 = functi ...

  6. 手写bind函数

    实现bind函数 参考MDN提供的Polyfill方案 Function.prototype.myBind = function(context){ //这里对调用者做一个判断,如果不是函数类型,直接 ...

  7. C++之手写strlen函数

    代码: int strlen(const char *str){ assert(str!=NULL); intlen=; while((*str++)!='\0') len++; return len ...

  8. js面试题之手写节流函数和防抖函数

    函数节流:不断触发一个函数后,执行第一次,只有大于设定的执行周期后才会执行第二次 /* 节流函数:fn:要被节流的函数,delay:规定的时间 */ function throttle(fn,dela ...

  9. 【OpenCV学习笔记】之六 手写图像旋转函数---万丈高楼平地起

    话说,平凡之处显真格,这一点也没错!  比如,对旋转图像进行双线性插值,很简单吧?  可,对我,折腾了大半天,也没有达到预期效果!  尤其是三个误区让我抓瞎好久: 1,坐标旋转公式.   这东西,要用 ...

随机推荐

  1. UIPickView的基本使用

    UIPickView和TableView一样,想要展示数据也要设置数据源和代理设置数据源self.pickView.dataSource = self;设置代理self.pickView.delega ...

  2. LaunchScreen原理

    会自动加载LaunchScreen是因为在Target当中,指定了Launch Screen file 它的底层实现其实把LaunchScreen上的东西,生成了一张图片,然后把这张图片设为程序的启动 ...

  3. 学习jsp篇:jsp简单实例之一注册

    编程环境:IDEA,Tomcat ,JavaEE 实例一.注册 1.先在IDEA建一个web工程(不懂的可以在网上搜,一大堆..)ServletTest,在工程目录下的web目录建一个文件夹regis ...

  4. shell基础——数组

    定义数组 #小括号,空格 arr=(v1 v2 v3) arr=(`ls`) 打印数组 echo ${arr[0]} #下标从0开始 echo ${arr[*]} #整个数组 echo ${arr[@ ...

  5. 浅谈Java之反射

    反射 四种获取Class实例的方法 定义测试结构 获取属性结构 获取方法结构 获取构造器结构(包括父类泛型) 获取实现的接口 获取所在包 获取注解 获取并创建指定构造器 获取指定属性 获取并运行指定方 ...

  6. fuzz——AFL基础使用方法

    最近打 ctf 的时候感觉有点遇到瓶颈,就来 fuzz 这块看看. AFL 全称为 American huzzy loop,是 Fuzzing 最高级的测试工具之一.这个工具对有源码和无源码的二进制程 ...

  7. linux13

    ansible-playbook实现MySQL的二进制部署 Ansible playbook实现apache批量部署,并对不同主机提供以各自IP地址为内容的index.html http的报文结构和状 ...

  8. Pandas常用操作 - 新增数据列

    初始化测试数据 df = pd.DataFrame({'stu_name': ['Nancy', 'Tony', 'Tim', 'Jack', 'Lucy'], 'stu_age': [17, 16, ...

  9. 编译安装 tree 命令

    文章目录 下载源码包 编译源码包 tree下载地址:http://mama.indstate.edu/users/ice/tree/ Centos发行版,可以直接使用命令 yum -y install ...

  10. 日行一算(Vowel-大小写转换)

    题目 题目描述 solo从小就对英文字母非常感兴趣,尤其是元音字母(a,e,i,o,u,A,E,I,O,U),他在写日记的时候都会把元音字母写成大写的,辅音字母则都写成小写,虽然别人看起来很别扭,但是 ...