3

用得上的 JavaScript 代码片段和技巧

 2 years ago
source link: https://www.techug.com/post/useful-javascript-code-snippets-and-techniques.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

用得上的 JavaScript 代码片段和技巧

2



img163616190664566534.jpeg

过去陆陆续续总结了一些有助项目开发效率和开发技能的代码片段,一方面加深对 Javascript 语法的理解,一方面对代码进行归档。本文总结一些项目开发中用得上的使用方法及代码整洁的技巧。

1. localStorage

localStorage 是 HTML5 中的本地持久化存储方法之一,也是前端项目常用的本地存储方案之一。localStorage 存储的数据只要用户不去主动清除是永久存储的,存储的值只能是 string 类型,不能跨浏览器,不能跨域名访问,存储大小一般是 5M 左右。现代前端项目基本都会用到localStorage ,下面的代码片段对 localStorage 数据的存储、获取、清除进行封装。

const useStorage = (storageKey = "authorization") => {
    const localKey = `devpoint.local.${storageKey}`;


    const toJson = (str) => {
        try {
            return JSON.parse(str);
        } catch {
            return false;
        }
    };


    const save = (data) => {
        window.localStorage.setItem(localKey, JSON.stringify(data));
    };


    const get = () => {
        const localData = window.localStorage.getItem(localKey);
        if (localData && localData !== "") {
            return toJson(localData);
        } else {
            return false;
        }
    };
    /**
     * 清除localStorage
     */
    const clear = () => {
        window.localStorage.setItem(localKey, "");
    };
    // 返回存储对象处理方法
    return {
        save,
        get,
        clear,
    };
};
const storageAuth = useStorage();
const loginInfo = {
    username: "hballard",
    age: 30,
};
storageAuth.save(loginInfo);
console.log(storageAuth.get());

2. JSON 格式判断

当需要数据是否为 JSON 格式时,下面的代码片段将派上用场:

function isJSON(str) {
    try {
        JSON.parse(str);
    } catch {
        return false;
    }
    return true;
}
const data1 = "JavaScript";
const data2 = `{"title":"js"}`;
console.log(isJSON(data1)); // false
console.log(isJSON(data2)); // true

3. Array 转 CSV

CSV 是当今广泛使用的电子表格,可以使用如下所示的简单代码段将数组转换为 CSV 格式:

const arrayToCSV = (array, delimiter = ",") =>
    array
        .map((item) => item.map((value) => `"${value}"`).join(delimiter))
        .join("\n");


const users = [
    { name: "hballard", age: 30 },
    { name: "sguzman", age: 24 },
    { name: "jrowe", age: 28 },
    { name: "plowe", age: 32 },
];
const arrayUsers = users.map((item) => Object.values(item));
console.log(arrayUsers);
// [
//     [ 'hballard', 30 ],
//     [ 'sguzman', 24 ],
//     [ 'jrowe', 28 ],
//     [ 'plowe', 32 ]
//   ]
const strCsv1 = arrayToCSV(arrayUsers);
const strCsv2 = arrayToCSV(arrayUsers, ";");


console.log(strCsv1);
// "hballard","30"
// "sguzman","24"
// "jrowe","28"
// "plowe","32"
console.log(strCsv2);
// "hballard";"30"
// "sguzman";"24"
// "jrowe";"28"
// "plowe";"32"

4. 数字格式判断

下面的代码片段将展示如何检查一个值或变量是否包含一个数字(整数、浮点数等)。

function isNumber(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}
console.log(isNumber(100)); // true
console.log(isNumber(3.14)); // true
console.log(isNumber("3.14")); // true
console.log(isNumber("a3.14")); // false
console.log(isNumber("JavaScript")); // false

5. 数据类型判断

数据类型判断是在大部分项目中都会用上,特别对于 JavaScript ,对于不同的数据类型使用不同的方法。

const isCheck = (type, val) =>
    ![undefined, null].includes(val) && val.constructor === type;


console.log(isCheck(Array, ["a"])); // true
console.log(isCheck(Object, {})); // true
console.log(isCheck(ArrayBuffer, new ArrayBuffer())); // true
console.log(isCheck(Boolean, new Boolean(true))); // true
console.log(isCheck(RegExp, /./g)); // true
console.log(isCheck(Number, 0)); // true

6. 数组求和、平均值

reduce 方法在数组的每个元素上执行提供的回调函数迭代器。它传入前一个元素计算的返回值,结果是单个值,它是在数组的所有元素上运行迭代器的结果。对于数组求和、平均值等场合非常实用。

const sum = (...array) => [...array].reduce((acc, current) => acc + current, 0);


const testArray = [1, 2, 3, 4, 5];
console.log(sum(1, 2, 3, 4, 5)); // 15
console.log(sum(...testArray)); // 15

const average = (...numbers) =>
    numbers.reduce((acc, current) => acc + current, 0) / numbers.length;


const testArray1 = [1, 2, 3, 4, 5];
console.log(average(...testArray1)); // 3
console.log(average(1, 2, 3, 4, 5)); // 3

7. 函数链

函数链,应该算是代码组织形式,这里放到代码片段中,希望可以对项目代码组织有一定的启发。

function CusModal() {
    const This = this;
    this.options = {
        theme: "default",
        title: "modal",
        visible: false,
    };
    const setOptions = function (key, value) {
        This.options[key] = value;
    };
    this.setTheme = function (theme) {
        setOptions("theme", theme);
        return this;
    };
    this.setTitle = function (title) {
        setOptions("title", title);
        return this;
    };
    this.show = function () {
        setOptions("visible", true);
    };
    this.close = function () {
        setOptions("visible", false);
    };
    this.getOptions = function () {
        return this.options;
    };
}


const modalHelper = new CusModal();
// 设置弹窗主题、设置标题、显示
modalHelper.setTheme("dark").setTitle("发布文章窗口").show();


console.log(modalHelper.getOptions()); // { theme: 'dark', title: '发布文章窗口', visible: true }

8. 科学计数完整显示

在项目中有遇到 API 返回数字是以科学计数法的方式,在页面上需要显示完整的数字,通常并不清楚科学计数的数字是小数点多少位,因此在精度方面不好固定。下面代码实现了一个小数点后大于 0 的数字三位,如下:

function flatNumber(num) {
    const strNumber = num.toFixed(30);
    console.log(strNumber);
    const arrayNumbers = [...strNumber];
    const numberIndex = arrayNumbers.findIndex(
        (item) => parseInt(item, 10) > 0
    );
    const precision = numberIndex >= 0 ? numberIndex + 1 : 0;
    return num.toFixed(precision);
}


const number = 1.71604938271605e-8;
console.log(number.toFixed(30)); // 0.000000017160493827160499945830
console.log(flatNumber(number)); // 0.0000000172

9. 定时器

定时器,在项目开发过程中结果过,使用定时器需要严格控制定时器的启动与关闭,避免过多定时器没有关闭导致内存泄露,下面代码实现了一个定时器的开启与停止:

class Timer {
    constructor(fn, delay) {
        this._triggerTimer = null;
        this._delay = delay;
        this._fn = fn;
    }


    stop() {
        if (this._triggerTimer) {
            clearTimeout(this._triggerTimer);
            this._triggerTimer = null;
        }
    }


    begin() {
        this.stop();
        this._triggerTimer = setTimeout(() => {
            this._fn();
        }, this._delay);
    }
}
// 下面是使用方法
let timerCount = 0;
const timerHelper = new Timer(() => {
    timerCount++;
    if (timerCount < 5) {
        console.log(timerCount);
        timerHelper.begin();
    } else {
        timerHelper.stop();
    }
}, 2000);
timerHelper.begin();

10. 时间格式化

JavaScript 中时间相关的脚本库有很多,如 Moment 和 Luxon,提供比较丰富的时间相关的方法,这里介绍原生方法的实现。

const formatDate = (date, formatStr = "YYYY-MM-DD") => {
    date = new Date(date);
    const padStart = (str) => str.toString().padStart(2, "0");
    const month = date.getMonth() + 1;
    const year = date.getFullYear();
    const day = date.getDate();
    const hours = date.getHours();
    const minutes = date.getMinutes();
    const seconds = date.getSeconds();
    return formatStr
        .replace(/\bYYYY\b/g, year)
        .replace(/\bYY\b/g, `${year}`.substring(2))
        .replace(/\bMM\b/g, padStart(month))
        .replace(/\bM\b/g, month)
        .replace(/\bDD\b/g, padStart(day))
        .replace(/\bD\b/g, day)
        .replace(/\bHH\b/g, padStart(hours))
        .replace(/\bhh\b/g, hours)
        .replace(/\bmm\b/g, padStart(minutes))
        .replace(/\bss\b/g, padStart(seconds));
};
console.log(formatDate(Date.now())); // 2021-11-03
console.log(formatDate(Date.now(), "YYYY-MM-DD HH:mm:ss")); // 2021-11-03 18:49:29

11. 类私方法

JavaScript 有自己的方法来创建类私有成员,但目前还处于 ES2020 试验草案中,并且语法比较奇怪,以 # 作为前缀。下面代码片段使用闭包、作用域来实现类的私有域。

const Helper = (() => {
    // 这里定义私有方法 defaultValue
    const defaultValue = (val, defVal) => {
        if (val && val !== "") {
            return val;
        } else {
            return defVal;
        }
    };
    const apiEndpoint = "/Auth";


    // 对外暴露的类
    class Utility {
        constructor() {
            this.loginPath = `${apiEndpoint}/login`;
        }


        getVal(key, defVal) {
            return defaultValue(key, defVal);
        }
    }
    return Utility;
})();


const testHelper = new Helper();
console.log(testHelper.getVal(undefined, 0)); // 0
console.log(testHelper.loginPath); // /Auth/login

12. 空值判断

正如上面说的,判断空值,在不同的项目下有不同的解释,下面的代码片段可以判断所有类型的空值。

const isEmpty = (x) => {
    if (Array.isArray(x) || typeof x === "string" || x instanceof String) {
        return x.length === 0;
    }


    if (x instanceof Map || x instanceof Set) {
        return x.size === 0;
    }


    if ({}.toString.call(x) === "[object Object]") {
        return Object.keys(x).length === 0;
    }
    if (!isNaN(parseFloat(x)) && isFinite(x)) {
        return false;
    }
    return !x;
};
console.log(isEmpty(null)); // true
console.log(isEmpty(undefined)); // true
console.log(isEmpty([])); // true
console.log(isEmpty({})); // true
console.log(isEmpty("")); // true
console.log(isEmpty(new Set())); // true
console.log(isEmpty(0));

代码整洁技巧

项目开发中,除了完成相应功能需要,还需要去重新阅读其代码,去发掘代码整洁的方式,代码优化是一个没有标准答案的工作,但有一些推荐的方式。下面总结了一些代码整洁的技巧。在这里推荐两个学些代码的不错的网站 https://1loc.dev/30secondsofcode

1. 短循环

你知道在 JavaScript 中可以在一行中缩短循环吗?这意味着可以为循环编写更少的代码。

const provinces = ["Guangdong", "Jiangxi", "Hunan", "Fujian"];
// 常规
for (let i = 0, len = provinces.length; i < len; i++) {
    console.log(provinces[i]);
}
// 短循环
for (const province of provinces) console.log(province);

2. 数组长度变更

在 JavaScript 可以通过使用 length 方法调整数组的大小, length 不仅用于获取数组的长度,还可以对数组进行切片。

const array1 = [1, 2, 3, 4, 5, 6];
const array2 = ["Python", "JavaScript", "C++", "Dart"];
array1.length = 3;
array2.length = 1;
console.log(array1); // [1, 2, 3]
console.log(array2); // ["Python"]

3. 浮点数转换为整数

要将浮点数转换为整数,通常可以使用 Math.floor()Math.round()Math.ceil() 方法,这里介绍一种简短的方式,即按位 OR ,如下:

// 常规
console.log(Math.floor(3.14)); // 3
// 简短
console.log(3.14 | 0); // 3

4. 数组去重

通过利用 JavaScript 数据类型 Set 特征,关于 Set 的使用可以参阅《JavaScript中的Set数据操作:交集、差集、交集、对称差集》。使用Set 可以快速的实现数组去重,如下:

const removeDupli = (arr) => [...new Set(arr)];
console.log(removeDupli([2, 2, 2, 11, 3])); // [ 2, 11, 3 ]
console.log(removeDupli([2, 0, 2, 1, 11, 1])); // [ 2, 0, 1, 11 ]

5. 数组合并

这段代码将两个数组合并为一个数组,这是一种简单快捷的方法,无需使用循环。

const lang1 = ["JavaScript", "Python", "C++"];
const lang2 = ["C#", "Dart", "Clojure"];
const merge = [...lang1, ...lang2];
console.log(merge); // [ 'JavaScript', 'Python', 'C++', 'C#', 'Dart', 'Clojure' ]

这个是扩展运算符 ... 的比较经典的使用方法。更多扩展运算符的使用请参阅《ES6中扩展运算符的8种用法

6. 获取数组最后一项

当需要获取数组的最后一个元素时,最简短的方式是使用 slice 方法,只需将负数作为参数,它就会从最后一个索引开始对数组进行切片。

const array = [1, 3, 4, 5, 6, 9, 10, 12];
console.log(array.slice(-1)); // [12]
console.log(array.slice(-2)); // [10, 12]
console.log(array.slice(-4)); // [6, 9 ,10, 12]

7. 对象合并

将多个对象合并为一个。在 JavaScript 中,可以使用 ... 方法,这也是实现此需求最简洁的方法,如下:

const article1 = { title: "JavaScript特征", lang: "js" };
const article2 = { view: 10, time: "2021", lang: "javascript" };
const article = {
    ...article1,
    ...article2,
};
console.log(article); // { title: 'JavaScript特征', lang: 'javascript', view: 10, time: '2021' }

如有相同的属性,后面的会覆盖前面的。

8. 数组最大数最小数

这是一种查找数组中最大数或者最小数的方法之一,也可以通过循环来实现这一需求,下面分享一种简单方法:

const findMax = (arrayNumbers) => Math.max(...arrayNumbers);
const findMin = (arrayNumbers) => Math.min(...arrayNumbers);
const arrNumbers = [10, 13, 1, 48, 6, 216];
console.log(findMax(arrNumbers)); // 216
console.log(findMin(arrNumbers)); // 1

JavaScript 的灵活性使得编程充满技巧,作为 JavaScript 开发人员,要感觉自己就是一个魔术师,合理灵活的利用其技巧,不段提升对代码的组织能力。

本文文字及图片出自 InfoQ


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK