这是三个常用的操作函数的方法,在js中函数就是一等公民,所以说掌握这三个方法还是有必要的
call 和 apply,都会绑定函数的上下文(context)并立即执行调用该方法函数,两者区别在于,接受的参数格式不一样。
call 接收的参数形式是: (context,arg1,arg2,ar3....) // argn 是一个个具体的参数
apply 接收的参数形式是: (context,argArr) // argArr 可以是一个有参数组成的数组或者arguments
bind 会返回绑定调用该方法的函数上下文的新的函数。
1.call的示例
var a = { name: 'aa', getName: function(age) { return this.name + ',' + age; } }; var b = { name: 'bbb' }; a.getName.call(b,23) // bbb,23
1.用call实现apply
现在的我能想到的办法就是通过eval对参数进行拼接,因为函数底层操作参数的方法没有暴露(可能不知道吧)
代码示例
这里先看下一个eval作用域的事情,经过测试eval方法获取变量也是在划分作用域的,并不是从全局获取,示例:
(function () { var me = {name: '33'}; console.log(eval('me')); // 33 })();
这样我们就能拿到函数原来的上下文
用call实现apply
// 用个low的办法实现apply Function.prototype.fakeApply = function (context,arguments) { // 拼接参数 var arg; // 如果有参数将参数转换成数组 if(arguments){ arg = [].slice.call(arguments,0); // 将数组拼接成字符串格式 -> arg1,arg2,arg3,... arg = arg.join(','); } var excuteStr = 'this.call(context' + (arg ?',' + arg : '' ) + ')'; // this.call(context,2,3,4) console.log(eval('this.call(context' + (arguments ?',' + [].slice.call(arguments,0).join(',') : '' ) + ')')); // { name: 44 } // { '0': 2, '1': 3, '2': 4 } // ok }; var a = { name: 'aa', getName: function() { console.log(this); console.log(arguments); return 'ok'; } }; a.getName.fakeApply({name:44},[2,3,4]);
为了加深bind理解,下面是用apply实现bind的示例
Function.prototype.fakeBind = function () { // bind 有可能会传入绑定的参数 var prevFun = this; var context = arguments[0]; var prevArg = arguments.length > 1 ? [].slice.call(arguments,1) : [] ; return function () { var curArg = [].concat.apply(prevArg,arguments); return prevFun.apply(context,curArg); }; }; var fun1 = function () { console.log(this); console.log(arguments); }; var fun2 = fun1.fakeBind({name: 'aaa'},2,3); fun2(4,5); // { name: 'aaa' } // { '0': 2, '1': 3, '2': 4, '3': 5 }
返回了一个新的函数,函数中的prevFun和preArg 是闭包的变量。