学以致用的 JavaScript 技巧

338 阅读4分钟

展开操作符 ...

实现对象和数组的浅拷贝:

const numbers = [1,2,3,4,5]
const person = {
  name: 'Amanda',
  active: false
}
console.log([...numbers, 6, 7])   //  [1, 2, 3, 4, 5, 6, 7]

console.log({...person, active: true})   // {name: 'Amanda', active: true}

console.log({...person, age: 100})   //{name: 'Amanda', active: false, age: 100}

结合 && 实现有条件地向对象添加属性:

const condition = true;
const person = {
  name: 'John Doe',
  ...(condition && { age: 16 }),
};
console.log(person)  // {name: 'John Doe', age: 16}

解构赋值

// 结构对象
const fruit = {name: 'apple', price: 1}
const { price } = fruit   // 1

// 多层结构
const fruitPrices = {
  apples: {
    red: 1,
    green: 2
  }
}
const {apples: { red }} = fruitPrices
console.log(red)    // 1

// import 结构
import { debounce } from 'lodash'

// 函数参数结构
function printPrice({price}){
  console.log(price)
}
printPrice(fruit)

// 数组结构
const nums = [3,1,2]
const [first] = nums.sort()
console.log(first)   // 1

// 交换
let a = 5;
let b = 8;
[a,b] = [b,a]
console.log(a,b)    // 8,5

逻辑或(||) VS 空值合并运算符(??)

|| 运算符左侧是空字符串或 false 或 0 等 falsy 值的时候,直接取运算符右侧值。其中 falsy 值包括:falsenullNaN0、空字符串(“” 、'')、undefined

const a = 0 || 10
console.log(a)  
// 10
const b = 0 || 0
console.log(b)  
// 0
const c = 0 || null
console.log(c)  
// null

?? 空值合并运算符是 ES2020 引入,只有运算符左侧是 nullundefined 时,才会返回右侧的值。

const a = 0 ?? 10
console.log(a)  
// 0
const b = undefined || 0
console.log(b)  
// 0
const c = null || null
console.log(c)  
// null

扁平化嵌套数组

Array.prototype.flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

const newArray = arr.flat([depth])
  • depth 可选
  • 指定要提取嵌套数组的结构深度,默认值为 1。
const arr1 = [0, 1, 2, [3, 4]];

console.log(arr1.flat());
// [0, 1, 2, 3, 4]

const arr2 = [0, 1, 2, [[[3, 4]]]];

console.log(arr2.flat(2));
// [0, 1, 2, [3, 4]]

如果你不知道要扁平的数组的具体深度,只想完全扁平这个嵌套数组里的成员话,可以使用 Infinity 这个值。

const veryDeep = [[1, [2, 2, [3,[4,[5,[6]]]]], 1]]; 

veryDeep.flat(Infinity);   // [1, 2, 2, 3, 4, 5, 6, 1]

获取数组中的最后 N 项

如果要获取数组的末尾元素,可以使用slice方法,得到数组。

const array = [0, 1, 2, 3, 4, 5, 6, 7] 
console.log(array.slice(-1))
// [7]

console.log(array.slice(-2))
// [6, 7]

console.log(array.slice(-3))
// [5, 6, 7]

使用 Array.prototype.at()at() 方法接收一个整数值并返回该索引的项目,允许正数和负数。负整数从数组中的最后一个项目开始倒数。

const array = [0, 1, 2, 3, 4, 5, 6, 7] 
console.log(array.at(-1))
// 7

console.log(array.at(-2))
// 6

console.log(array.at(-3))
// 5

使用 length 缩短数组

const array = ["A", "B", "C", "D", "E", "F"]

array.length = 2
console.log(array)     // ["A", "B"]

// 清空数组
array.length = 0
console.log(array)     // []

使用 Set 去重

const ReDuplicates = array => [...new Set(array)];
// const ReDuplicates = array => Array.from(new Set(array))

console.log(ReDuplicates([200,200,300,300,400,500,600,600])) 
// [200,300,400,600]

可选链操作符 (?.)

你是不是也讨厌这种错误提示:TypeError: Cannot read property ‘foo’ of null, 可选链操作符 (?.) 为了解决这类问题而引入的:

const book = { id:1, title: 'Title', author: null };

console.log(book.author.age)     // throws error

console.log(book.author && book.author.age);   // returns null (no error)

// with optional chaining
console.log(book.author?.age);    // returns undefined

// or deep optional chaining
console.log(book.author?.address?.city);   // returns undefined

可选链操作符 (?.)与函数一起使用:

const person = {
  firstName: 'Haseeb',
  lastName: 'Anwar',
  printName: function () {
    return `${this.firstName} ${this.lastName}`;
  },
};

console.log(person.printName());        // returns 'Haseeb Anwar'

console.log(persone.doesNotExist?.());    // returns undefined

语法:

obj?.prop        // 对象属性
obj?.[expr]      // 对象属性
arr?.[index]     // 访问数组
func?.(args)     // 访问函数

string 和 number 的转换

使用 + 运算符快速将 string 转为 number 类型:

const stringNumer = '123';

console.log(+stringNumer);            // returns integer 123

console.log(typeof +stringNumer);     // returns 'number'

使用 + '' 运算符快速将 number 转为 string 类型:

const myString = 25 + '';

console.log(myString);              // returns '25'

console.log(typeof myString);       // returns 'string'

传递对象作为参数

const createProduct = ({name, description, price}) => {
  // Create the product
}
createProduct({
  name: 'Pepperoni Pizza',
  description: 'Hot, crispy and tasty!',
  price: 15.99
})

传递对象作为参数有许多好处:

  • 参数的顺序不再重要,使得开发者专注于提供高质量代码,而不是反复检查功能定义
  • 很方便的增加新的参数变量

switch/case中数字范围使用

使用带有数字范围的switch/case语句:

function getCategory(age) {  
    let category = "";  
    switch (true) {  
        case isNaN(age):  
            category = "not an age";  
            break;  
        case (age >= 50):  
            category = "Old";  
            break;  
        case (age <= 20):  
            category = "Baby";  
            break;  
        default:  
            category = "Young";  
            break;  
    };  
    return category;  
}  
getCategory(5);  // will return "Baby"

格式化 JSON 输出

const profile = {
  name: 'Mary',
  age: 28,
  dateJoined: '11-01-2019'
};

console.log(JSON.stringify(profile, null, 2))

//{
//  "name": "Mary",
//  "age": 28,
//  "dateJoined": "11-01-2019"
//}

执行时间

方式一:

console.time('timer-1')
let sum = 0
for(let i=0;i<10000;i++){
  sum += i
}
console.timeEnd('timer-1')   // timer-1: 0.221923828125 ms

方式二:

const firstTime = performance.now();
let sum = 0
for(let i=0;i<10000;i++){
  sum += i
}
const secondTime = performance.now();
console.log(`The something function took ${secondTime - firstTime} milliseconds.`); 
// The something function took 0.3999999910593033 milliseconds.

收集来自:
# 10 Modern JavaScript Tricks Every Developer Should Use
# 20个提升效率的JS简写技巧
# 10 Clever JavaScript Tricks That Every Developer Should Know
# 掌握这20个JS技巧,做一个不加班的前端人
# 15 Magical JavaScript Tips for Every Web Developer
# my 5 MOST USED javascript tricks # 8 JavaScript Tips & Tricks That No One Teaches 🚀 # 2022前端应该掌握的10个 JS 小技巧