开发中遇到的一些技巧和坑
发布于 1 个月前 作者 richenlin 730 次浏览 来自 分享

尽量使用模板字符串而非+号连接

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 } }

区别是浅继承仅仅复制了父对象的属性值(基础数据类型),如果父对象的属性值为一个对象(或数组),仅仅是赋值(指针指向)而非复制;

ps

我们团队的框架 https://github.com/richenlin/thinknode 欢迎start和发pull

团队求靠谱Node开发工程师、测试工程师,地标北京

回到顶部