總結下 javascript 中的一些小技巧

lyreal666發表於2019-04-03

這篇文章主要記錄一下平時自己實踐得到的, 部落格中學習的以及在一些專案原始碼中看到的 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 失敗後執行 task3, 可以使用:

const task3 = () => console.log('task1 執行失敗後執行 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
複製程式碼

類陣列轉陣列

類陣列指的是像 argumentsjquery 物件一樣可以使用下標訪問還有 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 ] 
複製程式碼

函式引數使用結構賦值

函式引數比較多的時候我們往往會讓引數直接接受一個配置物件。但是使用物件引數我們無法設定預設值,在函式體中使用物件引數時還需要使用通過物件引數來訪問,當訪問次數比較多或者巢狀比較深就會覺得不方便。在函式引數中使用結構賦值就解決了上面的問題。

// 必須給物件引數設定預設值, 不然傳引數時因為沒有解構物件會報錯
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!`);
    }
*/
複製程式碼

清空陣列的最快方法

const array = [1, 2, 3, 4];
array.length = 0;
console.log(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)
複製程式碼

使用 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
複製程式碼

更多技巧待我想起來了再補充...

本文為原創內容,首發於個人部落格, 轉載請註明出處。如果有問題歡迎郵件騷擾 ytj2713151713@gmail.com。

相關文章