這篇文章主要記錄一下平時本身實踐獲得的, 博客中學習的以及在一些項目源碼中看到的 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。