一道面试题引发的对JavaScript类型转换的思考

发表于:2017-3-10 09:41

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:ChokCoco    来源:51Testing软件测试网采编

分享:
  可以看到,这里把我们定义的 test 函数的重新打印了一遍,其实,这里自行调用了函数的 valueOf 方法:
  我们改写一下 test 函数的 valueOf 方法。
  test.valueOf = function() {
  console.log('调用 valueOf 方法');
  return 2;
  }
  test;
  // 输出如下:
  // 调用 valueOf 方法
  // 2
  与 Number 转换类似,如果函数的 valueOf 方法返回的不是一个原始类型,会继续找到它的 toString 方法:
  test.valueOf = function() {
  console.log('调用 valueOf 方法');
  return {};
  }
  test.toString= function() {
  console.log('调用 toString 方法');
  return 3;
  }
  test;
  // 输出如下:
  // 调用 valueOf 方法
  // 调用 toString 方法
  // 3
  破题
  再看回我正文开头那题的答案,正是运用了函数会自行调用 valueOf 方法这个技巧,并改写了该方法。我们稍作改变,变形如下:
functionadd(){
console.log('进入add');
varargs=Array.prototype.slice.call(arguments);
varfn=function(){
vararg_fn=Array.prototype.slice.call(arguments);
console.log('调用fn');
returnadd.apply(null,args.concat(arg_fn));
}
fn.valueOf=function(){
console.log('调用valueOf');
returnargs.reduce(function(a,b){
returna+b;
})
}
returnfn;
}
  当调用一次 add 的时候,实际是是返回 fn 这个 function,实际是也就是返回 fn.valueOf();
  add(1);
  // 输出如下:
  // 进入add
  // 调用valueOf
  // 1
  其实也就是相当于:
  [1].reduce(function(a, b) {
  return a + b;
  })
  // 1
  当链式调用两次的时候:
  add(1)(2);
  // 输出如下:
  // 进入add
  // 调用fn
  // 进入add
  // 调用valueOf
  // 3
  当链式调用三次的时候:
  add(1)(2)(3);
  // 输出如下:
  // 进入add
  // 调用fn
  // 进入add
  // 调用fn
  // 进入add
  // 调用valueOf
  // 6
  可以看到,这里其实有一种循环。只有最后一次调用才真正调用到 valueOf,而之前的操作都是合并参数,递归调用本身,由于最后一次调用返回的是一个 fn 函数,所以最终调用了函数的 fn.valueOf,并且利用了 reduce 方法对所有参数求和。
  除了改写 valueOf 方法,也可以改写 toString 方法,所以,如果你喜欢,下面这样也可以:
function add () {
var args = Array.prototype.slice.call(arguments);
var fn = function () {
var arg_fn = Array.prototype.slice.call(arguments);
return add.apply(null, args.concat(arg_fn));
}
fn.toString = function() {
return args.reduce(function(a, b) {
return a + b;
})
}
return fn;
}
  这里有个规律,如果只改写 valueOf() 或是 toString() 其中一个,会优先调用被改写了的方法,而如果两个同时改写,则会像 Number 类型转换规则一样,优先查询 valueOf() 方法,在 valueOf() 方法返回的是非原始类型的情况下再查询 toString() 方法。
  后记
  像阮一峰老师所说的,“炫耀从来不是我写作的动机,好奇才是”。本文行文过程也是我自己学习的一个过程,过程中我也遇到了很多困惑,所以即便查阅了官方文档及大量的文章,但是错误及疏漏仍然在所难免,欢迎指正及给出更好的方法。
  对于类型转换,最好还是看看 ECMAScript 规范,拒绝成为伸手党,自己多尝试。另外评论处有很多人提出了自己的疑问,值得一看。
22/2<12
重磅发布,2022软件测试行业现状调查报告~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2023
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号