手写call,apply,bind
1.手写call函数
实现call函数首先了解call函数的作用:call()
方法使用一个指定的this
值和单独给出的一个或者多个参数来调用一个函数。
1 2 3 4 5 6 7 8 9
| function func(numA,numB){ console.log(this); return numA + numB } function sum(){ return '定义一个sum函数' } const res = func.call(sum,1,3) console.log('返回值为',res);
|
手写call函数,任何函数都可以调用它,在函数Function
的原型上加上自己手写的call函数,具体操作如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| Function.prototype.myCall=function(ctx,...args){ ctx = (ctx===undefined||ctx===null?globalThis:Object(ctx)) let key = Symbol('test') Object.defineProperty(ctx,key,{ enumerable:false, value:this, configurable:true }) let result = ctx[key](...args) delete ctx[key] return result }
function func(numA,numB){ console.log(this); return numA + numB } function sum(){ return '定义一个sum函数' } const res2 = func.myCall(sum,1,3) console.log('返回值为',res);
|
tips:Symbol
是ES6新增的一种数据类型,每个从Symbol()
返回的Symbol
值都是唯一的,用来作为对象属性的标志符。
1 2 3 4 5 6
| const s1 = Symbol() const s2 = Symbol() console.log(s1===s2); const s3 = Symbol('test') const s4 = Symbol('test') console.log(s3===s4);
|
2.手写apply函数
apply函数和call函数非常类似,只是第二个参数是一个数组。apply函数的使用:
1 2 3 4 5 6 7 8 9
| function func(numA,numB){ console.log(this); return numA + numB } function sum(){ return '定义一个sum函数' } const res = func.apply(sum,[1,3]) console.log('返回值为',res);
|
手写apply函数也跟call大致相似。在函数对象原型上定义的myApply
第二参数不需要用剩余参数的形式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Function.prototype.myApply = function(ctx,args){ ctx = (ctx===undefined||ctx===null?globalThis:Object(ctx)) let key = Symbol('key') Object.defineProperty(ctx,key,{ enumerable:false, value:this, configurable:true }) console.log(...args); let result = ctx[key](...args) delete ctx[key] return result }
function func(numA,numB){ console.log(this); return numA + numB } function sum(){ return '定义一个sum函数' } const res = func.myApply(sum,[1,3]) console.log('返回值为',res);
|
3.手写bind函数
bind函数也可以改变函数的this值,指向第一个参数。具体用法:
1 2 3 4 5 6 7 8 9
| function func(a,b,c,d){ console.log(a,b,c,d); console.log(this); return 111 }
const newFn = func.myBind('ctx',1,2) let result = newFn(3,4) console.log(result);
|
与call,aplly不同,bind会创建一个新的函数实例,需要再次调用函数。
手写apply
,先从函数原型上绑定自定的myBind,核心就是获取改变调用函数的this,指向传入的第一个参数,然后获取两次传递的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Function.prototype.myBind = function(ctx){ var args = Array.prototype.slice.call(arguments,1) var fn = this return function A(){ var restArgs = Array.prototype.slice.call(arguments) allArgs = args.concat(restArgs) if(Object.getPrototypeOf(this)===A.prototype){ return new fn(...allArgs) }else{ return fn.apply(ctx,allArgs) } } }
const newFn =func.myBind('ctx',1,2) let result = new newFn(3,4) console.log(result);
|
tips:关于判断是否用new创建实例,这里要了解new创建实例的步骤,
1.