js call原理,apply原理

call的特点

  1. 可以改变我们当前函数的this指向

  2. 还会让当前函数执行

 

function fn1() {
    console.log(this)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call();     //此时this指向window

function fn1() {
    console.log(this)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call();     //此时this指向window
fn1.call('hello')

 

 call还能传参

function fn1() {
    console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call();     //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')

 call方法大概原理,在原型链上增加call方法,在方法内部使用this()执行函数

function fn1() {
    console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call();     //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')

function fn2() {
    console.log('2')
}

function fn3() {
    console.log('3')
}
// Function.prototype.call = function(context){
//     this()      //执行当前函数
// }
fn2.call(fn3)

function fn1() {
    console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call();     //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')

function fn2() {
    console.log('2')
}

function fn3() {
    console.log('3')
}
// Function.prototype.call = function(context){
//     this()      //执行当前函数
// }
fn2.call(fn3)
fn2.call.call(fn3)      //call会改变当前的this指向,此时this指向fn3,this()执行fn3()

 

 手写call方法

function fn1() {
    console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call();     //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')

function fn2(a,b) {
    console.log('fn2',this,arguments)
}

function fn3() {
    console.log('fn3',this,'3')
}
Function.prototype.call = function(context){
    context = context ? Object(context):window
    console.log('context',context)
    context.fn = this
    console.log('context.fn',context.fn)
    let args = []
    for(let i=1;i<arguments.length; i++){
        args.push('arguments['+i +']')      // ['arguments[1]','arguments[2]']
    }
    console.log(args)
    //利用数组的toString特性
    const str = 'context.fn('+args + ')';
    console.log(str)                        //context.fn(arguments[1],arguments[2])
    let r = eval(str)
    delete context.fn
    console.log('r',r)
    return r
}
fn2.call(fn3,1,'2')
fn2.call.call(fn3)      //call会改变当前的this指向,此时this指向fn3,this()执行fn3()

fn2.call是函数,是如下函数,所以fn2.call.call(fn3) 中最后调用call的调用者为fn2.call,是如下函数。其实因为如下函数挂载到Function.prototype,所以fn2.call.call.call.call无论调用多少次,fn2.call是函数,是函数就有如下方法,如下方法又是函数,则又有如下方法。所以fn2.call.call.call.call.call(fn3)就等于如下函数.call(fn3)。

function(context){
    context = context ? Object(context):window
    console.log('context',context)
    context.fn = this
    console.log('context.fn',context.fn)
    let args = []
    for(let i=1;i<arguments.length; i++){
        args.push('arguments['+i +']')      // ['arguments[1]','arguments[2]']
    }
    console.log(args)
    //利用数组的toString特性
    const str = 'context.fn('+args + ')';
    console.log(str)                        //context.fn(arguments[1],arguments[2])
    let r = eval(str)
    delete context.fn
    console.log('r',r)
    return r
}

context=fn3,转变为对象加上fn属性,属性值等于上边此函数,eval (context.fn())=此函数执行,调用者为context=fn3,此时传进此函数的参数为空,context为空,打印出window作为上下文,this=调用者=fn3,context.fn=this=fn3,执行eval(context.fn())=fn3()

apply原理

与call类似,只不过参数传的是数组,所以在call函数中的把参数封装成数组就不用了

function fn2(a,b) {
    console.log('fn2',this,arguments)
}

function fn3() {
    console.log('fn3',this,'3')
}
Function.prototype.apply = function(context,args){
    context = context ? Object(context):window
    console.log('context',context)
    context.fn = this
    console.log('context.fn',context.fn)
    console.log(args)
    if(!args){
        context.fn();
    }
    //利用数组的toString特性
    const str = 'context.fn('+args + ')';
    console.log(str)                        //context.fn(arguments[1],arguments[2])
    let r = eval(str)
    delete context.fn
    console.log('r',r)
    return r
}
fn2.call(fn3,[1,2,3,4])

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值