JavaScript中的一些实用小技巧总结


Posted in Javascript onApril 07, 2019

前言

这篇文章主要记录一下平时自己实践得到的, 博客中学习的以及在一些项目源码中看到的 javascript 技巧。有些东西可以说是奇淫技巧,有些可能是 ES6+ 中一些比较具有实用性的新语法。

&& 和 || 的妙用

有时候我们需要在某个函数或变量为 true 时执行另外一个函数。例如:

const task1 = () => {
 console.log('执行 task1');
 return Math.random() >= 0.5;
}

const task2 = () => console.log('task1 执行成功后执行 task2');
if (task1()) task2();

上面的 if 语句可以使用 && 直接简写为:

task1() && task2();

如果还要在 task1 失败(也就是task1返回false)后执行 task3, 可以使用:

const task3 = () => console.log('task1 执行失败后执行 task3');
task1() && task2() || task3();

本质上还是利用了 && 和 || 的短路特性。

其实这里使用条件运算符也是可以的:

task1() ? task2() : task3();

下面展示一个我最近使用 react hooks 开发的项目的的一个代码片段:

const ProfileItem = (props) => {
 const { name, value, render } = props;

 return (
  <div className="profile-item">
   <span className="item-name">{name}</span>
   <form action="">
    {/* 根据是否有 render 这个 props 来返回不同的内容 */}
    {render && render(props) || <SimpleProfileItemContent value={value}/>}
   </form>
  </div>
 )
}

函数默认值

ES5 版本

使用短路或操作符来设置函数默认值的方式其实很常见。但是有一些坑,下面展示的代码中当默认值参数为一个数字时,传参为 0 还是会使用默认值,必须对 y 为 0 的时候单独进行判断。

const pow = (x, y) => {
 y = y || 2;
 
 let result = 1;
 for (let i = 0, max = y; i < max; i++) {
  result *= x;
 }

 return result;
}

console.log(pow(2)); // => 4
console.log(pow(2, 3)); // => 8

// 当 y 传值为 0 时, y 取值 2
console.log(pow(2, 0)); // => 4

ES6 版本

ES6 在语法层面提供的默认值语法就靠谱的多了

const pow = (x, y=2) => {
 let result = 1;
 for (let i = 0, max = y; i < max; i++) {
  result *= x;
 }

 return result;
}

console.log(pow(2)); // => 4
console.log(pow(2, 3)) // => 8
console.log(pow(2, 0)); // => 1

类数组转数组

类数组指的是像 arguments ,jquery 对象一样可以使用下标访问还有 length 属性的和数组很像但并不是数组的一类对象。

类数组没有 slice, map 等集合函数,这也是为什么我们有时候需要将类数组转换成数组的原因。

function func() {
 for (let i = 0, max = arguments.length; i < max; i++) {
  console.log(arguments[i]);
 }

 console.log(Array.isArray(arguments)); // => false
 // 类数组没有 slice, forEach, map 等集合函数
 console.log(arguments.slice === undefined); // => true
}

func('Google', 'facebook', 'Microsoft'); 
// => 
// Google
// facebook
// Microsoft

ES5 中的转换方法

将 Array 原型中的 slice 方法绑定到 arguments 对象上调用,并且不传参数目的为了让其返回所有的元素。

function func() {
 const array = Array.prototype.slice.call(arguments);
 console.log(array.slice(0, 1));
}

func('Google', 'facebook', 'Microsoft'); // => [ 'Google' ]

ES6 中的转换方法

ES6 将类数组转换成数组的方法多一些。

使用扩展运算符

function func() {
 console.log([...arguments])
}

func('Google', 'facebook', 'Microsoft'); // [ 'Google', 'facebook', 'Microsoft' ]

使用 Array.from

function func() {
 console.log(Array.from(arguments))
}

func('Google', 'facebook', 'Microsoft'); // [ 'Google', 'facebook', 'Microsoft' ]

构造一个连续整数的数组

这里就直接给出我觉得最好的方法了

// 输出 2 开始连续的8个整数
const array = Array.from({ length: 8}).map((ele, index) => index + 2);
console.log(array); // => [ 2, 3, 4, 5, 6, 7, 8, 9 ] 
// 评论区指出有更简洁的版本, Array.from 自带的映射函数
const array = Array.from({ length: 8}, (ele, index) => index + 2);
console.log(array); // => [ 2, 3, 4, 5, 6, 7, 8, 9 ] 

函数参数使用解构赋值

函数参数比较多的时候我们往往会让参数直接接受一个配置对象。但是使用对象参数我们无法设置默认值,在函数体中使用对象参数时还需要使用通过对象参数来访问,当访问次数比较多或者嵌套比较深就会觉得不方便。在函数参数中使用解构赋值就解决了上面的问题。

// 必须给对象参数设置默认值, 不然传参数时因为没有解构对象会报错
const getUsers = ({
 offset=0,
 limit=1,
 orderBy="salary"
}={}) => {
 // 根据条件查询数据库返回用户数据
 console.log({ offset, limit, orderBy });
}

getUsers({ offset: 10, limit: 20,orderBy: 'age' }); // => { offset: 10, limit: 20, orderBy: 'age' }
getUsers();// => { offset: 0, limit: 1, orderBy: 'salary' }

使用 !! 将其它类型转换成 bool 型

console.log(!!{}); // true
console.log(!!0); // false
console.log(!![]); // true
console.log(!!undefined); // false

const httpGet = (url, retry) => {
 if (!!retry) {
  // 超时重发
 }
}

JSON.stringify

深度克隆

使用先序列化再反序列化这种方式来深度克隆对象在一般情况下很方便,缺点就是无法克隆函数以及继承的属性。
如果还要克隆函数属性,推荐使用 lodash 的 cloneDeep。

const me = {
  name: 'lyreal666',
  age: 23,
  speak() {
    console.log(`Hello, I'm ly!`);
  }
}

const clonedMe = JSON.parse(JSON.stringify(me));
console.log(clonedMe); // => { name: 'lyreal666', age: 23 }
console.log(clonedMe.speak === undefined); // => true

使用第二个和第三参数

JSON.stringify 的第二个参数是用来对属性值进行处理的,第三个参数则是用来指定输出的 json 字符串的缩进长度,可以传数字也可以传字符串。

const me = {
  name: 'lyreal666',
  age: 23,
  speak() {
    console.log(`Hello, I'm ly!`);
  }
}

const jsonStr = JSON.stringify(me, (key, value) => key === 'name' ? '老余' : value, 2);

console.log(jsonStr);
/* =>
{
 "name": "老余",
 "age": 23
}
*/

优雅的遍历对像

使用解构赋值和 Object.entries。

const me = {
  name: 'lyreal666',
  age: 23,
  speak() {
    console.log(`Hello, I'm ly!`);
  }
}

for (const [key, value] of Object.entries(me)) {
  console.log(`${key}: ${value}`);
}

/* =>
name: lyreal666
age: 23
speak: speak() {
    console.log(`Hello, I'm ly!`);
  }
*/

清空数组的最快方法

评论区有人说这种直接修改 length 的做法是有问题的, 我之前也看过关于清空数组的方法的讨论, 但是我觉得一般情况下这样用是没什么问题的, 既简单, 又不用重新分配内存给新数组。

const array = [1, 2, 3, 4];
array.length = 0;
console.log(array); // => []

// 网友指出可以更好的方式是直接赋值空数组
let array = [1, 2, 3, 4];
array = [];

判断一个整数是否是 -1

// ~ 操作符的运算规律可以简单记作将加一的结果取反
console.log(~1); // => -2
console.log(~0); // => -1
console.log(~(-3)); // => 2
console.log(~(-1)); // => 0

const number = -2;

// 判断一个数是否为 -1
if (!~number) {
  // 当 number 是 -1 的操作...
}

立即执行函数

立即执行函数可以让我们的代码中的变量不污染外部变量,常见的使用方式是像下面这样的。

// 使用括号将函数括起来调用
(function(window, $) {
  // 内部代码
}) (window, jQuery)

更优雅的方式是下面这种,事实上很多其它的算术运算符比如 +, -, *, ~ 等也是可以的。

! function(window, $) {
  // 内部代码
} (window, jQuery)

// 还可以使用 +, -, * 等
+ function(window, $) {
  // 内部代码
} (window, jQuery)

// 更神奇的是还可以用 new, typeof 等操作符
new function(window, $) {
  // 内部代码
} (window, jQuery);

使用 set 来对数组去重复

console.log([...new Set([1, 3, 1, 2, 2, 1])]); // => [ 1, 3, 2 ]

使用 reduce 连乘或连加

const array = [ 1, 2, 3, 4];
// 连加
console.log(array.reduce((p, c) => p + c)); // => 10
// 连乘
console.log(array.reduce((p, c) => p * c)); // => 24

取整

Math 中的一堆取整函数这里就不说了,主要是提一些比较巧妙地取整方式。

console.log(~~3.14); // => 3
console.log(~~(-2.5)); // => -2

console.log(6.18 | 0); // => 6
console.log(-3.6 | 0); // => -3

console.log(9.9 >> 0); // => 9
console.log(-2.1 >> 0); // => -2

// superagent 是一个很实用的发送 http 请求的 node 模块,它对返回码的处理就用到了 |
var type = status / 100 | 0;

// status / class
res.status = status;
res.statusType = type;

// basics
res.info = 1 == type;
res.ok = 2 == type;
res.clientError = 4 == type;
res.serverError = 5 == type;
res.error = 4 == type || 5 == type;

使用 + 将其它类型转换成 number 类型

console.log(+'3.14'); // => 3.14
console.log(typeof +'3.14') // => number

const sleep = (milliseconds) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(), milliseconds);
    });
}

// 当然这里可以考虑使用 console.time 来测试
! async function main() {
  const start = +new Date();
  await sleep(3000);
  const end = +new Date();
  console.log(`执行了${end - start}`); // 执行了 3002
}();

使用科学计数法表示大数字

const str1 = 'hello';
const str2 = ' world'

console.time('测试 + 拼接字符串');
for (let i = 0; i < 200000000; i++) {
  const joinedStr = str1 + str2;
}
console.timeEnd('测试 + 拼接字符串');

console.time('测试模板字符串拼接字符串');
// 使用科学计数法比打 8 个 0 方便不少
for (let i = 0; i < 2E8; i++) {
  const joinedStr =`${str1}${str2}`;
}
console.timeEnd('测试模板字符串拼接字符串')

/* =>
测试 + 拼接字符串: 3238.037ms
测试模板字符串拼接字符串: 3680.225ms
*/

交换变量值

直接利用解构赋值

let a = 666;
let b = 999;
[a, b] = [b, a];
console.log({ a, b }); // => { a: 999, b: 666 }

获取随机字符串

截取下标 2 开始后的字符串是因为不需要 Math.random() 返回的小数构成的字符串的 0. 这两个字符。使用 36 进制可以制造字符种类更多些的随机字符串

console.log(Math.random().toString(16).substring(2)); // 13位 => 45d9d0bb10b31
console.log(Math.random().toString(36).substring(2)); // 11位 => zwcx1yewjvj

扁平化数组

ES 2019 新增了 Array.prototype.flat,目前 chrome 最新正式版 73.0.3683.103 已经支持了, node 最新的 LTS 10.15.3 还不支持, node 最新开发版 11.13.0 是支持的。这里贴一个在掘金一个兄弟面经里面看到的比较 hack 的方法,这里要注意根据情况做类型转换。

const array = [1, [2, [3, 4], 5], 6, 7];
console.log(array.toString().split(',').map(ele => Number.parseInt(ele))); // => [ 1, 2, 3, 4, 5, 6, 7 ]

最近面试腾讯,阿里前端实习岗真的是一言难尽,后面打算整篇文章聊聊我最近的面试经历。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
Prototype使用指南之enumerable.js
Jan 10 Javascript
JavaScript 解析读取XML文档 实例代码
Jul 07 Javascript
Function.prototype.bind用法示例
Sep 16 Javascript
js控制input输入字符解析
Dec 27 Javascript
JS实现将人民币金额转换为大写的示例代码
Feb 13 Javascript
javascript实现的网站访问量统计代码
Dec 20 Javascript
JavaScript实现简洁的俄罗斯方块完整实例
Mar 01 Javascript
微信小程序组件 contact-button(客服会话按钮)详解及实例代码
Jan 10 Javascript
移动端H5页面返回并刷新页面(BFcache)的方法
Nov 06 Javascript
JavaScript实现的3D旋转魔方动画效果实例代码
Jul 31 Javascript
js实现拖拽与碰撞检测
Sep 18 Javascript
解决vue项目打包上服务器显示404错误,本地没出错的问题
Nov 03 Javascript
详解vue 不同环境配置不同的打包命令
Apr 07 #Javascript
JavaScript数组去重的几种方法
Apr 07 #Javascript
vue表单验证你真的会了吗?vue表单验证(form)validate
Apr 07 #Javascript
js中Generator函数的深入讲解
Apr 07 #Javascript
巧妙运用v-model实现父子组件传值的方法示例
Apr 07 #Javascript
vue路由导航守卫和请求拦截以及基于node的token认证的方法
Apr 07 #Javascript
vue自定义指令directive的使用方法
Apr 07 #Javascript
You might like
在PHP中利用XML技术构造远程服务(上)
2006/10/09 PHP
PHP彩蛋信息介绍和阻止泄漏的方法(隐藏功能)
2014/08/06 PHP
php 使用html5实现多文件上传实例
2016/10/24 PHP
jQuery 选择器、DOM操作、事件、动画
2010/11/25 Javascript
jQuery Clone Bug解决代码
2010/12/22 Javascript
jQuery增加和删除表格项目及实现表格项目排序的方法
2016/05/30 Javascript
把json格式的字符串转换成javascript对象或数组的方法总结
2016/11/03 Javascript
JavaScript动态数量的文件上传控件
2016/11/18 Javascript
jQuery插件HighCharts绘制2D金字塔图效果示例【附demo源码下载】
2017/03/09 Javascript
AngularJS1.X学习笔记2-数据绑定详解
2017/04/01 Javascript
详解JavaScript中return的用法
2017/05/08 Javascript
jQuery中$原理实例分析
2018/08/13 jQuery
使用vue完成微信公众号网页小记(推荐)
2019/04/28 Javascript
微信提示 在浏览器打开 效果实现过程解析
2019/09/10 Javascript
vue(2.x,3.0)配置跨域代理
2019/11/27 Javascript
js用正则表达式筛选年月日的实例方法
2021/01/04 Javascript
跟老齐学Python之再深点,更懂list
2014/09/20 Python
Python编程中用close()方法关闭文件的教程
2015/05/24 Python
Djang中静态文件配置方法
2015/07/30 Python
python之文件的读写和文件目录以及文件夹的操作实现代码
2016/08/28 Python
Python实现自动发送邮件功能
2021/03/02 Python
Python读写及备份oracle数据库操作示例
2018/05/17 Python
基于python实现KNN分类算法
2020/04/23 Python
python中有关时间日期格式转换问题
2019/12/25 Python
浅谈pytorch、cuda、python的版本对齐问题
2020/01/15 Python
如何在 Django 模板中输出 &quot;{{&quot;
2020/01/24 Python
音乐教学案例
2014/01/30 职场文书
公益广告语集锦
2014/03/13 职场文书
借款担保书范文
2014/05/13 职场文书
质量管理标语
2014/06/12 职场文书
投标人法定代表人授权委托书格式
2014/09/28 职场文书
教师党员个人剖析材料
2014/09/29 职场文书
群众路线教育实践活动心得体会(四风)
2014/11/03 职场文书
财产保全担保书
2015/01/20 职场文书
大专护理专业自荐信
2015/03/25 职场文书
教你怎么用python selenium实现自动化测试
2021/05/27 Python