尽量使用模板字符串而非+号连接
let test = 'test string';
let str = 'this is a '+ test;
let str2 = `this is a ${test}`;//推荐用法,注意这里的`号不是单引号
因为模板字符串为es6的语法,不建议在前端js使用,因为目前浏览器对es6支持不完整
善于使用逻辑运算符来简化代码
** !!**
let obj = null;
let boolean = !!(''); //使用两个逻辑非可以获取准确的布尔值结果
** ||**
if(obj === null || obj === '' || obj === undefined || obj === 0){
obj = '';
}
简化为:
obj = obj || '';//此处注意obj的值在什么情况下是false
** &&**
if(obj !== null){
obj = 'has value';
}
简化为:
obj !== null && (obj = 'has value');
** ~**
if(str.indexOf('a') > -1){
...
}
简化为:
if(~str.indexOf('a')){
...
}
多条件分支语句的简化
多条件分支语句如果执行逻辑类似或相同时,可以使用简化写法。(逻辑不同也可以,但需要提取为独立的处理方法)
if写法
if(flag == 1){
retrun test1();
}else if(flag == 2){
return test2();
}else if(flag == 3){
return test3();
}else if(flag == 4){
return test4();
}else if(flag == 5){
retrun test5();
......
}else{
retrun test();
}
switch写法
switch(flag){
case 1:
retrun test1();
break;
case 2:
retrun test2();
break;
case 3:
retrun test3();
break;
case 4:
retrun test4();
break;
case 5:
retrun test5();
break;
......
default:
retrun test();
break;
}
上述语句都可以简写为:
let caseList = {1: test1, 2: test2, 3: test3, 4: test4, 5: test5 ......};
if(flag && flag in caseList){
return caseList[flag] (); //此处为了markdown正常显示,多打了一个空格
} else {
retrun test();
}
使用Promise.all来处理批量异步(无依赖)
某些情况下我们需要循环进行异步处理,很多人这样写:
for(let n in obj){
await this.model.where({id: obj[n]['id']}).update({status: 1});
}
在并发量大或者数据库数据量大的情况下,理论上的处理时间和为 (单个异步处理时间 * obj.length),会出现性能问题,推荐的写法是:
let ps = [];
for(let n in obj){
ps.push(this.model.where({id: obj[n]['id']}).update({status: 1}));//将异步事件放入数组
}
await Promise.all(ps);//并行处理
理论上处理时间和为 max(每个异步处理时间)
无依赖是指,下次循环不需要依赖当前循环的异步事件结果。如果有依赖此方法不适用
慎用连续赋值
一个例子:
let a = {"n" : 1};
let b = a;
a.x = a = {"n": 2};
console.log(a.x);//undefined
console.log(b.x);//{"n": 2}
乍一看,很容易弄错结果,以为a.x的值是{“n”: 2};其实不然,因为.运算符比赋值运算符优先级高,所以a.x赋值后,a再次赋值,指针变化了,a.x属性丢失
推荐写法:
let a = {"n" : 1};
let b = a;
a.x = {"n": 2};
a = {"n": 2}; //此处明显看出a的指针变化,x属性丢失
console.log(a.x);//undefined
console.log(b.x);//{"n": 2}
箭头函数内部无法使用 async/await
错误代码:
return promise.then(data => {
let info = await this.model.find(); //错误
...
});
正确代码:
return promise.then(data => {
return this.model.find();
}).then(info => {
...
});
空模型实例化后仅可以工作在mysql数据源
M('').query('select * from test'); //仅适用于mysql
mongoDb不能使用空模型,必须有对应的实体类:
M('Test').query('db.test.findOne()');
super不能和async/await并存
错误代码:
if(true){
await this.model.where({id:1}).update({name: 'test'});
}
return super.indexAction();//此处使用到了super调用父类方法,但在上面的语句中使用了await,被babel编译之后,导致作用域混乱,控制器实例化失败
正确代码:
let promise = getPromise();
if(true){
promise = this.model.where({id: 1}).update({name: 'test'});
}
return promise.then(() => {
return super.indexAction();//注意此处的super在箭头函数内,绑定的作用域为控制器
});
错误代码2:
await super.test(); //await被babel编译后成为Generator函数,在函数体内调用super导致作用域混乱
return this.render();
正确代码2:
return super.test().then(() => this.render());
extend函数的浅继承和深继承
extend函数是ThinkNode框架提供的一个非常有用的函数,来自于jQuery。可以实现对象和数组的继承和克隆。但是在使用中一定要注意浅继承和深继承的区别。
浅继承举例:
let data = {"aa": {"qq": 555555}};
let temp = extend(false, {}, data);//第一个参数为false,浅继承
temp.aa.qq = 222222;
console.log(data); //{ aa: { qq: 222222 } } //原始对象data被污染
console.log(temp); //{ aa: { qq: 222222 } }
深继承举例:
let data = {"aa": {"qq": 555555}};
let temp2 = extend({}, data); //深继承
temp2.aa.qq = 222222;
console.log(data); //{ aa: { qq: 555555 } } //原始对象未被污染
console.log(temp2); //{ aa: { qq: 222222 } }
区别是浅继承仅仅复制了父对象的属性值(基础数据类型),如果父对象的属性值为一个对象(或数组),仅仅是赋值(指针指向)而非复制;