IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    开发中遇到的一些技巧和坑

    richenlin发表于 2016-05-11 16:33:26
    love 0

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

    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 求star、求pull、求同玩。。。

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



沪ICP备19023445号-2号
友情链接