提高JS代码优雅性的小技巧

提高JS代码优雅性的小技巧

总结了一些常见、常用的JS写法小技巧,有的是为了性能考虑,有的则是让代码更简洁,总之就是为了写出更优雅的JS,小结了一下,希望都能有所收获。

1、按强类型风格写代码

(1)定义变量的时候要指明类型,告诉JS解释器这个变量是什么数据类型的,而不要让解释器去猜。

例如:
	    var a,b,c; // bad,定义变量时没有指明类型
   		var a ="", b=[], c={}; // good

(2)不要随意地改变变量的类型。

例如:
	let a = ""; 
	a = 100; // bad,改变了定义变量时的类型

	let b = 5;  
	b = 200; // good

(3)函数的返回类型应该是要确定的。

例如:

	// bad,返回了不同的数据类型
	function getResult(cont) {
		if(count < 0) {
			return "";
		} else {
			return count * 10;
		}
	}

	// good
	function getResult(cont) {
		if(count < 0) {
			return -1;
		} else {
			return count * 10;
		}
	}

2、避免==的使用

JavaScript是一门弱类型语言,表达式运算赋值等操作都会导致类型转换。
在JavaScript中, “==” 叫做相等运算符, " === " 叫做严格运算符。
" == " 表示只要值相等即可为真,而 " === "则要求不仅值相等,而且也要求类型相同。

"=="的运算规则是:

  • 原始类型的值:数据转换成数值类型再进行比较。字符串和布尔值都会转换成数值。
  • 对象与原始类型值比较:对象转化成原始类型的值,进行比较。
  • undefined和null:undefined和null与其他类型的值比较时,结果都为false,它们互相比较时结果为true。

"==="的运算规则:

  • 不同类型值:如果两个值的类型不同,直接返回false。

  • 同一类的原始类型值:同一类型的原始类型的值(数值number、字符串string、布尔值boolean)比较时,值相同就返回true,值不同就返回false。

  • 同一类的复合类型值/高级类型:两个复合类型(对象Object、数组Array、函数Funtion)的数据比较时,不是比较它们的值是否相等,而是比较它们是否指向同一个对象。即“地址指针”是否相等。

  • undefined和null:undefined 和 null 与自身严格相等。

      null === null            // true
      undefined === undefined  // true
      undefined === null       // true
    

(1)使用==有时候会达不到预期的结果,埋下隐患。

例如:
	
	0  == ''          // true
	0  == '0'         // true
	'' == 0           // true
	'' == '0'         // false
	' \t\r\n ' == 0   // true

	false == '0'        // true
	false == 'false'    // false
	false == undefined  // false
	false == null       // false
	null == undefined   // true
	true == 1           // true

	new String("abc") == "abc" // true
	new Boolean(true) == true  // true

(2)使用==在JSLint检查的时候是不通过的。

例如:
	if(a == b){} // JSLint的输出:Expected ‘===’ and instead saw ‘==’

(3)如果确定了变量的类型,那么就没必要使用==。

例如:

	var num = parseInt(value);
	if(num == 10){} // bad
	if(num === 10) {} // good

(4)如果类型不确定,那么应该手动做一下类型转换。

例如:

	var total = "5";
	if(total == 1) {} // bad
	if(parseInt(total) === 1){} // good

3、合并表达式

1)用三目运算符取代简单的if-else。

例如:

// bad
function getCount(count){
	if(count < 0) {
		return -1;
	} else {
	 return count * 100;
	}	
}

// good
function getCount(count){
	return count < 0 ? return -1 : count * 100;
}

利用三目运算符,比写一个if-else看起来清爽多了。而且,如果写的是if-else,压缩工具也会把它改三目运算符的形式。

(2)连等:利用赋值运算表达式返回所赋的值,并且按从右到左的顺序执行代码。

例如: one = two = three = {...}

(3)自增: 利用自增也可以简化代码。

例如:

	chatService.sendMessage(localMsgId++, msgContent); // 每发出一条消息,localMsgId 就自增1

4、使用ES6简化代码

(1)使用箭头函数取代小函数。

例如:排序

var nums = [4, 8, 1, 9, 0];

nums.sort(function(a, b){ // bad
	return b - a;
});

nums.sort(a, b => b - a); // good: es6

(2)使用ES6的class。

例如:

function Person(name, age){
    this.name = name;
    this.age = age;
}
Person.prototype.addAge = function(){
    this.age++;
};
Person.prototype.setName = function(name){
    this.name = name;
};

// good: es6
class Person{
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
    addAge(){
        this.age++;
    }
    setName(name){
        this.name = name;
    }
}

es6的class可以很方便地实现继承、静态的成员函数。

(3)字符串拼接:用字符串模板代替"+"

例如:url拼接

	var page = 5, type = encodeURIComponet("#js");

	var url = "/list?page=" + page + "&type=" + type;

	var url = `/list?page=${page}&type=${type}`; // es6

(4)块级作用域变量:用let代替var定义变量。

例如:打印1,2,3,4

	var arr = [];
	for(var i = 0; i < 4; i++){
	    arr.push(function(){
	        console.log(i);
	    });
	}
	for(var j = 0; j < arr.length; j++){
	    arr[j]();
	}

想要得到到结果:1,2,3,4,实际结果: 4,4,4,4,这是因为闭包都是用的同一个i变量。

解决办法一:

var arr = [];
for(var i = 0; i < 4; i++){
    !function(k){
        arr.push(function(){
            console.log(k);
        });
    }(i);
}
for(var j = 0; j < arr.length; j++){
    arr[j]();
}

解决办法二:利用es6的let

	var arr = [];
	for(let i = 0; i < 4; i++){
	    arr.push(function(){
	        console.log(i);
	    });
	}
	for(var j = 0; j < arr.length; j++){
	    arr[j]();
	}

显然第二种解决办法就简单得多,因为for循环里面有个大括号,大括号就是一个独立的作用域,let定义的变量在独立的作用域里面它的值也是独立的。

除了以上几点,ES6还有其它一些比较好用的功能,如Object的assign,Promise等,也是可以帮助写出简洁高效的代码。

5、多重判断时使用 Array.includes

例如:

// normal
function test(fruit) {
  if (fruit == 'apple' || fruit == 'strawberry') {
    console.log('red');
  }
}
// better
function test(fruit) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
  if (redFruits.includes(fruit)) {
    console.log('red');
  }
}

6、更少的嵌套,尽早 return

例如:

// normal
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
  if (fruit) { // 条件 1: fruit 必须有值
    if (redFruits.includes(fruit)) { // 条件 2: 必须是red的
      console.log('red');
      if (quantity > 10) { // 条件 3: quantity大于10
        console.log('big quantity');
      }
    }
  } else {
    throw new Error('No fruit!');
  }
}

// better
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
  if (!fruit){ // 条件 1: 尽早抛出错误
	 throw new Error('No fruit!');
  }
  if (!redFruits.includes(fruit)) { // 条件 2: 当水果不是红色时停止继续执行
	return; 
  } 
  console.log('red');
  if (quantity > 10) {  // 条件 3: 必须是大质量的
    console.log('big quantity');
  }
}

7、倾向于遍历对象而不是 Switch 语句

例如:根据 color 打印出水果

// normal
function test(color) {
  switch (color) { // 使用条件语句来寻找对应颜色的水果
    case 'red':
      return ['apple', 'strawberry'];
    case 'yellow':
      return ['banana', 'pineapple'];
    case 'purple':
      return ['grape', 'plum'];
    default:
      return [];
  }
}

// good-1
const fruitColor = {
  red: ['apple', 'strawberry'],
  yellow: ['banana', 'pineapple'],
  purple: ['grape', 'plum']
};
function test(color) {
  return fruitColor[color] || [];
}

// good-2
const fruitColor = new Map()
    .set('red', ['apple', 'strawberry'])
    .set('yellow', ['banana', 'pineapple'])
    .set('purple', ['grape', 'plum']);
function test(color) {
  return fruitColor.get(color) || [];
}

// good-3
const fruits = [
    { name: 'apple', color: 'red' }, 
    { name: 'strawberry', color: 'red' }, 
    { name: 'banana', color: 'yellow' }, 
    { name: 'pineapple', color: 'yellow' }, 
    { name: 'grape', color: 'purple' }, 
    { name: 'plum', color: 'purple' }
];
function test(color) {
  return fruits.filter(f => f.color == color);
}

8、对 所有/部分 判断使用 Array.every & Array.some

例如:检查是否所有水果都是红色

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];

// normal
function test() {
  let isAllRed = true;
  for (let f of fruits) { // 条件:所有水果都是红色
    if (!isAllRed) break;
    isAllRed = (f.color == 'red');
  }
  console.log(isAllRed); // false
}

// good-1
function test() {
  const isAllRed = fruits.every(f => f.color == 'red');
  console.log(isAllRed); // false
}

// good-2
function test() {
  const isAnyRed = fruits.some(f => f.color == 'red'); // 条件:任何一个水果是红色
  console.log(isAnyRed); // true
}

还有很多小技巧,在后续遇到了就补充吧。

你可能感兴趣的:(JavaScript,web前端)