这篇文章主要记录一下平时本身实践获得的, 博客中学习的以及在一些项目源码中看到的 javascript 技巧。有些东西能够说是奇淫技巧,有些多是 ES6+ 中一些比较具备实用性的新语法。javascript
有时候咱们须要在某个函数或变量为 true 时执行另一个函数。例如:前端
const task1 = () => {
console.log('执行 task1');
return Math.random() >= 0.5;
}
const task2 = () => console.log('task1 执行成功后执行 task2');
if (task1()) task2();
复制代码
上面的 if 语句可使用 &&
直接简写为:java
task1() && task2();
复制代码
若是还要在 task1 失败(也就是task1返回false)后执行 task3, 可使用:node
const task3 = () => console.log('task1 执行失败后执行 task3');
task1() && task2() || task3();
复制代码
本质上仍是利用了 &&
和 ||
的短路特性。react
其实这里使用条件运算符也是能够的:jquery
task1() ? task2() : task3();
复制代码
下面展现的我最近的一个使用 react hooks 开发的项目中的一个代码片断,这里利用了 render props:面试
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> ) } 复制代码
使用短路或操做符来设置函数默认值的方式其实很常见。可是有一些坑,下面展现的代码中当默认值参数为一个数字时,传参为 0 仍是会使用默认值,必须对 y 为 0 的时候单独进行判断。chrome
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 在语法层面提供的默认值语法就靠谱的多了数据库
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 属性的和数组很像但并非数组的一类对象。json
类数组没有 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
复制代码
将 Array 原型中的 slice 方法绑定到 arguments 对象上调用,而且不传参数目的为了让其返回全部的元素。
function func() {
const array = Array.prototype.slice.call(arguments);
console.log(array.slice(0, 1));
}
func('Google', 'facebook', 'Microsoft'); // => [ 'Google' ]
复制代码
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 ]
// 还有一个网友指出能够利用 Array.prototype.keys 来构造
const array = [...Array(8).keys()].map((ele, index) => index + 2)
复制代码
函数参数比较多的时候咱们每每会让参数直接接受一个配置对象。可是使用对象参数咱们没法设置默认值,在函数体中使用对象参数时还须要使用经过对象参数来访问,当访问次数比较多或者嵌套比较深就会以为不方便。在函数参数中使用解构赋值就解决了上面的问题。
// 必须给对象参数设置默认值, 否则传参数时由于没有解构对象会报错
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' }
复制代码
console.log(!!{}); // true
console.log(!!0); // false
console.log(!![]); // true
console.log(!!undefined); // false
const httpGet = (url, retry) => {
if (!!retry) {
// 超时重发
}
}
复制代码
使用先序列化再反序列化这种方式来深度克隆对象在通常状况下很方便,缺点就是没法克隆函数以及继承的属性。
若是还要克隆函数属性,推荐使用 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 = [];
复制代码
// ~ 操做符的运算规律能够简单记做将加一的结果取反
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);
复制代码
console.log([...new Set([1, 3, 1, 2, 2, 1])]); // => [ 1, 3, 2 ]
复制代码
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;
复制代码
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 ]
复制代码
最近面试腾讯,阿里前端实习岗真的是一言难尽,后面打算整篇文章聊聊我最近的面试经历。nodejs 写爬虫系列文章第二篇也快要写完了。
本文为原创内容,首发于我的博客,转载请注明出处。若是有问题欢迎邮件骚扰 ytj2713151713@gmail.com。