[CodeWars][JS]实现链式加法
在知乎上看到这样一个问题:http://www.zhihu.com/question/31805304;
简单地说就是实现这样一个add函数:
add(x1)(x2)(x3)...(xn) == x1 + x2 + x3 + ... + xn // true;
正好发现在codewars上也有这道题,那不妨一块刷了吧。
Kata Description
level:5 kyu
We want to create a function that will add numbers together when called in succession.
add(1)(2);
// returns 3
We also want to be able to continue to add numbers to our chain.
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10
add(1)(2)(3)(4)(5); // 15
and so on...
Test cases:
Test.expect(add(1) == 1);
Test.expect(add(1)(2) == 3);
Test.expect(add(1)(2)(3) == 6);
Solution
首先,第一个示例似乎表示add(1)(2)应该返回数字3,但如此一来add(1)(2)(3)岂不是将函数调用应用在了一个数字上面?
我们再来看这道题提供的Test Cases, 注意cases里使用的是'=='而不是'===',也就是说返回值不需要是一个数字,只需要是一个能进行类型转换以变成数字的‘值’就可以了。而这道题中,因为add可以连续调用,所以这个‘值’应该是一个函数。
那么我们要解决的第一个问题: 怎样能使得函数转化为数字?
问题一 怎样将函数与数字联系起来
1.valueOf() 方法。
顾名思义,这个方法返回的是调用这个对象的‘值’。
默认情况下一个函数调用valueOf()方法,返回值是函数本身
var fn = function(num){return ++num;};
fn(1); //
(fn.valueOf())(1); //
然而这并没有什么卵用。
在这个题目里,我们需要重写这个方法:
var fn = function () {};
fn.valueOf = function(){ return 233;};
console.log(fn==233); // true
console.log(fn===233); //false
以上我们可以发现,当 == 对函数对象进行类型转化的时候,会读取函数的valueOf的返回值,这样就达到了我们的目的。
实际上Function本身并没有valueOf方法,该方法继承自Object.prototype.valueOf();
也就是说,不仅仅是函数,当我们需要对任何对象与数字进行比较的时候,都能够使用这个方法。
var o = {};
o.valueOf = function(){return 233;};
console.log(o == 233) // true
console.log(o === 233) // false
另外,与Function不同,Number,String这些对象,都有着自己的valueOf方法,而非继承于Object。
所以我们可以猜测,==符进行类型转化的时候,可能都是先读取对象的valueOf的返回值进行比较。
2. toString()方法。
除了用上面的valueOf方法以外,toString也可以达到同样的目的。
var fn = new Function;
fn.toString = function() { return 233;};
console.log(fn==233); // true
console.log(fn===233); //false
和valueOf不同的是,Function中的toString并非继承自Object,它使用的是自己的toString方法。
对于函数而言,toString的返回值就像是调用函数的‘名字’。修改了toString, 就好像给函数换了个‘称号’:
var fn = function(){};
console.log(fn); // function()
var fn2 = function(){};
fn2.toString = function(){return 233;};
console.log(fn2) //
默认调用toString返回的值是该函数的字符串形式,就像对这段代码进行了反编译。
var fn = function(){
//Can you see me?
//Oh..
return 233;
};
var fnStr = fn.toString();
console.log(fnStr);
输出
'function (){
//Can you see me?
//Oh..
return 233;
}'
嗯没错连函数里的注释,换行,空格什么的都包括进来了。
另外MDN的文档说toString()还可以接受一个缩进的参数,不过我试了试好像没有什么用。
3. toString() 与 valueOf()
既然上面两种方法都可以,那么在这个题目里,如果同时使用了这两种方法,那种的优先级更高呢?
这个简单,我们来试一试:
var fn = function(){};
fn.toString = function(){return 'toString wins';};
fn.valueOf = function() {return 'valueOf wins';}
fn == 'toString wins'; // false
fn == 'valueOf wins'; // true
看来是valueOf()等级更高啊。
也就是说,使用==符对对象与普通数据进行比较的时候,先读取对象的‘value’,如果value不是普通数据类型,再读取‘string’,如果还不是,那就输出false。当然,在读取过程中,如果读取到了普通数据类型并且判断为不等,那就直接输出fasle,不会进行下一步的比较。
问题二 然后呢
上面的问题解决后这个题也就解决得差不多了。
首先我们的add函数应该返回一个函数,并且我们需要对这个函数的valueOf(或者toString)进行重写:
var add=function(num){
var inner = function(){};
inner.valueOf=function(){};
return inner;
};
然后用一个temp变量来存储累加的结果吧,temp同时也应该是内部函数的valueOf的返回值:
var add=function(num){
var temp = num;
var inner = function(num2){};
inner.valueOf=function(){
return temp;
};
return inner;
};
最后补全内部函数的主体部分,因为这个函数要能够不停地被调用,所以inner函数的返回值应该是它本身:
var add=function(num){
var temp = num;
var inner = function(num2){
temp+=num2;
return inner;
};
inner.valueOf=function(){
return temp;
};
return inner;
};
到此大功告成,submit, pass!
到这里这道题告一段落,不过呢我发现上面的解决方案里完美的解决方案还有一定距离,在我提交代码并看了排名靠前的代码后……
比如temp这个变量是必须的吗?
代码里出现了两次 return inner;是不是有些冗余的感觉呢?
……
[CodeWars][JS]实现链式加法的更多相关文章
- objective-c 一个链式加法计算器实现
一个链式加法计算器实现思路 1.使用时的效果 Calculate * manger=[Calculate new]; int result=manger.add(123).add(123).sub(1 ...
- js实现链式操作
前言:前不久阿里远程面试时问了我一个问题,如下: function Person(){}; var person = new Person(); //实现person.set(10).get()返回2 ...
- 玩一把JS的链式调用
链式调用我们平常用到很多,比如jQuery中的$(ele).show().find(child).hide(),再比如angularjs中的$http.get(url).success(fn_s).e ...
- js动画--链式运动
前面几节我们只是讲述了一种运动,这节课我将讲述链式运动:就以一个动作接着一个动作完成. 对于这个实现,我们只需要改变一下就可以实现了,设置一个回调函数. var timer; window.onloa ...
- [CodeWars][JS]实现大整数加法
问题描述 实现‘字符串加法’,即将两个以字符串形式表示的数字相加,得到结果然后返回一个新的字符串. 例如:输入‘123’,‘321’,返回‘444’. 这样在进行两个任意大的整数相加的时候,既不会溢出 ...
- JS实现链式调用 a().b().c()
function a() { this.b = function () { console.log('111') return this } this.c = function () { consol ...
- 文件上传以及JS链式结构
文件上传: 文件上传使用FileUpload控件,使用控件的SaveAs方法,需要绝对路径. 获取文件的绝对路径:Server.MapPath(相对路径); 或许要上传文件的本身名字用.FileNam ...
- 谈谈 Objective-C 链式语法的实现
引言 对于 Objective-C 的语法,喜欢的人会觉得它是如此的优雅,代码可读性强,接近自然语言,开发者在调用大多数方法时不需要去查看注释或文档,通常只凭借方法名就可以大致知道这个方法的作用,可以 ...
- 如何写 JS 的链式调用 ---》JS 设计模式《----方法的链式调用
1.以$ 函数为例.通常返回一个HTML元素或一个元素集合. 代码如下: function $(){ var elements = []; ;i<arguments.length;i++){ v ...
随机推荐
- Android 在线订单倒计时设计
接到一个需求,用户下单后,商店这边需要显示在线订单列表,订单十分钟内有效.于是需要设计倒计时,显示每个订单剩余处理时间. 倒计时剩余时间: 订单创建时间 + 10分钟 - 系统当 ...
- 冰冻三尺非一日之寒--js dom
1. 写页面是觉得丑 float,clear:both,margin,padding position: left: 网 ...
- linux下查看最消耗CPU、内存的进程
2012-11-19 15:38:04 分类: LINUX 1.CPU占用最多的前10个进程: ps auxw|head -1;ps auxw|sort -rn -k3|head -10 2.内存消耗 ...
- spring boot整合shiro出现UnavailableSecurityManagerException
spring boot自带spring security,spring security自然不用说是一个强大的安全框架,但是用惯了shiro,一时半会用不来spring security,所以要在sp ...
- Frameset框架
总结一下.通过使用Frameset框架,可以在同一个浏览器窗口中显示不止一个页面. 先举个例子: <frameset rows="> <frame src="to ...
- C# Winform防止一个程序重复运行
1: //在写一些服务型的软件的时候,你可能不希望一个操作系统里有两个副本在运行,这样也许会扰乱你的操作.这时,你就需要限制程序的副本.下面的这个方法,很简单的就可以实现上述功能. using Sys ...
- 【原创】自己动手写工具----签到器[Beta 2.0]
一.前面的话 上一篇中基本实现了简单的签到任务,但是不够灵活.在上一篇自己动手写工具----签到器的结尾中,我设想了几个新增功能来提高工具的灵活程度,下面把新增功能点列出来看看: (1)新增其他的进程 ...
- 【原】聊聊js代码异常监控
在平时的工作,js报错是比较常见的一个情景,尤其是有一些错误可能我们在本地测试的时候测试不出来,当发布到线上之后才可以发现,如果抢救及时,那还好,假如很晚才发 现,那就可能造成很大的损失了.如果我们前 ...
- PHP中explode和implode的区别
字符串的连接与分割是非常重要的两个内容,通过其可以将数组按照指定的规则转换成字符串,也可以将字符串按照指定的规则进行分割,返回一个数组.其应用范围很广,如在购物网站的购物车,在线投票系统等.这两项技术 ...
- jvascript 顺序查找和二分查找法
第一种:顺序查找法 中心思想:和数组中的值逐个比对! /* * 参数说明: * array:传入数组 * findVal:传入需要查找的数 */ function Orderseach(array,f ...