新开一个坑,起名为【build your xxx】,本身造一些小轮子。
工做中不要重复造轮子,可是以学习的目的去造轮子却意义重大。
以前貌似在知乎上看到一个问题是说如何使用JavaScript实现它原生的call和apply方法,今天我来实现一番。git
首先看看call是干什么的,从MDN上扒一张图:
举个例子github
function showName(gender, age){ console.log(this.name, " ", gender, " ", age) } var obj = { name: "亚古" } showName.call(obj, "female", 22)// 亚古 female 22
梳理思路
能够看出来Func.call(obj, arg1, arg2...)实现了这么几件事:数组
实现app
Function.prototype.Zcall = function (othis) { othis.fn = this; othis.fn(); } showName.Zcall(obj) // 亚古 undefined undefined
第一个步骤已经实现了,可是很明显的是这样子会对传入的othis形成反作用,即给othis对象平白无故添加了一个方法,因此:学习
Function.prototype.Zcall = function (othis) { othis.fn = this; othis.fn(); delete othis.fn; }
反作用已经消除了,接下来就是参数的问题,这里有个问题是参数个数是不定的,貌似能够使用一个数组来arr保存住arguments里面的参数,而后再执行othis.fn(arr)。可是,这样等于说只给fn传了一个数组参数,并不能达到目的。此时问题转化为咱们如何实现像 othis.fn(arguments[0], arguments[1], arguments[2] ...) 这样的语句呢?
此时能够想起一个不怎么经常使用的方法eval
简单的说就是能够把字符串解析为JavaScript语句来执行。
借助eval,改写Zcall方法:ui
Function.prototype.Zcall = function (othis) { othis.fn = this; let args = []; for(let i = 1, len = arguments.length;i < len;i++) { args.push("arguments[" + i + "]"); } // othis.fn(); eval("othis.fn(" + args + ")"); delete othis.fn; }
其实就是用args把arguments用字符串的方式保存住,而后在eval方法中再把字符串从新解析为语句。this
同理来实现apply:spa
Function.prototype.Zapply = function (othis) { othis.fn = this; let argsArr = arguments[1]; if (!arguments[1]) { let args = []; for(let i = 0, len = arguments[1].length;i < len;i++) { args.push("arguments[1][" + i + "]"); } eval("othis.fn(" + args + ")"); }else{ othis.fn(); } delete othis.fn; }
参考资料:
MDN-eval
MDN-apply
JavaScript深刻之call和apply的模拟实现prototype