第一印--模拟call函数的实现:
第一步我们向所有函数父类的原型上也就是window的Function属性原型上添加模仿的call函数
//Function原型上添加模仿的call函数
Function.prototype.imicall=function (){
console.log("模拟call:");
//这里面的this就是sum这个函数
let fn=this
fn()
}
function sum(){
console.log("i am sum:",this);
}
sum.imicall()
第二步尝试用隐式绑定把函数引用的this绑定到指定传入的对象上(简单实现)
Function.prototype.imicall=function (flag){
console.log("模拟call:");
let fn=this
flag.fn=fn
flag.fn()
delete flag.fn
}
function sum(){
console.log("i am sum:",this);
}
var obj={name:'xwl'}
sum.imicall(obj)
第三步考虑边界(绑定对象的选值情况)--进一步完善this绑定
首先要知道通过call函数绑定的this类型最后都为object
function test(){
console.log(typeof this);
console.log(this);
console.log("i am test");
}
test.call(123)
接下来考虑下null和undefined如何处理
我们先来看下结果
可以看到都是window,至于转换成对象,这个简单,直接用Object包裹就可以了
所以思路如下:如果flag有值且不为空那么就用Object包裹,否则就赋为window
Function.prototype.imicall=function (flag){
console.log("模拟call:");
if(flag!==0){
flag=flag?Object(flag):window
}else{
flag=Object(flag)
}
let fn=this
flag.fn=fn
flag.fn()
delete flag.fn
}
function sum(){
console.log("i am sum:",this);
}
var obj={name:'xwl'}
sum.imicall(obj)接下来我们来测试下好使不
Function.prototype.imicall=function (flag){
console.log("模拟call:");
if(flag!==0){
flag=flag?Object(flag):window
}else{
flag=Object(flag)
}
let fn=this
flag.fn=fn
flag.fn()
delete flag.fn
}
function sum(){
console.log("i am sum:",this);
}
var obj={name:'xwl'}
sum.imicall(obj)
sum.imicall(null)
sum.imicall(undefined)
sum.imicall()
第四步解决参数传递问题
首先想到的是我们能不能用函数自带的保存参数的arguments来做
Function.prototype.imicall=function (flag){
console.log("模拟call:");
console.log(arguments);
if(flag!==0){
flag=flag?Object(flag):window
}else{
flag=Object(flag)
}
let fn=this
flag.fn=fn
flag.fn()
delete flag.fn
}
function sum(num1,num2){
console.log("i am sum:",this);
console.log(num1+num2);
}
var obj={name:'xwl'}
sum.imicall(obj,1,2)
所以我们把下标从1开始的元素推到新的数组里,再将数组展开放到执行函数参数中
Function.prototype.imicall=function (flag){
console.log("模拟call:");
let args=[]
for(var i=1;i<arguments.length;i++){
args.push(arguments[i])
}
if(flag!==0){
flag=flag?Object(flag):window
}else{
flag=Object(flag)
}
let fn=this
flag.fn=fn
flag.fn(...args)
delete flag.fn
}
function sum(num1,num2){
console.log("i am sum:",this);
console.log(num1+num2);
}
var obj={name:'xwl'}
sum.imicall(obj,1,2)
感觉有点麻烦对吗?
那就用es6,需要注意的是如果我们向flag后面添加个新的参数,并对其展开,那么它会是什么?
欸嘿,它直接就是数组,那就好办了,底下直接展开不就完事了!
第五步别家函数都可以显示返回值,你不也得搞一个!
Function.prototype.imicall=function (flag,...args){
console.log("模拟call:");
if(flag!==0){
flag=flag?Object(flag):window
}else{
flag=Object(flag)
}
let fn=this
flag.fn=fn
var result=flag.fn(...args)
console.log(result);
delete flag.fn
return result
}
function sum(num1,num2){
console.log("i am sum:",this);
// console.log(num1+num2);
return num1+num2
}
var obj={name:'xwl'}
var res=sum.imicall(obj,1,2)
console.log(res);
最后一步完整版
Function.prototype.imicall=function (flag,...args){
console.log("模拟call:");
if(flag!==0){
flag=flag?Object(flag):window
}else{
flag=Object(flag)
}
let fn=this
flag.fn=fn
var result=flag.fn(...args)
delete flag.fn
return result
}
function sum(num1,num2){
console.log("i am sum:",this);
return num1+num2
}
var obj={name:'xwl'}
var res=sum.imicall(obj,1,2)
京公网安备 11010502036488号