valueOf和toString
有一道经典的题目:
var add = function() {___}; console.log(add(3)(4)(5)); // 输出60
题目要求能无限相乘,请补充add函数。
首先很显然,add函数必须返回一个带一个参数的function,不然无法进行后续的连乘操作;其次,乘到最后,没有参数了,add函数直接得把数值返回。其实这类似一个深搜的函数,根据n的值进行递归:
var add = function(n) { if(n === 5) return n; return n * add(n + 1); } console.log(add(3));
第二行相当于没有参数时的判断操作,第四行相当于返回一个带参数的方法。此题的难点是值的累计,如果能设置一个全局变量保存值,将会方便很多,因为没有中间变量,而根据js函数特性又只能返回一个函数,不能返回函数与数字相乘的方式。如果能设置全局变量:
var add = function(n) { ans *= n; return add; } var ans = 1; add(5)(4)(3); console.log(ans);
因为要返回一个函数,又要实现值的累计,又不能外加变量,所以只能将累计的值作为参数传入。
var add = function(a) { var temp = function(b) { return add(a * b); } return temp; }
那么,add(3)(4)(5)在以上代码中是如何运作的?第一步a=3,b=4,运算后变成add(3*4)(5),第二步,a=12,b=5,运算后变成add(3*4*5),第三步a=60传入,temp方法return了,在控制台看到如下:
function (b) { return add(a * b); }
这时就要关注一下function的toString和valueOf方法。重写toString和valueOf方法,就能得到答案。
var add = function(a) { var temp = function(b) { return add(a * b); } temp.toString = temp.valueOf = function() { return a; } return temp; } console.log(add(3)(4)(5));
关于valueOf & toString:
js里除了null外每个对象都有valueOf和toString方法,一般情况下对象会先调用toString方法,然后再调用valueOf。
var bbb = { toString: function() { console.log('toString'); return 10; }, valueOf: function() { console.log('valueOf'); return 10; } } alert(bbb);// 10 toString alert(+bbb); // 10 valueOf alert(''+bbb); // 10 valueOf alert(String(bbb)); // 10 toString alert(Number(bbb)); // 10 valueOf alert(bbb == '10'); // true valueOf alert(bbb === '10'); // false
这是司徒正美的一个例子,他也对结果作出了解释。如果转换为字符串时调用toString方法,如果是转换为数值时则调用valueOf方法,但其中有两个很不和谐,一个是alert(''+bbb),字符串合拼应该是调用toString方法……另一个我们暂时可以理解为===操作符不进行隐式转换,因此不调用它们。为了追究真相,我们需要更严谨的实验。
var aa = { i: 10, toString: function() { console.log('toString'); return this.i; } } alert(aa);// 10 toString alert(+aa); // 10 toString alert(''+aa); // 10 toString alert(String(aa)); // 10 toString alert(Number(aa)); // 10 toString alert(aa == '10'); // true toString
因为aa没重写valueOf方法,在实际运行时,会先优先去寻找其toString方法,而比如alert(+aa)其实是应该优先调用valueOf方法的,但是木有valueOf,所以就退而求其次调用toString了。
var bb = { i: 10, valueOf: function() { console.log('valueOf'); return this.i; } } alert(bb);// [object Object] alert(+bb); // 10 valueOf alert(''+bb); // 10 valueOf alert(String(bb)); // [object Object] alert(Number(bb)); // 10 valueOf alert(bb == '10'); // true valueOf
而以上结果似乎不太和谐,顺着思路,没有toString方法,所以就调用valueOf,但是为何1和4输出的是[object object]。司徒正美说是继承了Object的toString方法,尝试去掉后:
Object.prototype.toString = null; var cc = { i: 10, valueOf: function() { console.log('valueOf'); return this.i; } } alert(cc);// 10 valueOf alert(+cc); // 10 valueOf alert(''+cc); // 10 valueOf alert(String(cc)); // 10 valueOf alert(Number(cc)); // 10 valueOf alert(cc == '10'); // true valueOf
如果只重写了toString,对象转换时会无视valueOf的存在来进行转换。但是,如果只重写了valueOf方法,在要转换为字符串的时候会优先考虑toString方法。在不能调用toString的情况下,只能让valueOf上阵了。对于那个奇怪的字符串拼接问题,可能是出于操作符上,翻开ECMA262-5 发现都有一个getValue操作。嗯,那么谜底应该是揭开了。重写会加大它们调用的优化高,而在有操作符的情况下,valueOf的优先级本来就比toString的高。
valueOf和toString的更多相关文章
- Javascript中的valueOf与toString
基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...
- valueOf和toString的区别
基本上所有的JavaScript数据类型都有valueOf(),toString()方法,null除外,这两个方法解决了JavaScript值运算和显示的问题 valueOf()会把数据类型转换成原始 ...
- Javascript中valueOf与toString区别
前言 基本上,所有JS数据类型都拥有这两个方法,null除外.它们俩解决JavaScript值运算与显示的问题,重写会加大它们调用的优化. 测试分析 先看一例:var aaa = { i: 10, ...
- JavaScript的valueOf和toString
深度好文 http://www.cnblogs.com/coco1s/p/6509141.html 知识要点 不同对象调用valueOf和toString的顺序不一样 高阶函数的使用,替代for循环 ...
- JS类型转换之valueOf和toString详解
最近群里有人发了下面这题: 实现一个函数,运算结果可以满足如下预期结果: add(1)(2)// 3 add(1,2,3)(10)// 16 add(1)(2)(3)(4)(5)// 15 对于一个好 ...
- JavaScript中的valueOf与toString方法
基本上,所有JS数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题. JavaScript 的 valueOf() 方法 valu ...
- 深入理解Javascript中的valueOf与toString
基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...
- valueOf()、toString()
基本上,所有JS数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题. JavaScript 的 valueOf() 方法 valu ...
- String、String.valueOf、toString 它们三者的区别总结
今天在使用这个的时候发现,他们三者好像在某些场所都是可以用的,但是不免会让人想到那既然它们三者这么的相似,那么总有些什么区别吧.我也在网上找了一些资料看.自己也看了API文档,就将他们三的区别总结一下 ...
随机推荐
- Python pass语句作用与用法
Python中的pass语句作用是什么?表示它不做任何事情,一般用做占位语句.pass语句具体作用及使用方法,我们往下看. pass语句在函数中的作用 当你在编写一个程序时,执行语句部分思路还没有完成 ...
- db2 常用命令(二)
1. 打开命令行窗口 #db2cmd 2. 打开控制中心 # db2cmd db2cc 3. 打开命令编辑器 db2cmd db2ce ======脚本文件操作命令======= -- 执行脚本 ...
- A class for global logging
Some time we need to record the logging information in multiple module, however if we use the follow ...
- WCF宿主端检验队列
ServiceHost host = new ServiceHost(typeof(Service1)); if (MessageQueue.Exists(@".\private\MyMes ...
- selenium处理滚动条
1.用js实现 滚动到底部 String js="document.documentElement.scrollTop=10000"滚动到顶部 String js="do ...
- 【温故而知新-Javascript】使用 DOM 元素
1. 使用元素对象 HTMLElement对象提供了一组属性,可以用它们来读取和修改被代表的数据.下表介绍了这些属性. 下面代码展示了如何使用表中所列的一些基本属性. <!DOCTYPE htm ...
- UVA 12730 Skyrk's Bar --期望问题
题意:有n个地方,现在要站人进去,而每两个人之间至少要隔k个空地,问这n个地方能站的人数的期望是多少. 分析:考虑dp[i]表示 i 个地方能站的期望数,从左往右推, 如果i-k-1<1,那么最 ...
- 第16章 Windows线程栈
16.1 线程栈及工作原理 (1)线程栈简介 ①系统在创建线程时,会为线程预订一块地址空间(即每个线程私有的栈空间),并调拨一些物理存储器.默认情况下,预订1MB的地址空间并调拨两个页面的存储器. ② ...
- NGUI3.x Button事件
代码调用事件 UI搭建 1.首先创建一个Button,和一个的GameObeject命名为GUIClikEvent 2.方法一:创建一个NGUIClickTest.cs,绑定在Button上 Clic ...
- Linux搭建python环境
环境: CentOS 6.4 前言:CentOS 6.4系统自带的有python2.6.6版本 一.下载文件 python官网:https://www.python.org/downloads/ 版本 ...