深入call apply bind

栏目: JavaScript · 发布时间: 7年前

内容简介:稍微翻了一下call,apply, bind 的各种论坛上的文章, 发现讲的都太浅了,大部分都只讲了个用法, 对于实现的原理却都没有提,因此,在这里,我写下这篇文章, 希望能让大家认识到原理所在。众所周知, 这三个函数都是改变执行上下文的 , 那么我们来捋一捋,这些函数内部到底做了什么。Function是函数对象的构造方法,call,apply,bind 都是函数原型上的方法 作为实例 他自身也有这三个方法

前言

稍微翻了一下call,apply, bind 的各种论坛上的文章, 发现讲的都太浅了,大部分都只讲了个用法, 对于实现的原理却都没有提,因此,在这里,我写下这篇文章, 希望能让大家认识到原理所在。

众所周知, 这三个函数都是改变执行上下文的 , 那么我们来捋一捋,这些函数内部到底做了什么。

call

Function是函数对象的构造方法,call,apply,bind 都是函数原型上的方法 作为实例 他自身也有这三个方法

深入call apply bind

圈中的为原型方法, 方块的为实例方法,另外length属性就是argument的长度,我们通常调用一个函数

function a(){ console.log(this,'a')};
function b(b){console.log(b)}
a.call(b,'我是B的参数')

深入call apply bind

执行a, 并把context指向b, 这里大家都没有疑问, 那么问题来了

function a(){ console.log(this,'a')};
function b(){console.log(this,'b')}
a.call.call.call(b,'b')  // 这个结果是什么呢?
答案是

深入call apply bind

傻眼了吧 ? 怎么执行了B 并且this指向了这个 b字符串

我们来分析一下 call是原型上的方法 那么a.call 他本身也是一个函数 所以a.call.call.call 不就是a.call.call的原型上的call方法么?

所以不就是执行call.call 并改变 call.call的上下文

我们来撸一遍call的源码,

深入call apply bind

第一个参数是上下文, 当我们call(null),this指向了window 当我们传入字符串 会把字符串包装成对象

a.call 执行 this是指向a的(谁调用this 指向谁) 然后又执行了a方法,所以内部是

Function.prototype.call = function(context){
    context = context ? Object(context):window
    this()   // 因为调用的都是函数 所以this是一个函数 也就是a
}

那这样并未改变this指向啊,咋办? 上句话不是说((谁调用this 指向谁)),所以我们要在内部改变掉this,做如下修改

Function.prototype.call = function(context){
    context = context ? Object(context):window
    context.fn = this  
    context.fn() // 通过调用context.fn 来改变调用者 实现fn的this指向context 即改变a内部的this
}

那么参数怎么传呢,我们首先要拿到call的里的参数

Function.prototype.call = function(context,...args){
    context = context ? Object(context):window
    context.fn = this  
    let r = context.fn(...args) // 通过调用context.fn 来改变调用者 实现fn的this指向context 即改变a内部的this
    delete context.fn   //删除属性
    return r  // 返回执行的结果 
}

现在我们回头分析一下a.call.call.call(b,'b')

a.call.call是个函数,它调用call方法 执行它 我们进入函数里面看看

首先把context 也就是b转为字符串对象 它的属性上赋予fn 也就是a.call.call ,然后执行context.fn(...args), 也就是a.call.call('b') 接着删除fn 返回执行结果 宏观来看 是a.call.call这个函数去执行并传入('b') a.call.call 也就是Function.prototype.call 所以就是call('b') 所以啊, 结果才是this是指向string的b 并且参数是undefined

Function.prototype.call = function(context,...args){
    context = context ? Object(context):window 
    context.fn = this  //a.call.call('b')
    var r = context.fn(...args) // 通过调用context.fn 来改变调用者 实现fn的this指向context 即改变a内部的this
    delete context.fn
    return r
}


function a(){ console.log(this,'a')};
function b(args){console.log('我是this:' + this,'我是b的参数args:' + args)}
a.call.call.call(b,'我到底是参数呢还是this')

深入call apply bind

结论!

一个函数call2次或者2次以上 执行的永远是b, 并且call的第二个参数成为当前context

apply

apply 就是参数不同 直接上代码

Function.prototype.apply = function(context,...args){
    context = context ? Object(context):window 
    context.fn = this;
    var r; 
    if(args.length){
        r = context.fn(...args) 
        delete context.fn
    }else{
        r = context.fn()
    }
    return r
}


function a(args){ console.log(this,args)};
function b(){console.log('我是this:' + this)}
a.apply(b,[1,2,3,4])

深入call apply bind

bind 明天写 累了


以上所述就是小编给大家介绍的《深入call apply bind》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Mobilizing Web Sites

Mobilizing Web Sites

Layon, Kristofer / 2011-12 / 266.00元

Everyone has been talking about the mobile web in recent years, and more of us are browsing the web on smartphones and similar devices than ever before. But most of what we are viewing has not yet bee......一起来看看 《Mobilizing Web Sites》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具