你可能不知道的19个JavaScript编码技巧

这篇文章收集了JavaScript中一些常见的和新颖的编码技巧,并基于ES6增加了新的内容;附有长短版本的比较,以便读者更好地理解,所有的JavaScript开发者不防都看一下。

1、条件操作符

使用条件操作符可以在一行代码中完成 if…else 语句的功能。

const x = 20;
let answer;
if (x > 10) {
    answer = 'is greater';
} else {
    answer = 'is lesser';
}

使用条件操作符:

const answer = x > 10 ? 'is greater' : 'is lesser';

2、短路验证1

当把一个变量的值赋给另一个变量时,有时需要验证这个变量是否为null、undefined或为空。当然你可以在if语句中添加多个条件完成验证,但不妨试试下面这个简写版本。

if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
     let variable2 = variable1;
}

使用短路运算符:

let variable2 = variable1  || ' ';

如果有怀疑可在浏览器控制台粘贴如下代码进行测试:

let variable1;
let variable2 = variable1  || '';
console.log(variable2 === ''); // 打印 true

variable1 = 'foo';
variable2 = variable1  || '';
console.log(variable2); // 打印 foo

3、变量声明

当需要同时声明多个变量时,使用简写的形式能够节省不少的时间和空间,不仅JavaScript中如此,不少语言都支持类似的写法。

let x;
let y;
let z = 3;

简写形式:

let x, 
     y, 
     z=3;

(注:原文中的形式为

let x, y, z=3;

我认为是不妥的,当变量较多时,会变得不易阅读;采用上面的形式,容易阅读,且方便对变量添加注释。)

4、如果为真

这算是非常常见的,但仍然提一下。

if (likeJavaScript === true)

简写:

if (likeJavaScript)

如果非真:

if (likeJavaScript !== true)

简写:

if ( !likeJavaScript )

5、for循环简写

在某些情况下,可以使用for-in语句简化for循环。

for (let i = 0; i < allImgs.length; i++)

简写:

for (let index in allImgs)

数组的forEach()方法简写(适用于代码重用的情况下):

function logArrayElements(element, index, array) {
  console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements);
// 控制台输出:
// a[0] = 2
// a[1] = 5
// a[2] = 9

6、短路验证2

下面的6行代码实现当预期参数为null或undefined时,赋给变量一个默认值。如果我们使用短路逻辑操作符的话,只需要一行代码即可。

let dbHost;
if (process.env.DB_HOST) {
  dbHost = process.env.DB_HOST;
} else {
  dbHost = 'localhost';
}

简写:

const dbHost = process.env.DB_HOST || 'localhost';

7、大数的指数形式缩写

for (let i = 0; i < 10000; i++) {}

指数形式:

for (let i = 0; i < 1e4; i++) {}

//1e0 === 1;
//1e1 === 10;
//1e2 === 100;
//1e3 === 1000;
//1e4 === 10000;
//1e5 === 100000;

8、对象属性简写

ES6给对象字面量添加了几个重要的便利拓展,其中一个就是简约属性。

let x = 2, y = 3;
let obj = {
	x: x,
	y: y
};

如果x: x让你感到冗余,那么有个好消息。如果你需要定义一个名称和词法标识符一致的属性,你可以将它从x: x缩写为x

let x = 2, y = 3;
let obj = {
	x,
	y
};

9、箭头函数缩写

经典函数的原始形式是容易书写和阅读的,但一旦将其嵌套在其他函数的调用中,就会显得冗长而混乱。ES6中新的箭头函数为我们提供了新的解决方案。(关于ES6的内容建议读者参看《你所不知道的JS:ES6及未来》:https://github.com/getify/You-Dont-Know-JS/blob/1ed-zh-CN/es6%20&%20beyond/ch2.md)

function sayHello(name) {
  console.log('Hello', name);
}

setTimeout(function() {
  console.log('Loaded')
}, 2000);

list.forEach(function(item) {
  console.log(item);
});

使用箭头函数:

sayHello = name => console.log('Hello', name);

setTimeout(() => console.log('Loaded'), 2000);

list.forEach(item => console.log(item));

10、隐式 return

return 是我们返回函数最终结果的常用关键词,一个单语句的箭头函数会隐式地返回结果(该函数必须省略大括号 {} 才能省略 return 关键词)。

function calcCircumference(diameter) {
  return Math.PI * diameter
}

简写:

calcCircumference = diameter => (
  Math.PI * diameter;
)

11、参数默认值

你可以在函数体中使用 if 语句为参数指定默认值,而在ES6中,你可以在函数声明中定义参数默认值。

function volume(l, w, h) {
  if (w === undefined)
    w = 3;
  if (h === undefined)
    h = 4;
  return l * w * h;
}

简写:

volume = (l, w = 3, h = 4 ) => (l * w * h);

volume(2) //output: 24

12、模板字面量

ES6提供了一种新的方式来将多个变量连接成字符串,而不再需要蠢蠢地使用 '+' 这种方式,你需要使用的是反引号以及 ${variable_name}

const welcome = 'You have logged in as ' + firstname + ' ' + lastname + '.';

const db = 'http://' + host + ':' + port + '/' + database;

简写:

const welcome = `You have logged in as ${first} ${last}`;

const db = `http://${host}:${port}/${database}`;

13、解构赋值简写

如果你使用了某种流行的web框架,那么很有可能你会以对象字面量的形式在组件与API间传递信息。一旦数据对象到达组件,即需要解包。

const observable = require('mobx/observable');
const action = require('mobx/action');
const runInAction = require('mobx/runInAction');

const store = this.props.store;
const form = this.props.form;
const loading = this.props.loading;
const errors = this.props.errors;
const entity = this.props.entity;

简写:

import { observable, action, runInAction } from 'mobx';

const { store, form, loading, errors, entity } = this.props;

也可以自定变量名:

const { store, form, loading, errors, entity:contact } = this.props;

14、多行字符串简写

const lorem = 'the first line.\n\t'
    + 'the second line.\n\t'
    + 'the third line.\n\t';

使用反引号简写:

const lorem = `the first line.
    the secong line.
    the third line.`;

15、使用拓展操作符简写

ES6中引入的拓展操作符(…)有多种使用场景,使得JavaScript代码更加高效易用。例如可用来替代特定的数组方法。

// 连接数组
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);

// 克隆数组
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()

简写:

// 连接数组
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]

// 克隆数组
const arr = [1, 2, 3, 4];
const arr2 = [...arr];

与 concat() 方法不同的是,使用拓展操作符可以在数组的任意位置插入另一个数组:

const odd = [1, 3, 5 ];
const nums = [2, ...odd, 4 , 6];

也可将拓展运算符与解构符号组合使用:

const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a) // 1
console.log(b) // 2
console.log(z) // { c: 3, d: 4 }

16、强制性参数说明

在JavaScript中,未传值的函数参数会被设置为 undefined ,而在其他语言中会直接抛出警告或错误。为了保证参数能够被赋值,我们可以使用 if 语句抛出一个错误;或者我们也可以使用强制参数说明。

function foo(bar) {
  if(bar === undefined) {
    throw new Error('Missing parameter!');
  }
  return bar;
}

简写:

mandatory = () => {
  throw new Error('Missing parameter!');
}

foo = (bar = mandatory()) => {
  return bar;
}

17、Array.find

在以前,我们通常会使用 for 循环来实现查找,而在ES6中,引入了一种新的数组方法 find()。

const pets = [
  { type: 'Dog', name: 'Max'},
  { type: 'Cat', name: 'Karl'},
  { type: 'Dog', name: 'Tommy'},
]

function findDog(name) {
  for(let i = 0; i<pets.length; ++i) {
    if(pets[i].type === 'Dog' && pets[i].name === name) {
      return pets[i];
    }
  }
}

简写:

pet = pets.find(pet => pet.type ==='Dog' && pet.name === 'Tommy');
console.log(pet); // { type: 'Dog', name: 'Tommy' }

18、Object[key]

你知道 Foo.bar 可以写成 Foo[‘bar’] 吗?看起来似乎我们完全没有理由这么写,但这个符号可为编写可重用代码提供构建块。

考虑下面这个简化的验证函数:

function validate(values) {
  if(!values.first)
    return false;
  if(!values.last)
    return false;
  return true;
}

console.log(validate({first:'Bruce',last:'Wayne'})); // true

这个函数完美地实现了所需功能,但是考虑下面的场景。如果现在有许多表单需要使用这样的函数进行验证,但却有不同的字段。如果有一个通用的函数能够在运行时进行配置岂不是非常好?

// object validation rules
const schema = {
  first: {
    required:true
  },
  last: {
    required:true
  }
}

// universal validation function
const validate = (schema, values) => {
  for(field in schema) {
    if(schema[field].required) {
      if(!values[field]) {
        return false;
      }
    }
  }
  return true;
}


console.log(validate(schema, {first:'Bruce'})); // false
console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // true

这样我们就拥有了一个可在所有表单中重复使用的验证函数。

19、双按位非

可以使用双按位非运算符来代替 Math.floor(),其执行速度相比起来更快。

Math.floor(4.9) === 4  //true

使用双按位非:

~~4.9 === 4  //true

发表评论

电子邮件地址不会被公开。