你不知道的js(中卷)第5章 语法

1.语句和表达式

表达式可以返回一个结果值。
语句包含表达式,可以比表达式长(就像句子可以包含短语)。语句也有结果值。

1.1 语句的结果值

      在控制台输入一个语句,执行完,控制台输出的就是结果值。
      在代码中没法取到结果值。硬要看的话,可以用eval来看。实际开发中不推荐用eval。
      目前语句的结果值还无关紧要,以后它可能会有比较重要的意义。

1.2 表达式的副作用

      表达式会造成副作用的情况:
      ①有些函数调用

      ②递增运算符++和递减运算符--

      ③delete运算符,操作成功返回true,失败则返回false,其副作用是删除对象的属性
      tips:逗号运算符可将多个语句连成一个,例:let b = (a++, a),b得到的就是a自增之后的值。

      ④=运算符,a=42返回42,其副作用是给a赋值
      tips:

    let matches
    matches = str.match(/[aeiou]/g) // 提取所有元音字母
    if (matches) {...}

      就可以写成:

    let matches
    if (matches = str.match(/[aeiou]/g)) {...}

      (作者说的副作用啥的我能理解,但等号运算符,那个赋值短语直接拿去做判断,还是感觉不确定靠谱不靠谱,赋值短语的值就等于赋的值吗??)

1.3 上下文规则

      在js中同样的语法在不同情况下会有不同的解释

      ①大括号
      目前用到大括号的情况有两种(以后还会更多):
      (1)用大括号定义对象。如 let a = {foo: bar()} // 假设bar函数已经定义过
      (2)标签。如{foo: bar()} // 假设bar函数已经定义过
      此时大括号会被当作代码块。foo: bar()会被当作标签语句。
      所谓标签语句,就是:
      a.如果给循环加了标签,它可以跟break或continue结合使用。break 某标签,表示跳出标签指定的那层循环。continue 某标签,表示执行标签指定的那层循环的下一轮循环。
      b.如果给代码块加了标签,它可以跟break结合使用,break 某标签,表示跳过标签指定的代码块的剩余语句。
      这两种写法都不太常见,也不建议使用,如果要使用务必写注释。
      (但是我自己在控制台试了下{foo: bar()}并没被当作标签啊,貌似foo得写在花括号外面才会被当作标签。。迷惑)

      ②代码块
      {} + [] // 0
      是因为前面的{}会被当作空代码块,而不是一个对象常量。所以结果等于+ [],即0。

      ③解构赋值

      ④if else和可选代码块
      JavaScript没有else if。常用的else if,其实是,else后面跟着单独一条语句,而那个语句恰好是if...


2.运算符优先级

      首先作者举了3个例子,分别说明:a.逗号操作符连接若干个语句时,逗号操作符的优先级最低;b.&&操作符优先级高于=操作符;c.&&操作符优先级高于||。
      然后作者说,JavaScript规范对运算符优先级并没有一个集中的介绍,因此需要从语法规则中间逐一了解。(不过也早有人整理出专门的文章了)

2.1 短路

      对&&和||来说,如果从左边的操作数能够得出结果,就可以忽略右边的操作数。我们将这种现象称为“短路”。
      实际开发中,短路经常用来做判断,如果左边的操作数满足某条件,后续的操作就可以略过。

2.2 更强的绑定

      &&运算符的优先级高于||,而||的优先级又高于? :。
      这个规则的另外一种讲法:“&&和||比?:的绑定更强”。

2.3 关联

      &&运算符是左关联(||也是),所以a && b && c会被处理为(a&& b) &&c。
      像&&和||左关联还是右关联计算结果都是一样。
      但三目运算符?:就不是这样a ? b : c ? d : e是左关联还是右关联就会影响到结果。
      三目运算符是右关联的,a ? b : c ? d : e 相当于 a ? b : (c ? d : e)
      =赋值运算符也是右关联。

2.4

      有时候用()把短语包住,可以使代码更易懂。有时候,不用(),仅凭运算符优先级,可以使代码更简洁。建议根据实际情况斟酌后选择。


3.自动分号

      JavaScript会自动为代码行补上缺失的分号,即自动分号插入(Automatic SemicolonInsertion, ASI)。
      ASI只在换行符处起作用,而不会在代码行的中间插入分号,并且只有在代码行末尾与换行符之间除了空格和注释之外没有别的内容时,它才会这样做。
      仔细阅读规范就会发现,ASI实际上是一个“纠错”(error correction)机制。这里的错误是指解析器错误。换句话说,ASI的目的在于提高解析器的容错性。
      依赖于ASI实际上是将换行符当作有意义的“空格”来对待。因此作者说,不要依赖ASI,该加分号的地方自己加上分号。


4.错误

      JavaScript不仅有各种类型的运行时错误(TypeError、ReferenceError、SyntaxError等),它的语法中也定义了一些编译时错误。
      在编译阶段发现的代码错误叫作“早期错误”(early error)。语法错误是早期错误的一种。

      然后作者介绍了一种从ES6起才有的语法错误,叫TDZ(Temporal Dead Zone,暂时性死区)。
      指的是由于代码中的变量还没有初始化而不能被引用的情况。
      例:

{
    a = 2; // ReferenceError!
    let a;
}

又例:

{
    typeof a; // ReferenceError!
    typeof b; // undefined
    let a;
}


5. 函数参数

      函数参数中的TDZ:

var b = 3;
function foo(a = 42, b = a + b + 5) {...}

a + b + 5在参数b的TDZ中访问b,会报错,但它访问a是没问题的,因为此时刚好跨出了参数a的TDZ。

function foo(a = 42, b = a + 1) {...}

      此处42是a的默认值,a + 1是b的默认值。
      如果没有传入参数,或传入undefined,则取该参数的默认值。

      但是没传参数和传入undefined有一个区别,arguments的length会不一样,不传的话length为0,传的话arguments中会出现一个值位undefined的单元。
      不建议用arguments,自从ES6有了剩余参数...之后,就更没必要了。


6.try..finally

      我们知道finally中的代码总是会在try之后执行,如果有catch的话则在catch之后执行。
      假如try中有return语句,会怎么样呢?

funcion foo() {
    try{ 
      return 42;
    }
    finally{
      console.log("Hello");
    }
}

console.log(foo());
// Hello
// 42

      这里return 42先执行,并将foo()函数的返回值设置为42。然后try执行完毕,接着执行finally。最后foo()函数执行完毕,console.log(..)显示返回值。

      如果try中有throw语句也是,finally代码块会被执行,然后函数抛出异常。
      如果finally中抛出异常,则此前try中(如果有)已有的return值会被丢弃,函数抛出异常。
      try中有continue语句也一样,try后面如果有finally,finally还是会被执行,再continue去下一轮循环。
      另外,finally中的return会覆盖try和catch中return的返回值。(要注意,在finally中return后面如果不跟值,则会返回前面的return设定的返回值。)

      finally中如果有break标签,还可以跳过try中的return:

function foo() {
    bar: {
      try {
        return 42;
      }
      finally {
        break bar;
      }
    }
    console.log('Creazy');
    return 'Hello';
}
console.log(foo());
// Crazy
// Hello


7.switch

      注意switch case中的匹配是===,严格相等才匹配。
      switch中的break可以带标签。

      一个奇葩例子:

var a  = 10;
switch(a) {
  case 1:
  case 2:
  // 永远执行不到这里
  default:
    console.log("default");
  case 3:
    console.log("3");
    break;
  case 4:
    console.log("4")
}
// default
// 3

      首先遍历并找到所有匹配的case,如果没有匹配则执行default中的代码。因为其中没有break,所以继续执行已经遍历过的case 3代码块,直到break为止。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352