Skip to content

Latest commit

 

History

History
83 lines (74 loc) · 3.64 KB

appendixB.md

File metadata and controls

83 lines (74 loc) · 3.64 KB

附录B 禁止使用的语法

在javascript早期,有着不少明显的设计失误。这些设计失误导致了一些语法有着极为诡异的行为。在现在看来,这些语法在实际应用中是禁止被使用的。否则程序会被引入各种奇怪的行为,而且查找出错误的位置也相当耗时间。

==和!=

这两个符号居然一言不合就做类型转换,导致''和0会被判成相等。因此永远使用不带类型转换的===!==,或者使用Object.is

自动分号插入机制

下面的语句返回什么?

function func() {
  return
  {
    a: 1
  };
}

如果你认为函数返回的是一个对象,那么你图样图森破。Javascript的自动分号插入机制在return的后面强行加了一个分号,于是该函数就return了一个undefined。这导致javascript写花括号不能换行。在其它语言中,这是难以想象的。如何规避这个机制众说纷纭,但我们一般都是在该加分号的地方全部都加上分号。并且,花括号之前不要换行。真希望这个语法被取消掉。

不定义变量

无论在程序的什么位置,不用var/const/let,直接赋值变量,则定义了一个全局变量。

function func(){
  x = 10; // x是全局变量
}

禁止使用这种语法。不仅如此,也要禁止使用全局变量。因为一旦忘记写var/const/let,程序就引入了一个未知的行为,但要找到问题出在哪一行却犹如大海捞针。幸好后来的严格模式禁止了这种语法。建议永远使用严格模式。

var

在早期,只能用这个关键字来定义变量。但是,这个关键字定义出来的变量居然没有块域。

{
  var x = 10;
}
console.log(x); // 10

它跟下面的语句等价。

var x = 10;
console.log(x); // 10

我们甚至还可以这样。

console.log(x); // undefined
{
  var x = 10;
}

变量x可以先被使用(虽然值为undefined),然后再被定义出来。它跟下面的语句等价。

var x;
console.log(x); // undefined
x = 10;

也就是说,var定义的变量,其实编译器把它悄悄的放到了第一行,在定义的那一行再进行初始化操作。如此诡异的语法,除了javascript之外,还真没有其它语言采用。Javascript还为这个特性取了一个名字,叫做“变量提升”。 神奇的是,var定义的变量虽然没有块域,但是却有函数域。

function func(){
  var x = 10;
}
console.log(x); // error: x is not defined

为了让var表现得好像有块域一样,一个特有的语法被发明出来,叫做立即执行函数。用这玩意可以把var封锁在函数局部域内。

(function() {
  var x = 10; // x只在这个匿名函数内部可见
})();

可惜,立即执行函数会改变this的含义,因此有些地方还是需要做特殊处理。 想要用好var,需要对上面的内容了如指掌。否则稍有不慎就会创造出诡异的bug。因此,永远使用带有块域和函数域的let/const。禁止使用var。

eval函数

这个函数把字符串作为javascript语句来执行。它的功能过于强大(因而很不安全),因此禁止使用。

with语句

如果你完全不知道with语句是做什么的,那么恭喜你,你永远也不需要知道。如果你已经知道with是做什么的,那么赶紧忘掉它。

封装对象

除了用它来测试javascript引擎是符合标准的之外,完全没有任何用处。

命名函数表达式

同上,禁用。

上一课 | 目录 | 下一课