【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性

【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性我们平时在刷题或者网上找资料的时候,得到的很多答案可能都不是用JavaScript实现的,我们就直接照搬翻译成JavaScript过来了,其实JavaScript有很多自己的特性,用的好的话直接起飞

如何写好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 false
        n /= 4
    }
    return true
};

看看LeetCode上执行的结果

image.png

还不错,够用了~

菜鸟学废版

我们使用位运算来提高效率啊

一个数x模4就相当于 x 的二进制形式 与 二进制数 11 也就是十进制的 3 按位相,(与运算是两个数都为1结果才为1,否则结果都是0)因为11前面都是0,所以x的二进制形式最后只剩最后两位,最后两位 与 11 做与运算,结果还是自身(x的二进制形式的最后两位),所以 n % 4n & 3 是一样的;

一个数除以4,相当于把他的二进制形式向右移动2位(向右移动一位相当于除以2),所以 n / 4n >>> 2 是一样的

var isPowerOfFour = function(n) {
    if( n < 1) return false 
    while(n > 1){
        if(n & 3) return false
        n >>>= 2
    }
    return true
};

看看LeetCode上执行的结果

image.png

进阶版

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上执行的结果

image.png

效率不咋地啊 不过多测几次还不一样

image.png

image.png

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上执行的结果 image.png

还可以的样子啊~

案例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;
  // 递归调用mergeSort
  mergeSort(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中的元素按规则写回nums
  for (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);
  // 递归调用mergeSort
  return 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的自有特性当然远远不止这些,后面我也会继续进行归纳总结的~

总结

  1. 一些位元算可以提高代码的执行效率,可以在数字的一些运算的时候考虑他们的二进制
  2. JavaScript中有很多好用的特性,我们要会利用好
  3. 后面我会再总结关于JavaScript位运算与小技巧的博文,敬请期待

更多相关博文

【青训营】月影老师告诉我写好JavaScript的三大原则——各司其责

【青训营】月影老师告诉我写好JavaScript的三大原则——组件封装

【青训营】月影老师告诉我写好JavaScript的三大原则——过程抽象

【青训营】月影老师告诉我写好JavaScript的四大技巧——风格优先

【青训营】月影老师告诉我写好JavaScript的四大技巧——保证正确

【青训营】月影老师告诉我写好JavaScript的四大技巧——封装函数

【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性

也可以关注专栏: 【青训营笔记专栏】

今天的文章【青训营】月影老师告诉我写好JavaScript的四大技巧——妙用特性分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/20586.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注