call的用法是简单粗暴,但是要彻底理解深刻也需要一丢丢的研究. 一般简单的正常的使用就很容易啦 比如
fn1.call(obj)
就是执行fn1的时候,把fn1里面的this指向obj
其实可以这么理解 虽然有点邪门,但是确实可以这样去想
fn1.call(obj) 相当于 obj.fn1= fn1 //obj有一个属性是fn1
然后 执行 obj.fn1( ) 这样fn1的this自然指向了obj, 然后用完之后过河拆桥,
delete obj.fn1 把obj的fn1属性删掉,因为只是借用这个方法,obj本身并没有保留这个方法 ,所以删掉
从这个角度去理解call做了什么就很容易了. 不过我在网上看见了一个邪门的东西
function fn1 (){ console.log( '1' )}
function fn2 (){ console.log( '2' )}
fn1.call(fn2) //1
fn1.call.call(fn2) //????
fn1.call(fn2)挺好理解的 因为fn2里面并没有this的操作 所以就只是fn1执行就完事了
那么fn1.call.call是什么呢 去浏览器实验 发现是得2
其实是相当于
let fn1Call =fn1.call
fn1Call.call(fn2)
这样去理解就清晰一点了 就是执行fn1Call这个对象(函数)的call属性,并把fn2当参数传入
但是(fn1.call)这个方法是什么呢?让我们来造一个call函数出来
Function.prototype.myCall=function( ){
let args=[]
Object.assign(args,arguments)//复制一份参数数组出来
args.splice(0,1) //第一个是context 去掉
let context =arguments[0] || window
context.func =this
context.func(...args)
delete context.func
}
function fn1 (){ console.log( '1' )}
function fn2 (){ console.log( '2' )}
fn1.call(fn2) //1
fn1.call.call(fn2) //2
这个就是call的基本实现原理 那么为什么fn1.call.call(fn2)是2呢, 一步一步解析 fn1.call其实是等于这个函数
//fn1.call 就下面这个函数
function( ){
let args=[]
Object.assign(args,arguments)//复制一份参数数组出来
args.splice(0,1) //第一个是context 去掉
let context =arguments[0] || window
context.func =this
context.func(...args)
delete context.func
}
let fn1Pro =fn1.call
然后再慢慢解析 fn1Pro.call(fn2) 把fn1Pro的this改成 fn2 然后执行 fn1Pro 然后fn1Pro里面做了什么
let context =arguments[0] || window
context.func =this
context.func(...args)
fn1Pro就是把传进去的参数执行了 仅此而已,那么传进去了什么参数了 f2
那么执行的结果 就是 2
这样我们就能明白到底这call是怎么回事了