资讯专栏INFORMATION COLUMN

一道JavaScript编程题的拓展

lemanli / 1976人阅读

摘要:背景在下前端小白,近日在刷各种算法编程题,今天碰到一编程题,考点是,虽说简单,但在解题时发现了一个挺有意思的东东,特来分享一下。分析及结论如下原理其实很简单,其实就是一个函数,将视为一个整体,记作。

背景

在下前端小白,近日在刷各种算法/编程题,今天碰到一编程题,考点是apply,虽说简单,但在解题时发现了一个挺有意思的东东,特来分享一下。欢迎各位大佬指点~

正文

话不多说,直接上题目:二次封装函数。

已知函数 fn 执行需要 3 个参数。请实现函数 partial,调用之后满足如下条件:
1、返回一个函数 result,该函数接受一个参数
2、执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致

哈哈,这题简单!稍微学过js的朋友就能写出来:

function partial(fn,str1,str2) {
    var result = function(str3) {
        return fn(str1,str2,str3);
    }
    return result;
}

这里用个call可能会显得有点逼格(笑),当然apply,bind也能达到一样的效果。

function partial(fn,str1,str2) {
    var result = function(str3) {
        return fn.call(null,str1,str2,str3);
    }
    return result;
}

不多停留,我们来看下一题,同样是二次封装函数:

实现函数 partialUsingArguments,调用之后满足如下条件:
1、返回一个函数 result
2、调用 result 之后,返回的结果与调用函数 fn 的结果一致
3、fn 的调用参数为 partialUsingArguments 的第一个参数之后的全部参数以及 result 的调用参数

emmmmm,传入的参数不固定? 有了! 用arguments~

function partialUsingArguments(fn) {
  var _arguments = Array.prototype.slice.call(arguments,1)
  var result = function() {
    var newArguments = _arguments.concat(Array.prototype.slice.call(arguments,0));
    return fn.apply(null,newArguments)
  }
  return result;
}

唔,好像也没什么难的,_arguments就是partialUsingArguments第一个参数后的所有参数组成的数组,将它和result的所有参数合并起来,利用apply传入fn,ok~解决了!

诶诶?有意思的东西呢?这特么一点意思都没啊。
说出来你们可能不信,其实我看到这题的时候,虽然我想到了用apply,但我并没有想到fn.apply(null,newArguments)。那我想到的是什么呢?

Function.prototype.call.apply

什么鬼?我也不知道是在哪看过这东西(也许没看过),又好像是

Function.prototype.call.call

还是

Function.prototype.apply.apply

还是

Function.prototype.apply.call

好像都差不多,妈个鸡,试试就知道了!

return Function.prototype.call.apply(fn,newArguments)
浏览器一跑,好像对了?不对!我传入的第一个参数怎么不见了?
Google之~ 噢~ 原来第一个参数被吃了。
原来Function.prototype.call.apply(fn,newArguments)同等于fn.call(a,b,c,...z) // newArguments = [a,b,c,...z],这里的...z不是ES6中的...rest哦,只是表示省略了中间的参数。

知道了原理(并不知道),那就好办了,我给newArguments数组的头部补一个元素上去不就好了~

newArguments.unshift(0);
Function.prototype.call.apply(fn,newArguments)

浏览器一跑——没毛病老铁!

完了吗?

并没有!

既然.call.apply可以用,那其他3个按理来说也能用,况且这里多了一步对数组的操作,能不能更优雅一点呢?(另外3个怎么用,观众老爷们心里有答案吗?)
本着 求知 以及 code less,do more 的精神,我对剩下的3种组合进行了深♂入的研究。

分析及结论如下

原理其实很简单,Function.prototype.apply(call)其实就是一个函数,将视为一个整体,记作A。原式就可以转换成:A.apply(参数)A.call(参数),然后进一步转换,参数1.A(参数2),什么参数、参数1、参数2的?
相信大家也看出来了,这里唯一的难点(?)就是参数。参数怎么写呢?

其实很简单,apply就传数组,call就传一个序列。

applycall的区别大家肯定知道,我就不多说了。第一个参数肯定是fn,这个没跑了。关键就在第二个参数上。

第二个参数,首先它形式上要看后一个apply/call,如果是apply,我们就传数组进去,如果是call,就传一个序列。然后它的内容就要看A了,也就是前一个apply/call,同理,如果是apply,就传数组参数,如果是call,就传序列参数

所以我们可以得出以下结果:

Function.prototype.apply.apply(fn,[null,newArguments])
Function.prototype.call.call(fn,null,...newArguments])
Function.prototype.apply.call(fn,null,newArguments])
//上面3式可以实际上等于
fn.apply(null,newArguments)
fn.call(null,...newArguments) //...为扩展运算符,...[arr] = arr[0],arr[1],...arr[n]
fn.apply(null,newArguments)

绕了一大圈,又回来了~ :)
而上面的Function.prototype.call.apply也可以改写成:

    Function.prototype.call.apply(fn,[null,...newArguments])

从而减少了对数组newArguments的操作。

写在最后

第一次写文章(水贴),十分紧张,删了改,改完了删,总觉得写的不好、十分啰嗦。
可能会有人觉得毫无意义,但我觉得这个倒是可以作为一道面试题。

请在填写空白内容使等式成立:
fn.apply(null,args) = Function.prototype.apply.apply(_____)

如果真的有人遇到,请回来点赞^ ^
也希望此文能多少帮助到前端新人,大家一起学习,进步!
哪里要是写不好可以直说!帮助我进步。谢谢!
不废话了,
完。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84119.html

相关文章

  • 用程序消除一道概率题的二义性

    摘要:以下是对史密斯先生有两个孩子的可能情况进行描述,其中函数随机返回或的概率均为用于模拟现实中生男孩女孩的概率各一半。   无意在维基看到了一个关于概率悖论的讨论Boy or Girl paradox。有争议的的题目如下:  史密斯先生有两个孩子,至少其中之一是男孩,请问两个孩子都是男孩的可能性有多大?  原文如下:  Mr. Smith has two children. At leas...

    JackJiang 评论0 收藏0
  • 用程序消除一道概率题的二义性

    摘要:以下是对史密斯先生有两个孩子的可能情况进行描述,其中函数随机返回或的概率均为用于模拟现实中生男孩女孩的概率各一半。   无意在维基看到了一个关于概率悖论的讨论Boy or Girl paradox。有争议的的题目如下:  史密斯先生有两个孩子,至少其中之一是男孩,请问两个孩子都是男孩的可能性有多大?  原文如下:  Mr. Smith has two children. At leas...

    littlelightss 评论0 收藏0
  • 阮一峰老师微博上的关于js作用域的一道

    摘要:补充我弄明白了上面的问题,重点在于函数的作用域,函数中定义的变量之前我说没用,为什么没用是因为函数是定义在函数下的,所以的作用域链是这样的因为函数是这样定义的,所以函数定义了变量,所以中的赋值给了函数的参数。 在阮一峰老师的微博上看到这样一道题: javascriptfunction a(x, y) { y = function(){ x = 2; }...

    DTeam 评论0 收藏0
  • 一道面试题谈谈函数柯里化(Currying)

    摘要:忍者秘籍一书中,对于柯里化的定义如下在一个函数中首先填充几个参数然后再返回一个新函数的技术称为柯里化。回到我们的题目本身,其实根据测试用例我们可以发现,函数的要求就是接受单一函数,例如但是与柯里化不同之处在于,柯里化返回的一个新函数。   欢迎大家再一次来到我的文章专栏:从面试题中我们能学到什么,各位同行小伙伴是否已经开始了悠闲的春节假期呢?在这里提前祝大家鸡年大吉吧~哈哈,之前有人说...

    cppprimer 评论0 收藏0
  • 链式调用与事件循环--一道JavaScript面试题的思考

    摘要:最后画几张粗糙的图,简单描述一下这个执行的过程因为是链式调用,所以在链上的都会入栈然后执行,额,执行栈少画了和。。。 前言:昨天在群里讨(jin)论(chui)技(niu)术(pi),有位老铁发了一道他面的某公司面试题,顺手保存了。今早花了一点时间把这题做了出来,发现挺有意思的,决定在今天认真工(hua)作(shui)前,与大家分享我的解题方案和思考过程。 题目如下(可以自己先思考一会...

    wow_worktile 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<