JS大数相加

记得之前看到过一个JS超大正整数相加的题目,今天想了下自己会怎么实现,于是便进行了尝试,代码如下:

function  bigAdd(a, b){
	    let  lenA = a.length,
			 lenB = b.length,
			 curry = 0,
			 res = [];
		let loopLen = Math.max(lenA, lenB );

		for(let i = 0 ; i < loopLen ; i++){
			const indexA = ( lenA - i - 1 ) > -1 ? lenA - i -1 : -1;
			const indexB = ( lenB - i - 1) > -1 ? lenB - i -1 : -1;

			const valA = indexA > -1 ? a[ indexA ] : 0 ;
			const valB = indexB > -1 ? b[ indexB ] : 0 ;

			res[i] = (  Number(valA) + Number(valB)  + curry) % 10;
			curry = Math.floor( ( Number(valA) + Number(valB)  + curry ) / 10 );
		}	
		return res.reverse().join('');
	}

想法很简单,就是按照加法的规律,从末尾开始一项一项的相加。
然后看了网上关于该题目的算法,真是惊叹别人算法的简洁以及对于JS中类型转换相关知识的巧妙应用。

	function addBig(a, b){
		let temp = 0,
			res = '';
		a = a.split('');
		b = b.split('');
		while( a.lenght || b.length || temp){
			temp += ~~a.pop() + ~~b.pop();
			res = (temp % 10 ) + res;
			temp = temp > 9;
		}
		return res.replace(/^0+/g, '');
	}

首先,这个代码给人的感觉真的很精简。但是其中其实隐藏了很多关于JS 中类型转换的相关知识, 下面我们来一一分析。
1.为什么将a,b转换为数组
转换为数组的目的是为了在while循环体中使用 pop方法来获取数组中的最后一项。如果你不转换为数组,我们能想到的获取字符串的最后一项的方法是sutstr(-1,1)。但是这种方法只能获取最后一项,无法动态的改变字符串本身。
2. 为什么while的判断条件是 a.lenght || b.length || temp而不是a || b || temp
因为循环体中每次的循环会使数组长度减少1,当数组为空时,假设极端的条件下 a, b都为[],但是这个时候 [] || [] || 0 的结果是 true, 循环永不结束。只因为Boolean([]) = true
3. 为什么使用~~a.pop(),如果只是 为了将值转换为数字 ,为何不使用Number进行强制转换不是更加易懂?
这个就十分精髓了,首先使用~操作符进行取反是会将字符串转换为数字的,在进行一个取反操作,就转换为了字符串本身代表的数字,但不仅如此。考虑下我们数组循环的最后为空时,[].pop()的结果为undefined, 而 Number(undefined)的结果为NaN~NaN的结果为-1~~NaN的结果 为0,当你使用NaN进行加法运算时,一切结果都没有了意义。所以这个地方必须为~~a.pop(), 而不能使用Number进行强制转换。
4. 为什么temp = temp > 9,这是什么鬼?
这一点其实也是用了JS中的隐式转换,我们换个写法你就明白了temp = temp > 9 ? 1 : 0temp实际上表示的是进位的结果,在循环的开始我们使用temp += ~~a.pop() + ~~b.pop();进行temp的再赋值,实际等价于temp = (true | false) + Number。 而Boolean在进行数字运算时,true会转换为1,false会转换为0,此处巧妙的应用了该隐式转换。

一个小小的算法,其中隐含了这么多的基础知识,所以还是需要夯实基础啊!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章