Extreme Thinking
JS里的进阶技巧

2015-04-26


Table of Content:

    45个实用的JavaScript小贴士、小技巧和最佳实践, 英文原版45 Useful JavaScript Tips, Tricks and Best Practices

    1. 布尔表达式的结果与double negation(!!)

    这些值在布尔表达式中结果都为false: null, undefined, 空字符串"", 0, NaN, 其他都为true, 包括: 字符串'0', 空数组 [], 空对象 {}

    如果需要显式的得到一个布尔值, 可以使用!!表达式, !!expr等效于Boolean(expr), 写法更简洁但理解起来晦涩一点. !!expr可以确保返回一个布尔值. 使用!!的好处是某些情况下只需要布尔值时, 而expr可能是一个对象时, 可以释放expr所对应的对象.

    2. 防止不用new直接调用构造函数

    构造函数也是函数,所以可以直接调用,下面的代码可以防止调用构造函数时忘记写new:

    function Person(name) {
        if (this instanceof Person) {
            this.name = name;
        } else {
            return new Person(name);
        }
    }
    
    var person1 = new Person("Nicholas");
    var person2 = Person("Nicholas");  //same with: new Person()
    

    3. 在指定范围内获得一个随机数

    //in range [min, max)
    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min)) + min;
    }
    

    4. 用 && 与 || 代替if语句

    var foo = 10;  
    foo === 10 && doSomething(); // 等效 if (foo == 10) doSomething(); 
    foo === 5 || doSomething(); // 等效 if (foo != 5) doSomething();
    

    赋默认值: js function doSomething(arg1){ arg1 = arg1 || 10; // 如果arg1没有被赋值,则赋默认值10 }

    5. 序列化JSON对象与解析JSON

    var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} }; 
    var stringFromPerson = JSON.stringify(person); 
    //stringFromPerson is "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}"
    var personFromString = JSON.parse(stringFromPerson);  
    // personFromString is equal to person object
    

    6. 更好的Logging

    除了简单的使用console.log(), console.info()等方法来输出trace, 下面是一些有用的技巧:

    方法1: 使用Array.prototype.slice()给console.log()加前缀

    使用 Array.prototype.slice() 将类似数组的对象(譬如arguments)转成数组,trace时经常要在log前加一个前缀,那么就可以使用这个方法:

    function trace() {
        var args = Array.prototype.slice.call(arguments); //将 arguments 对象转成数组
        args.unshift('[myModuleName]');       //在数组最前面加上前缀,下一节介绍了如何得到file/function name
        console.log.apply(console, args);     //调用console.log(), 注意: 第一个参数必须要给console
    }
    

    参考stackoverflow了解为什么必须用console.

    方法2: 使用Function.apply.call()调用console方法

    语句 Function.apply.call(fn, console, args); 大约等同于 fn.apply(console, args); 如果fn.apply没有被重定义,两者完全一样,如果fn.apply被重定义过,Function.apply.call(fn, console, args)仍然能调用fn().

    第二个参数可以为任意object,但写trace函数时经常用到这个方法,所以第二个参数为console:

    //type could be 'log', 'info', 'warn', 'error'
    function _trace(type, args) {
        var prefix = 'any prefix'; //可以加上 file/func name 或者加上一个计数器
        args = Array.prototype.slice.apply(args);
        args.unshift(prefix);
        Function.apply.call(console[type], console, args);
    }
    function log() {
        _trace('log', arguments);
    }
    function error() {
        _trace('error', arguments);
    }
    

    7. 得到file/function name and line number

    方法1: 使用Function.caller属性

    请注意: Function.caller并不是规范里的属性, 虽然多数browser支持这个属性, 但在strict mode下, 这个属性不支持.

    function getLogPrefix() {
        // Get function name
        var callerFunc = getLogPrefix.caller ? getLogPrefix.caller.caller : null;
        var callerFuncName = (callerFunc) ? callerFunc.name : 'top';
    }
    

    方法2: 使用Error stack

    function getLogPrefix2() {
        // Get file name
        var err = new Error();
        // Error, getLogPrefix(), trace(), yourMethod()
        // so the array[3] is your method line, like below
        // at yourMethodName (http://localhost:63342/pan/web/simulator/examples/broadcast2.html:38:9)
        var caller = err.stack.split("\n")[3];
        var str = caller.slice(0, caller.lastIndexOf(':'));
        var filename = str.slice(str.lastIndexOf('/') + 1, str.lastIndexOf(':'));
    
        var prefix = '[' + filename + ']' + ' [' + callerFuncName + ']';
        return prefix;
    }
    

    参考 stackoverflow了解trace时如何得到行号

    8. 自定义trace方法:

    console.todo = function( msg){
        console.log( '%c %s %s %s ', 'color: yellow; background-color: black;', '--', msg, '--');
    }
    console.important = function( msg){
        console.log( '%c%s %s %s', 'color: brown; font-weight: bold; text-decoration: underline;', '--', msg, '--');
    }
    console.todo("This is something that's need to be fixed");
    console.important('This is an important message');
    

    更多技巧: