优雅编码 | javascript代码优化的15个小知识

虽然已经和 javascript 打交道很长时间了,但有时可能没有更新最新的特性,这些特性可以解决日常的一些问题,而不需要编写额外的代码。

在这里,收集总结了编写优雅代码的经验,对代码优化及review有一定的帮助。

1、如何在JavaScript中检查空字符串/undefined/null?

判断一个变量是否为空字符串、undefined、null,在与后台API联调时特别常见。

!!data

const items = ["", null, undefined];
for (const item of items) {
    console.log(!!item);
}

使用类型转换 Boolean(data)

const items = ["", null, undefined];
for (const item of items) {
    console.log(Boolean(item));
}

两种方法实现了相同的功能,将变量类型转换为布尔值。

  • 对于nullundefined0000""false,它将返回false
  • 对于字符串"0" 和空格" ",它返回true

2、小数四舍五入

这里列举四种实现方式

parseFloat

parseFloat() 函数解析一个参数(必要时先转换为字符串)并返回一个浮点数。

const FLOOR_NUMBER = 3.141592653;
console.log(parseFloat(FLOOR_NUMBER).toFixed(2));   // 3.14

Math.round

Math.round() 函数返回一个数字四舍五入后最接近的整数。

const FLOOR_NUMBER = 3.141592653;
console.log(Math.round(FLOOR_NUMBER * 100 + Number.EPSILON) / 100);

Number() 构造函数创建一个 Number 对象。

将字符串转换为十进制

const FLOOR_NUMBER = 3.141592653;
const strNumber = FLOOR_NUMBER.toFixed(2); // => '3.14'
console.log(Number(strNumber)); // => 3.14

使用Lodash

const _ = require("lodash");
const FLOOR_NUMBER = 3.141592653;
console.log(_.floor(FLOOR_NUMBER, 2));

3、对象数组按照指定key排序

实现的方式有几种,这里列举三种供参考

使用Lodash

Lodash 是一个一致性、模块化、高性能的 javascript 实用工具库,俗称下划线 _

_.sortBy(collection, [iteratees=[_.identity]])

创建一个元素数组。 以 iteratee 处理的结果升序排序。 这个方法执行稳定排序,也就是说相同元素会保持原始排序。 iteratees 调用1个参数: (value)。

const _ = require("lodash");
var users = [
    { user: "fred", age: 48 },
    { user: "barney", age: 36 },
    { user: "fred", age: 40 },
    { user: "barney", age: 34 },
];

_.sortBy(users, function (o) {
    return o.user;
}); // 结果为: [{ user: 'barney', age: 36 },{ user: 'barney', age: 34 },{ user: 'fred', age: 48 },{ user: 'fred', age: 40 }]

_.sortBy(users, ["user", "age"]); // 结果为: [{ user: 'barney', age: 34 },{ user: 'barney', age: 36 },{ user: 'fred', age: 40 },{ user: 'fred', age: 48 }]

_.sortBy(users, "user", function (o) {
    return Math.floor(o.age / 10);
}); // 结果为: [{ user: 'barney', age: 36 },{ user: 'barney', age: 34 },{ user: 'fred', age: 48 },{ user: 'fred', age: 40 }]

使用ES6

var users = [
    { user: "fred", age: 48 },
    { user: "barney", age: 36 },
    { user: "fred", age: 40 },
    { user: "barney", age: 34 },
];

// 按照age排序
const result = users.sort(function (a, b) {
    return a.age - b.age;
});
console.log(result);  // [{ user: 'barney', age: 34 }, { user: 'barney', age: 36 },{ user: 'fred', age: 40 },{ user: 'fred', age: 48 }]

4、对象遍历

每个ECMAScript版本都采用不同的方式遍历对象。

ES5 可以使用以下方法

  • Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

  • forEach() 方法对数组的每个元素执行一次给定的函数

const myinfo = { name: "devpoint", city: "Shenzhen" };
Object.keys(myinfo).forEach((key) => {
    console.log(key, "=", myinfo[key]);
}); 

ES6中可以使用 for...of

for...of语句在可迭代对象(包括 ArrayMapSetStringTypedArrayarguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

const myinfo = { name: "devpoint", city: "Shenzhen" };

for (const key of Object.keys(myinfo)) {
    console.log(key, "=", myinfo[key]);
}

ES8使用Object.entries()

Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

Object.entries(myinfo).forEach(([key, value]) => console.log(key, "=", value));

也可以这样:

for (const [key, value] of Object.entries(myinfo)) {
    console.log(key, "=", value);
}

使用Lodash

const _ = require("lodash");
const myinfo = { name: "devpoint", city: "Shenzhen" };

_.forEach(myinfo, (value, key) => {
    console.log(key, "=", value);
});

5、event.stopPropagation()、event.preventDefault() 和 return false 区别

event.stopPropagation() 阻止事件的冒泡方法,不让事件向 documen上蔓延,但是默认事件任然会执行,当你掉用这个方法的时候,如果点击一个连接,这个连接仍然会被打开;

event.preventDefault() 阻止默认事件的方法,调用此方法是,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素;

return false 比较暴力,会同时阻止事件冒泡也会阻止默认事件;写上此代码,连接不会被打开,事件也不会传递到上一层的父元素;可以理解为return false就等于同时调用了event.stopPropagation()event.preventDefault()

$(".header a").click(function (e) {
    event.stopPropagation(); //不会打印 devpoint ,但是页面会跳转;
});
$(".header").click(function () {
    console.log("devpoint"); 
});
$(".header").click(function () {
    console.log("devpoint"); 
});
$(".header a").click(function (e) {
    event.preventDefault(); // 页面不会跳转,但会打印 devpoint;
});

6、如何获取当前url

这是比较常见的,使用方法:window.location.href

7、如何判断对象是否存在某个KEY?

如判断对象中是否存在键值:title

使用操作符

const info = {
    title: "devpoint",
};
const detail = {
    content: "Hello",
};
const find = "title";
const result = find in info;
const result2 = find in detail;
console.log(result); // true
console.log(result2); // false

使用hasOwnProperty

const info = {
    title: "devpoint",
};
const detail = {
    content: "Hello",
};
const find = "title";
const result = info.hasOwnProperty(find);
const result2 = info.hasOwnProperty(detail);
console.log(result); // true
console.log(result2); // false

直接读取key值

const info = {
    title: "devpoint",
};
const detail = {
    content: "Hello",
};
const find = "title";
const result = info[find] !== undefined;
const result2 = detail[find] !== undefined;
console.log(result); // true
console.log(result2); // false

8、 如何插入元素到数组指定索引位置?

在特定索引位置附加1个元素,这里讨论的问题排除头部和尾部的情况,如在索引为2后面插入元素devpoint

const items = ["info", "name", "age", "day"];
const insertItem = "devpoint";
items.splice(2, 0, insertItem);
console.log(items); // [ 'info', 'name', 'devpoint', 'age', 'day' ]

附加多个元素,也是适用的。

const items = ["info", "name", "age", "day"];
const insert1 = "devpoint";
const insert2 = "https";
items.splice(2, 0, insert1, insert2);
console.log(items); // [ 'info', 'name', 'devpoint', 'https', 'age', 'day' ]

将1个数组所有元素附加到指定索引后面,如下:

const items = ["info", "name", "age", "day"];
const news = ["devpoint", "https"];
items.splice(2, 0, ...news);
console.log(items); // [ 'info', 'name', 'devpoint', 'https', 'age', 'day' ]

9、如何合并两个数组并删除重复项?

在开发中,合并数组并删除重复项是比较常见的需求。

使用Lodash

const _ = require("lodash");
const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020, 2021];
const newItem = _.union(item1, item2);
console.log(newItem); // [ 2021, 2022, 2023, 2019, 2020 ]

使用数组方法filtercontact

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020, 2021];

const tmpItem = item1.concat(item2); // [ 2021, 2022, 2023, 2019, 2020, 2021 ]
const newItem = tmpItem.filter((val, pos) => tmpItem.indexOf(val) === pos); // [ 2021, 2022, 2023, 2019, 2020 ]

使用set

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020, 2021];

const newItem = [...new Set([...item1, ...item2])]; // [ 2021, 2022, 2023, 2019, 2020 ]

10、如何在字符串中查找字符并替换为空?

使用replace

let str = "developpoint";
const findStr = "elop";
str = str.replace(findStr, ""); // devpoint
console.log(str);

使用正则表达式

let str = "developpoint";
const findStr = "elop";
str = str.replace(new RegExp(findStr), "");

11、如何在数组中追加新的元素?

在过去的JavaScript版本中,是通过使用apply方法来实现的。

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020];

Array.prototype.push.apply(item2, item1);
console.log(item2); // [ 2019, 2020, 2021, 2022, 2023 ]

使用ES6

const item1 = [2021, 2022, 2023];
const item2 = [2019, 2020];

item2.push(...item1);
console.log(item2); // [ 2019, 2020, 2021, 2022, 2023 ]

12、如何判断一个对象是否为数组?

判断一个对象是否为数组,使用场景也是比较常见的,同样可以使用Lodash,这里不做详细介绍了,有兴趣可以去看看文档

在ES6之前的版本可以通过下面的方式来判断是否为数组(可以兼容旧的浏览器),为了方便,三种方式写在一起。

const arrayYears = [2021, 2022, 2023];
const objYears = { value: "2021" };

const isArray = (() => {
    return {
        byInstanceof: (array) => {
            return array instanceof Array;
        },
        byConstructor: (array) => {
            return array.constructor.toString().indexOf("Array") > -1;
        },
        byPrototype: (array) => {
            return Object.prototype.toString.call(array) === "[object Array]";
        },
    };
})();

console.log(isArray.byInstanceof(arrayYears)); // true
console.log(isArray.byConstructor(arrayYears)); // true
console.log(isArray.byPrototype(arrayYears)); // true

console.log(isArray.byInstanceof(objYears)); // false
console.log(isArray.byConstructor(objYears)); // false
console.log(isArray.byPrototype(objYears)); // false

使用ES6

使用ES6就简洁多了。

const arrayYears = [2021, 2022, 2023];
const objYears = { value: "2021" };

const isArray = (array) => {
    return Array.isArray(array);
};
console.log(isArray(arrayYears)); // true
console.log(isArray(objYears)); // false

13、如何解析URL中的参数?

当在处理URL的时候,经常遇到需要解析URL中的参数,并获取其值。

使用正则

const getQueryStringParams = (query) => {
    return query
        ? (/^[?#]/.test(query) ? query.slice(1) : query)
              .split("&")
              .reduce((params, param) => {
                  const [key, value] = param.split("=");
                  params[key] = value
                      ? decodeURIComponent(value.replace(/\+/g, " "))
                      : "";
                  return params;
              }, {})
        : {};
};
const params = getQueryStringParams("?wd=devpoint"); // { wd: 'devpoint' }
console.log(params); // { wd: 'devpoint' }

使用URLSearchParams

URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串。拥有包括appenddeleteentries等方法,详见介绍

const getQueryStringParams = (strUrl) => {
    return new URL(strUrl).searchParams;
};
const url = "https://www.baidu.com/s/?wd=devpoint";
const params = getQueryStringParams(url); // URLSearchParams { 'wd' => 'devpoint' }
console.log(params.get("wd")); // devpoint

14、如何获取对象的长度(key数量)?

大部份情况下,我们会检查数组的长度,但如果要获取对象的长度呢?下面两种方法是获取对象长度的最佳方法。

使用Lodash

const _ = require("lodash");
const obj = {
    title: "devpoint",
    city: "Shenzhen",
    type: "blog",
};
const objSize = _.size(obj);
console.log(objSize); // 3

使用ES6

const obj = {
    title: "devpoint",
    city: "Shenzhen",
    type: "blog",
};
const objSize = Object.keys(obj).length;
console.log(objSize); // 3

15、如何将字符串转换为对象数组?

当从无法控制的第三方API获取一些数据时,就会出现这种情况。如何将字符串转换为对象数组以在应用程序中更好的使用?以下是获得此结果的最简单方法。

const apiData = "Option 1|false|Option 2|false|Option 3|false|Option 4|true";

const formatToArray = (str) => {
    return str.split("|").reduce((arrayResult, item, index, arrData) => {
        if (index % 2 === 0) {
            const [option, value] = [item, JSON.parse(arrData[index + 1])];
            arrayResult.push({ option, value });
        }
        return arrayResult;
    }, []);
};

console.log(formatToArray(apiData));

输出的数据格式为:

[
  { option: 'Option 1', value: false },
  { option: 'Option 2', value: false },
  { option: 'Option 3', value: false },
  { option: 'Option 4', value: true }
]

javascript的灵活性,使得编写优雅的代码方法多种多样,需要去深入研究并总结,今天的分享就到此。