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 相关文章推荐
在js中单选框和复选框获取值的方式
Nov 06 Javascript
jQuery html()等方法介绍
Nov 18 Javascript
JS date对象的减法处理实现代码
Dec 28 Javascript
window.open的页面如何刷新(父页面)上层页面
Dec 28 Javascript
javascript按位非运算符的使用方法
Nov 14 Javascript
js动态移动滚动条至底部示例代码
Apr 24 Javascript
浅析Node.js中的内存泄漏问题
Jun 23 Javascript
jQuery自定义多选下拉框效果
Jun 19 jQuery
Vue点击切换颜色的方法
Sep 13 Javascript
在Vue项目中引入JQuery-ui插件的讲解
Jan 27 jQuery
原生js实现贪吃蛇游戏
Oct 26 Javascript
Nuxt pages下不同的页面对应layout下的页面布局操作
Nov 05 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
关于手调机和数调机的选择
2021/03/02 无线电
PHP查询数据库中满足条件的记录条数(两种实现方法)
2013/01/29 PHP
PHP文件上传之多文件上传的实现思路
2016/01/27 PHP
PhpStorm本地断点调试的方法步骤
2018/05/21 PHP
laravel ORM关联关系中的 with和whereHas用法
2019/10/16 PHP
基于prototype的validation.js发布2.3.4新版本,让你彻底脱离表单验证的烦恼
2006/12/06 Javascript
初试jQuery EasyUI 使用介绍
2010/04/01 Javascript
jQuery的实现原理的模拟代码 -2 数据部分
2010/08/01 Javascript
Javascript将string类型转换int类型
2010/12/09 Javascript
整理一些JavaScript的IE和火狐的兼容性注意事项
2011/03/17 Javascript
ExtJS下书写动态生成的xml(兼容火狐)
2013/04/02 Javascript
js 通用订单代码
2013/12/23 Javascript
手机端图片缩放旋转全屏查看PhotoSwipe.js插件实现
2016/08/25 Javascript
BootStrap学习系列之布局组件(下拉,按钮组[toolbar],上拉)
2017/01/03 Javascript
利用transition实现文字上下抖动的效果
2017/01/21 Javascript
vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理
2017/03/06 Javascript
Vue2.0利用vue-resource上传文件到七牛的实例代码
2017/07/28 Javascript
JS对象序列化成json数据和json数据转化为JS对象的代码
2017/08/23 Javascript
微信小程序登录换取token的教程
2018/05/31 Javascript
Javascript Web Worker使用过程解析
2020/03/16 Javascript
ant design vue datepicker日期选择器中文化操作
2020/10/28 Javascript
JavaScript/TypeScript 实现并发请求控制的示例代码
2021/01/18 Javascript
Python中字符编码简介、方法及使用建议
2015/01/08 Python
Python 实现两个列表里元素对应相乘的方法
2018/11/14 Python
django框架model orM使用字典作为参数,保存数据的方法分析
2019/06/24 Python
python进程的状态、创建及使用方法详解
2019/12/06 Python
美国网上眼镜商城:Zenni Optical
2016/11/20 全球购物
英国家喻户晓的家居商店:The Range
2019/03/25 全球购物
彪马俄罗斯官网:PUMA俄罗斯
2019/07/13 全球购物
Unix里面如何在后台运行程序
2016/10/14 面试题
Servlet都有哪些方法?主要作用是什么?
2014/03/04 面试题
学生会竞选自荐信
2013/10/12 职场文书
全神贯注教学反思
2014/02/03 职场文书
如何写股份合作协议书
2014/09/11 职场文书
员工担保书范本
2015/09/22 职场文书
高通2023 年将发布高性能PC处理器
2022/04/29 数码科技