JavaScript中call方法的手动实现,与多个call连用引发的思考.

红牛战神
• 阅读 2980
今天在学习js的时候想到个有趣的问题, 自己实现一个call方法?. 
改变一个函数的this指向这种事听起来真的很原生态.

第一步:
  知己知彼,先从这个方法本身下手, 看看他到底有什么神通.
  // 1:定义个举例函数;
  function fn1(n){
   console.log('我是fn1',n,this)
  }
  function fn2(n){
   console.log('我是fn2',n,this)
  }
  let call = fn1.call
  
  // 2: 打印一下 他的call方法
  // 既然是function, 本身也就肯定也有call方法了,继续
  console.log(call)            // ƒ call() { [native code] }  
  console.log(call.call)       // ƒ call() { [native code] }
  console.log(call.call.call)  // ƒ call() { [native code] }
  
  // 3: 实际试试输出
    fn1.call.call(fn2,1)            // 我是fn2  undefined  Number {1}
    fn1.call.call.call(fn2,1)       // 我是fn2  undefined  Number {1}
    fn1.call.call.call.call(fn2,1)  // 我是fn2  undefined  Number {1}
    
  // 4: 看到这个结果的时候我蒙了, 这怎么执行fn2了, n是未定义, this指向了1
  //    感觉整体往后移了一位, ?呆滞.
  
  第二步: 查资料,逐步实现.
    真的很好奇,难道里面有什么判断规则?, 我找了几篇文章, 也没找到答案, 最后在曾经看过的视频里面找到了答案.
    // 1: 当然是定义在函数上了
    Function.prototype.myCall = function(context) {
     // 2: 如果传进来的第一个参数为空,就把它当做window, 所以我们平时想要指向window的时候才会穿个undefined,''之类的, Object()一下这个数, 是为了让他本身可以有对象的特性.
       context = context ? Object(context) : window;
     // 3: 这个this就是调用当前call方法的'.'前面的对象
     // 相当于模拟了一个对象
     // context === fn2 === { fn:fn1 } // 所以里面的fn1的this指向也就是父级fn2了.
      context.fn = this;
     // 4: 参数要处理一下, 以便传入到函数里面.
    let as = [];
       // 要从1开始, 因为第一个要作为this
    for (let i = 1; i < arguments.length; i++) {
      as.push(arguments[i]);
     }
    // 5: 执行context的fn方法, 也就是执行, 调用call的函数
    //    数组的加法, 比如 [1,2,3]+'' 结果是 1,2,3 这样就符合参数的样子了
    let r = eval('context.fn(' + as + ')');
    
    // 6: 做完这些, 当然要好好善后啦
    delete context.fn;
    return r
    };
    
    // 实验结果
    fn1.call(fn2,1) // 我是fn1 1 fn2
    
    
    第三步: 让我们来理解一下那个多次调用的问题.
    
    首先 :不管写几个call 都是call方法本身去调了一下call(fn2), 执行的时候,也就是相当于, 把call它的this指向变成 fn2, 并执行call这个方法,  而call这个方法一执行就会默再去认执行一下相当于fn2.call(后面的参数),因为fn2是他的this, 就相当于把后面的 1 当做要指定的this传进去, 也就造成了往后窜了一位.
    
    第四步: 总结
     
     不管写多少个call, 执行第一个参数, 第二个参数为第一个参数this的指向, 第三个参数开始是传参...哈哈挺有意思!
  
  
  
  
  
  
  
  
  
  
点赞
收藏
评论区
推荐文章
Dax Dax
4年前
JavaScript中call()、apply()、bind()的用法
call()apply()bind()都是用来更改this的指向的其中bind()返回的是一个函数,必须执行才行传参差异:call、bind、apply这三个函数的第一个参数都是this的指向对象,第二个参数差别就来了:call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面obj.myFun.call(db,'
巴拉米 巴拉米
4年前
bind、call、apply 区别?如何实现一个bind?
一、作用call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向那么什么情况下需要改变this的指向呢?下面举个例子var name"lucy";const obj{    name:"martin",    say:function (){        co
LinMeng LinMeng
4年前
call、apply、bind三者为改变this指向的方法。
共同点:第一个参数都为改变this的指针。若第一参数为null/undefined,this默认指向window差异点如下:1.call(无数个参数)第一个参数:改变this指向第二个参数:实参使用之后会自动执行该函数functionfn(a,b,c){console.log(this,abc);//this指
晴空闲云 晴空闲云
3年前
JavaScript中isPrototypeOf函数详解
有时看一些框架源码的时候,会碰到isPrototypeOf()这个函数,那么这个函数有什么作用呢?isPrototypeOf()isPrototypeOf()是Object函数(类)的下的一个方法,用于判断当前对象是否为另外一个对象的原型,如果是就返回true,否则就返回false。这个函数理解的关键是在原型链上,这个据说是JavaScript
Stella981 Stella981
3年前
Spark RDD操作之Map系算子
  本篇博客将介绍SparkRDD的Map系算子的基本用法。  1、map    map将RDD的元素一个个传入call方法,经过call方法的计算之后,逐个返回,生成新的RDD,计算之后,记录数不会缩减。示例代码,将每个数字加10之后再打印出来, 代码如下importjava.util.Arrays;im
Stella981 Stella981
3年前
Javascript 是如何体现继承的 ?
js继承的概念js里常用的如下两种继承方式:原型链继承(对象间的继承)类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现在面向对象的语言中,我们使用类来创建一个自定义对象
Wesley13 Wesley13
3年前
Java多线程(全)学习笔记(下)
七.Callable和Future接口    C可以把任意方法包装成线程执行体,包括那些有返回值的方法。Java也从jdk1.5开始,加入了Callable接口用来扩展Runnable接口的功能,Callable接口提供一个call()来增强Runnable的run()。因为call()可以有返回值,可以声明抛出
Stella981 Stella981
3年前
JS 中的this指向问题和call、apply、bind的区别
this的指向问题一般情况下this对象指向调用函数的对象,全局环境中执行函数this对象指向window。functiona(){console.log(this);//输出函数a中的this对象}functionb(){};varc{name:"call"}
Stella981 Stella981
3年前
JavaScript中call()与apply()有什么区别?
今天读《JavaScript权威指南》时发现其中有段代码用到了apply方法用于递归实现数组的展开。可是我不懂这个函数的用法,因此查了一下,将资料整理如下。Javascript的每个Function对象中有一个apply方法:function.apply(thisObj,argArray)还有一个类似功能的call方法:
Stella981 Stella981
3年前
Javascript中,实现类与继承的方法和优缺点分析
Javascript是一种弱类型语言,不存在类的概念,但在js中可以模仿类似于JAVA中的类,实现类与继承第一种方法:利用Javascript中的原型链1//首先定义一个父类23functionAnimal(name,age){4//定义父类的属性5thi
Stella981 Stella981
3年前
Python中函数和方法的区别
1、函数要手动传self,方法不用传self2、如果是一个函数,用类名去调用,如果是一个方法,用对象去调用 举例说明:classFoo(object):def__init__(self):self.name"haiyan"deffunc(self):