告诉我写好JavaScript的四大技巧——妙用特性"/>
【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性
文章目录
- 起步
- 案例1:判断4的幂
- 菜鸟版
- 菜鸟学废版
- 进阶版
- JS特性技巧版
- 案例2:深拷贝
- 平平无奇普通版
- JS特性技巧版
- 案例3:归并排序
- 《算法(第四版)》Java直译版
- JS特性技巧版
- 一些小技巧
- 转进制
- 交换元素
- 总结
- 更多相关博文
如何写好JavaScript是每一个前端工程师一直以来在思考的问题,月影老师告诉我们一些写好JavaScript的原则,同时也教了一些我们如何写好JavaScript的技巧,今天来继续跟着月影老师学JavaScript吧~~
起步
我们平时在刷题或者网上找资料的时候,得到的很多答案可能都不是用JavaScript实现的,我们就直接照搬翻译成JavaScript过来了,其实JavaScript有很多自己的特性,用的好的话直接起飞~
话不多说,我们来看案例
案例1:判断4的幂
菜鸟版
这题拿到太简单了,直接循环除以4最后能除尽就是啦
① 负数直接返回 false
② 对n进行循环除以4的遍历,只要有一次不能被4整除,就返 false
③ 否则返回 true
var isPowerOfFour = function(n) {if( n < 1) return false while(n > 1){if(n % 4) return falsen /= 4}return true
};
看看LeetCode上执行的结果
还不错,够用了~
菜鸟学废版
我们使用位运算来提高效率啊
一个数x模4就相当于 x 的二进制形式 与 二进制数 11
也就是十进制的 3 按位相与,(与运算是两个数都为1结果才为1,否则结果都是0)因为11
前面都是0
,所以x的二进制形式最后只剩最后两位,最后两位 与 11
做与运算,结果还是自身(x的二进制形式的最后两位),所以 n % 4
和 n & 3
是一样的;
一个数除以4,相当于把他的二进制形式向右移动2位(向右移动一位相当于除以2),所以 n / 4
和 n >>> 2
是一样的
var isPowerOfFour = function(n) {if( n < 1) return false while(n > 1){if(n & 3) return falsen >>>= 2}return true
};
看看LeetCode上执行的结果
进阶版
4的幂的前提是必须是2的幂,2的幂的前提必须是非负数
我们这里有三个判断,全部符合才是true
function isPowerOfFour(n) { return n > 0 && (n & (n - 1)) === 0 && (n & 0xAAAAAAAA) === 0;
}
① n > 0
—— > 必须是非负数
② (n & (n - 1)) === 0
——> 必须是2的幂
n & (n - 1)
之前我们说过这样操作可以将 n 二进制表示的最低位 1 移除
我们再来看看2的幂数的二进制表示
1 0000 0001
2 0000 0010
4 0000 0100
8 0000 1000
16 0001 0000
32 0100 0000
64 1000 0000
所以满足 (n & (n - 1)) === 0
的数 都是 2 的幂
【注意】这里位元算外面的括号,由于位运算的优先级比较低,所以这个括号是不可省略的
③ (n & 0xAAAAAAAA) === 0
——> 在2的幂的基础上必须是4的幂
0xAAAAAAAA
也就是0b1010101010101010
,它的所有偶数二进制位都是 0,所有奇数二进制位都是 1。
这样一来,我们将 n 和 0xAAAAAAAA
进行按位与运算,如果结果为 0,说明 n 二进制表示中的 1 出现在偶数的位置,这样就排除了 2, 8, 32 之类的是2的幂不是4的幂的数字。
看看LeetCode上执行的结果
效率不咋地啊
不过多测几次还不一样
JS特性技巧版
都做到位运算了,为什么不更深层次的看看4的幂的数的二进制的特点呢?
1 0000 0001
4 0000 0100
16 0001 0000
64 0100 0000
4的幂的二进制都是1开头,后面偶数个零这样的形式
我们将n转换成2进制,然后 用 正则匹配结果作为返回值即可
function isPowerOfFour(n) { n = n.toString(2) return /^1(?:00)*$/.test(n)
}
看看LeetCode上执行的结果
还可以的样子啊~
案例2:深拷贝
平平无奇普通版
function deepClone(obj){if (typeof obj !== 'object' || obj === null){return obj}let result = Array.isArray(obj) ? []: {}for (let key in obj) {if(obj.hasOwnProperty(key)) {result[key] = deepClone(obj[key])}}return result
}
JS特性技巧版
我们用JSON这个API就很简单啦
function deepClone1(target) {// 通过数据创建JSON格式的字符串let str = JSON.stringify(target);// 将 JSON 字符串创建为JS数据let data = JSON.parse(str);return data;
}
写成一行就是这样啦~
function deepClone1(target) {return JSON.parse(JSON.stringify(target));
}
案例3:归并排序
《算法(第四版)》Java直译版
在《算法(第四版)》中关于归并排序的代码从Java翻译成JavaScript就是这样
/*** 排序数组* @param {number[]} nums* @return {number[]}*/
var sortArray = function (nums) {const N = nums.length;let temp = new Array();mergeSort(nums, 0, N - 1, temp);return nums;
};/*** 归并排序 采用自顶向下的递归方法* @param {number[]} nums* @param {number} left* @param {number} right* @param {number[]} temp* @returns*/
var mergeSort = function (nums, left, right, temp) {// 如果指针重叠了就返回if (left >= right) {return;}// let mid = Math.floor(left + (right - left) / 2);let mid = (left + right) >> 1;// 递归调用mergeSortmergeSort(nums, left, mid, temp);mergeSort(nums, mid + 1, right, temp);// 归并两个有序数组merge(nums, left, mid, right, temp);
};/*** 归并两个有序数组* @param {number[]} nums* @param {number} left* @param {number} mid* @param {number} right* @param {number[]} temp*/
var merge = function (nums, left, mid, right, temp) {// 将nums复制到temp中去for (let k = left; k <= right; k++) {temp[k] = nums[k];}// 给两个数组分别定义一个指针let i = left;let j = mid + 1;// 将temp中的元素按规则写回numsfor (let k = left; k <= right; k++) {if (i > mid) {// 左半边取尽,取右半边元素nums[k] = temp[j];j++;} else if (j > right) {// 右半边取尽,取左半边元素,左指针右移nums[k] = temp[i];i++;} else if (temp[i] <= temp[j]) {// 谁小就取谁 ,左边小nums[k] = temp[i];i++;} else {// 右边小nums[k] = temp[j];j++;}}
};
其实在JavaScript数组有很多自带的方法,使得我们的数组可以直接当作队列或者栈才操作,用起来很方便
JS特性技巧版
使用JavaScript中数组的一些方法,使得归并排序实现起来异常简单,不用涉及过多的指针问题
更多内容我在之前的博文中有所介绍【算法】经典排序算法总结-JavaScript描述-图解-复杂度分析-插入-快速-归并-堆排序等
/*** 归并排序算法* @param {*} arr 数组* @returns 有序数组*/
function mergeSort(arr) {// 采用自顶向下的递归方法const N = arr.length;if (N < 2) {// 递归出口,数组只有一个元素,直接返回这个数组return arr;}// x >> 1 是位运算中的右移运算,表示右移一位,等同于 x 除以 2 再取整,即 x >> 1 === Math.floor(x / 2)// N >> 1 和 Math.floor(N / 2) 等价let middle = N >> 1;// 拆分为两个子数组let left = arr.slice(0, middle);let right = arr.slice(middle);// 递归调用mergeSortreturn merge(mergeSort(left), mergeSort(right));
}/*** 对两个有序数组进行合并操作* @param {*} left left数组* @param {*} right right数组* @returns 一个有序数组temp*/
function merge(left, right) {// 临时数组存储归并后的数据const temp = [];// 两个数组都还没有遍历结束while (left.length && right.length) {// 注意: 判断的条件是小于或等于,如果只是小于,那么排序将不稳定.if (left[0] <= right[0]) {// left[0]小,删除left数组中第一项left[0],并将它放入temp数组中temp.push(left.shift());} else {// 删除right数组中第一项,并将它放入temp数组中temp.push(right.shift());}}// left数组还有元素,right数组遍历完了while (left.length) {// 将left数组剩下的元素都放入temp数组中temp.push(left.shift());}// right数组还有元素,left数组遍历完了while (right.length) {temp.push(right.shift());}// 返回排序好的数组return temp;
}
一些小技巧
转进制
将十进制数转换成各种进制
124.toString(12)
交换元素
let a = 1, b = 2
一般情况下是这样操作的
let temp = a
a = b
b = temp
JavaScript可以直接这样交换元素的值
[a, b] = [b ,a]
JavaScript的自有特性当然远远不止这些,后面我也会继续进行归纳总结的~
总结
- 一些位元算可以提高代码的执行效率,可以在数字的一些运算的时候考虑他们的二进制
- JavaScript中有很多好用的特性,我们要会利用好
- 后面我会再总结关于JavaScript位运算与小技巧的博文,敬请期待
更多相关博文
【青训营】月影老师告诉我写好JavaScript的三大原则——各司其责
【青训营】月影老师告诉我写好JavaScript的三大原则——组件封装
【青训营】月影老师告诉我写好JavaScript的三大原则——过程抽象
【青训营】月影老师告诉我写好JavaScript的四大技巧——风格优先
【青训营】月影老师告诉我写好JavaScript的四大技巧——保证正确
【青训营】月影老师告诉我写好JavaScript的四大技巧——封装函数
【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性
也可以关注专栏: 【青训营笔记专栏】
更多推荐
【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性
发布评论