一、call()
-
ES6之前
Function.prototype.myCall = function (_context){ // _context空检测 _context = _context? _context: window; // 获取函数参数 let args = []; for(let i=1, len=arguments.length; i<len; i++){ // 避开在eval时组装参数中字符串的麻烦 args.push('arguments[' + i + ']'); } // 将函数挂到_context上 _context.__fn = this; // 执行函数 let result = eval('_context.__fn(' + args + ')'); // 删除_context内的新函数 delete _context.__fn; return result; }
-
ES6之后
Function.prototype.myCall = function (_context){ // _context空检测 _context = _context? _context: window; // 获取函数参数 let args = [...arguments].slice(1); // 将函数挂到_context上 let fnKey = Symbol(); // Symbol是唯一的 _context[fnKey] = this; // 执行函数 let result = _context[fnKey](...args); // 删除_context内的新函数 delete _context[fnKey]; return result; }
二、apply()
-
ES6之前
Function.prototype.myApply = function(_context, _arr){ // _context检测 _context = _context? _context: window; // _arr检测 let args = []; if(!_arr) args = null; else if(_arr instanceof Array === false) throw new Error('params must be array'); else{ for(let i=0, len=_arr.length; i<len; i++){ // 避开在eval时组装参数中字符串的麻烦 args.push('_arr[' + i + ']'); } } // 函数挂到_context上 _context.__fn = this; // 函数调用 let result = eval('_context.__fn(' + (args? args: '') + ')'); // 删除_context内的新函数 delete _context.__fn; return result; }
-
ES6之后
Function.prototype.myApply = function(_context, _arr){ // _context检测 _context = _context? _context: window; // 函数挂到_context上 let fnKey = Symbol(); // Symbol是唯一的 _context[fnKey] = this; // 函数调用 let result; if(!_arr) result = _context[fnKey](); else if(_arr instanceof Array === false) throw new Error('params must be array'); else result = _context[fnKey](..._arr); // 删除_context内的新函数 delete _context[fnKey]; return result; }
三、注意
- ES6之前不能使用
Symbol
的话,最好先判断下_contex
中是否有与即将定义的__fn
相同的键名,有的话需要对键值进行备份以及后续的恢复。