总结了一些常见、常用的JS写法小技巧,有的是为了性能考虑,有的则是让代码更简洁,总之就是为了写出更优雅的JS,小结了一下,希望都能有所收获。
(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;
}
}
JavaScript是一门弱类型语言,表达式运算赋值等操作都会导致类型转换。
在JavaScript中, “==” 叫做相等运算符, " === " 叫做严格运算符。
" == " 表示只要值相等即可为真,而 " === "则要求不仅值相等,而且也要求类型相同。
"=="的运算规则是:
"==="的运算规则:
不同类型值:如果两个值的类型不同,直接返回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
(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
(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等,也是可以帮助写出简洁高效的代码。
例如:
// 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');
}
}
例如:
// 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');
}
}
例如:根据 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);
}
例如:检查是否所有水果都是红色
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
}
还有很多小技巧,在后续遇到了就补充吧。