Math.pow(1.1, Day)

JavaScript中的小技巧

每种编程语言里都有一些小伎俩,有些确实能带来方便,有些则只是纯蛋疼。这里收集一些常见的JavaScript伎俩,按需自取。

!function foo(){}()

对于!function foo(){}(),有以下几点:

  • 运算符()!的优先级高,所以它等价于!(function foo(){}());
  • !(statement);会触发JavaScript引擎去解析statement,然后取其结果的布尔反值
  • 该语句的目的就是执行这个函数,它等价于(function foo(){})();

直接使用function foo(){}()会导致语法错误,因为

function foo() {}

是一个函数声明语句,末尾没有;号,对它的解析到}号为止,你不能在后面接(。想要调用foo,只能使用foo();

因此,这个伎俩的目的只是为了省一个字符:!function foo(){}() VS (function foo(){})();

!!variant

JavaScript中没有!!运算符,它实际上是两次!逻辑运算,结果是把任意一个JavaScript对象转化为一个布尔值。这其中,如果variant本身一个falsy value,那么!!variant是布尔假。否则为真。

console.log(!!1);   // true
Boolean(1) === !!1;  // true
console.log(!!"");   // false
Boolean("") === !!"";    //true

可以把它看作是布尔值转换运算。但如果你是为了在if语句中使用,大可不必这样做。因为JavaScript引擎会对if(statemen){}中的statement自动执行这个布尔值转换操作。比如,以下代码会把bar当作布尔真值来执行。

var bar = {a: 1};
if(bar){
    console.log(true);
}else{
    console.log(fasle);
}

函数参数的缺省值

在C++/PHP/Python中定义方法的时候都能为参数指定一个默认值,但JavaScript语言没有这个机制。因此我们只能仿造。一般是这样来做的:

function myFunc(requiredArg, optionalArg){
  optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;

  //do stuff
}

如果你确定这个参数是一个非falsy value的对象,还可以简化(这是我用得最多的方式):

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || defaultValue;

  //do stuff
}

注意:

  • 跟Python一样,你只能把带默认值的参数放在参数列表的最后。
  • ECMAScript6中的Function已经加入该特性,Firefox中已经支持:Default parameters

+运算符

这个问题中有很多蛋疼的例子,在这里说它的目的是提醒大家:严谨地使用+运算符。以下是使用+的蛋疼示例,运行示例请参考jsfidde

  • [] + []
    • // an empty string
  • [] + {}
    • [object Object]
  • {} + []
    • 0
  • {} + {}
    • NaN
  • Array(16).join(“wat” + 1)
    • wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1
  • Array(16).join(“wat” - 1)
    • NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN

实际上以上结果都是遵循ECMAScript5的执行结果。对于+运算符的规定为 The Addition operator ( + )

  • 不限制运算数必须为primitive
  • 首先将两个操作数转化为primitive - ToPrimitive
  • 将一个object转化为primitive就是返回其default value,如果该object有toString()方法,将返回该方法的值
  • 对于Array来说,就是调用其.join()方法
  • 对于object来说,调用toString()将返回"[object Object]"

以上规范能解释大部分使用+的场合,但还有两个示例需要进一步的解释:

  • {} + []
    • {}会被解析为一个block,而不是一个对象(除非你使用({})使它成为一个表达式)
    • 因此{} + []等价于+[]
    • +operand将返回toNumber(ToPrimitive(operand))
    • +[]将返回toNumber(""),也就是0
  • {} + {}
    • 由上可知它将返回toNumber("[object Object]")
    • 根据toNumber()的定义,这无法转成number,因此返回NaN

太复杂。实际使用中,最好保证+的两个操作数均为primitive类型,不能是object类型。