网站首页 > 技术文章 正文
今天老K为大家分享两个有关javascript类型转换问题的总结。
1.写出下面表达式的输出内容
([][[]]+[])[+!![]]+([]+{})[!+[]+!![]]
这是一个拆箱转换和装箱转换的问题。如果对js类型转换不熟的话,这道题是很难解答的。现在我们就按照将复杂问题逐步拆分成简单问题的思路来简答。
第一步简化:
以最中间的+为基准将表达式分成两个:
([][[]]+[])[+!![]]
([]+{})[!+[]+!![]]
第二步简化:
将第一个表达式再细化拆分
([][[]]+[])
[+!![]]
将第二个表达式再细化拆分
([]+{})
[!+[]+!![]]
最终简化:
最后我们要细化拆分成优先解决这个表达式的问题
[][[]] //underfined
这个表达式实际是找出一个空数组的未知下标的值,不确定的值输出是underfined。
知道了这个最小问题的返回值,我们就可以通过js的类型转化来求得表达式的值。
([][[]]+[])[+!![]] // 通过转换实际是 "underfined"[1],最终得到字符串"n"
([]+{})[!+[]+!![]] // 通过转换实际是 "[object Object]"[1],最终得到字符串"b"
对于 []+{} 的转换值为什么是"[object Object]",大家会有疑问?我引用《你不知道的 JavaScript(中卷)》第五章P102原文来解释一下:
还有一个坑常被提到(涉及强制类型转换,参见第 4 章):
[] + {}; // "[object Object]"
{} + []; // 0
表面上看 + 运算符根据第一个操作数([] 或 {})的不同会产生不同的结果,实则不然。 第一行代码中,{} 出现在 + 运算符表达式中,因此它被当作一个值(空对象)来处理。第4章讲过 [] 会被强制类型转换为 "",而 {} 会被强制类型转换为 "[object Object]"。但在第二行代码中,{} 被当作一个独立的空代码块(不执行任何操作)。代码块结尾不需要分号,所以这里不存在语法上的问题。最后 + [] 将 [] 显式强制类型转换(参见第 4 章) 为 0。
最终这个表达式的输出值为"nb"。
2.实现一个函数,运算结果可以满足如下预期结果:
add(1)(2) //3
add(1,2,3)(10) //16
add(1)(2)(3)(4)(5) //15
这个题单纯用高阶函数和Array.prototype.reduce()是不能实现结果的。因为我们没有实现同时返回函数的值和函数本身继续调用。
为了同时实现这种效果,我们需要怎么做呢?
先来简单了解下toString这个方法:
Object.prototype.toString()
toString() 方法返回一个表示该对象的字符串。
每个对象都有一个 toString() 方法,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。
这里先记住,toString() 在特定的场合下会自行调用。
看到这里你可能就有解题思路了。
在javascript中,函数也可以看成是一个object对象。如果想同时返回函数的值和函数本身,我们就可以重写函数的toString方法来改变函数的返回值以满足我们的需求。
解题方法:
function add () {
console.log('进入add');
var args = Array.prototype.slice.call(arguments);
var fn = function(){
var arg_fn = Array.prototype.slice.call(arguments);
console.log('调用fn');
return add.apply(null, args.concat(arg_fn));
}
fn.toString = function(){
console.log('调用toString');
return args.reduce(function(a,b){
return a + b;
})
}
return fn;
}
当调用一次add的时候,实际是返回fn这个function,实际也就是返回fn.toString();
add(1);
// 输出如下:
// 进入add
// 调用toString
// 1
当链式调用两次的时候:
add(1)(2);
// 输出如下:
// 进入add
// 调用fn
// 进入add
// 调用toString
// 3
当链式调用三次的时候:
add(1)(2)(3);
// 输出如下:
// 进入add
// 调用fn
// 进入add
// 调用fn
// 进入add
// 调用toString
// 6
可以看到,这里其实有一种循环。只有最后一次调用才真正调用到toString,而之前的操作都是合并参数,递归调用本身,由于最后一次调用返回的是一个fn函数,所以最终调用了函数的fn.toString,并且利用了reduce方法对所有参数求和。
有些文章也谈过改写valueOf也可以实现,但是本人亲自试了一下,没有效果。可能是浏览器版本的问题。这个大家也可以一块研究一下原因。
本文为原创内容,若转载请注明出处,转发感激不尽。
猜你喜欢
- 2024-11-01 Airbnb 开源力作:自动将 JavaScript 代码转换为 TypeScript
- 2024-11-01 JavaScript类型在什么情况下会发生类型自动转换
- 2024-11-01 js如何将接口get参数串转换成post格式输出
- 2024-11-01 【JS 字符转换】fromCharCode和charCodeAt
- 2024-11-01 几个JS开发小技巧,转换(js 开发)
- 2024-11-01 JavaScript将unicode编码转换为中文
- 2024-11-01 每日一题(js篇)通过js做进制转换(js 10进制转2进制)
- 2024-11-01 JavaScript-类型转换 224(javascript)
- 2024-11-01 基于Javascript编写的开源Markdown和HTML相互转换器——showdown
- 2024-11-01 一文读懂js中的隐式类型转换(js隐式调用)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)