先从一个小问题说起:
请你设计一个方法,用来将多维数组拍平。比如[1,2,3,[4,5,[6,7,8]]] ==> [1,2,3,4,5,6,7,8]
看到这,估计很多人开始考虑各种迭代,各种遍历之类的方法了,诚然,通过遍历可以实现,然而这种实现方法既不优雅,也太麻烦。今天看一个简单的方法:
function flat(arr) { return (arr + '').split(',').map(function(e,i) { return +e; }); } flat([1,2,3,[4,5,[6,7,8]]]); // [1,2,3,4,5,6,7,8]
恩,代码的确很短,但今天不是为代码太短而高兴的,我们要弄清楚到底发生了什么。
今天要探讨的点在这里:
arr + ''
一个数组 + 一个空字符串,这到底是什么呢?
众所周知,arr是一个对象,我们直接打印一个对象,会发生什么呢?
看下面一段代码:
var test = { a : 'A', b : 'B' }; alert(test); //[object Object]
我们看到,对象以一种奇怪的方式被打印出来了。那么对象为什么会以这种格式打印呢,我们如果想控制打印样式该怎么办呢?继续往下看
Object.prototype.toString = function(){ return "本来该打印对象的,结果打印出了我"; } var test = { a : 'A', b : 'B' }; alert(test); //本来该打印对象的,结果打印出了我
看到这里就应该明白了,我们打印对象时,实际上调用了Object.prototype对象的toString方法,因为所有的对象的原型链顶端都是Object.prototype,即任何对象都可以使用toString方法,所以,我们可以打印任何对象。
Object.prototype.toString默认使用[object ***]的方式打印对象,具体的打印结果如下:
var toString = Object.prototype.toString(); alert(toString.call(1)); // [object Number] alert(toString.call('1')); // [object String] alert(toString.call(new Date())); // [object Date] alert(toString.call(new RegExp())) // [object RegExp] alert(toString.call(true)); // [object Boolean] alert(toString.call([])); // [object Array] alert(toString.call({})); // [object Object] alert(toString.call(null)); // [object Null] alert(toString.call(undefined)); // [object Undefined]
这种方法可以准确的判断一个数据的类型,当typeof无法精确判断时可以采用这种方法判断;
另外,我们看到,这里toString是通过call来调用的,为什么呢?
因为有些对象复写了toString方法!
还是看代码:
alert(["ni","hao","world"].toString()); //"ni,hao,world" 已重写 Array会对每一个元素调用toString方法然后再调用join方法,最终返回一个字符串 alert((22).toString()) // 22 已重写 Number.toString([radix]) radix代表进制,从2到36 alert((function(){}).toString()); //function(){} 已重写 返回一个表示当前函数源代码的字符串 alert((true).toString()) //true 已重写 返回一个指定布尔对象的字符串形式 alert((new RegExp('a+b+c')).toString()) // /a+b+c/ 已重写 返回一个表示该正则表达式的字符串 alert((new Date()).toString()) //Mon Jul 18 2016 18:59:06 GMT+0800 (CST) 已重写 返回一个字符串,表示该Date对象
说了这么多,现在回头看看 arr + '',这就一目了然了,arr + ''会主动调用toString方法,将该数组转成一个由元素组成的字符串
好了,说了这么多,toString能说的基本上也说过了,如果还有什么遗漏,后期再补上