1.语句和表达式

var a = 3 * 6;
var b = a;
b;

这里,3 * 6是一个表达式(结果为18)。第二行的a也是一个表达式,第三行的b也是。表达式a和b的结果值都是18。

var a = 3 * 6var b = a称为声明语句,因为它们声明了变量。

a = 3 * 6b = a叫作赋值表达式

第三行代码中只有一个表达式b,同时它也是一个语句。这样的情况通常叫作表达式语句

1.1 表达式的副作用

最常见的有副作用的表达式是函数调用。

function foo(){
a = a + 1;
} var a = 1;
foo();//副作用:a的值被改变

其他一些表达式也有副作用:

var a = 42;
var b = a++; a;//43
b;//42

a++首先返回变量a的当前值42(再将该值赋给b),然后将a的值加1。

var a = 42;
var b = (a++,a); a;//43
b;//43

a++,a中第二个表达式a在a++之后执行,结果为43,并被赋值给b。

1.2 上下文规则

大括号

var a = {
foo: bar()
};

{...}被赋值给a,因而它是一个对象常量。

foo: bar()中的foo是语句bar()的标签。foo: bar()是标签语句。

JSON是JavaScript语法的一个子集,但是JSON本身并不是合法的JavaScript语法。

JSON属性名必须使用双引号,而标签不允许使用双引号。在控制台中输入{"a":42}会报错,因为它会被当作一个带有非法标签的语句块来执行。

JSON-P(将JSON数据封装为函数调用,比如foo({"a",42}))通过将JSON数据传递给函数来实现对其的访问。

代码块

[] + {};//"[object Object]"
{} + [];//0

第一行代码中,{}出现在+运算符表达式中,因此它被当作一个值(空对象)来处理。[]会被强制类型转换为"",而{}会被强制类型转换为"[object Object]"

第二行代码中,{}被当作一个独立的空代码块。代码块结尾不需要分号。最后+ [][]显式强制类型转换为0

对象解构

从ES6开始,{..}也可用于“解构赋值”,特别是对象的解构。

function getData(){
return {
a: 42,
b: "foo"
};
} var {a,b} = getData();
console.log(a,b);//42 "foo"

{a, b}实际上是{a: a, b: b}的简化版本。

{..}还可以用作函数命名参数的对象解构,方便隐式子地用对象属性赋值。

function foo({a,b,c}){
console.log(a,b,c);
} foo({
c: [1,2,3],
a: 42,
b: "foo"
});//42 "foo" [1,2,3]

else if

我们可以这样来写代码:

if (a){
//...
}
else if (b){
//...
}
else{
//...
}

其实JavaScript没有else if,上面只是省略代码块的{}。我们经常用到的else if实际上是这样的。

if(a){
//...
}
else{
if(b){
//...
}
else{
//...
}
}

2.运算符优先级

var a = 42,b;
b = (a++,a); console.log(a);//43
console.log(b);//43
/*
var a = 42,b;
b = a++,a; console.log(a);//43
console.log(b);//42
//b = a++,a可以理解为(b = a++),a。
*/

请务必记住,用,来连接一系列语句的时候,它的优先级最低,其他操作数的优先级都比它高。

2.1 短路

&&||来说,如果从左边的操作数能够得出结果,就可以忽略右边的操作数。我们将这种现象称为“短路”。

function doSomething(opts){
//如果opts未赋值,opst.cool就不会执行。
if(opts && opts.cool){
//...
}
}
function doSomething(opts){
//如果opts.cache存在,就无需调用primeCache()。
if(opts.cache && primeCache()){
//...
}
}

&&运算符的优先级高于||,而||的优先级又高于? :

a && b || c ? c || b ? a : c && b : a

//等价于(a && b || c) ? (c || b) ? a : (c && b) : a

2.2 关联

如果多个相同优先级的运算符同时出现,又该如何处理呢?

一般来说,运算符的关联(associativity)不是从左到右就是从右到左,这取决于组合(grouping)是从左开始还是从右开始。

请注意:关联和执行顺序不是一回事,原因是表达式可能会产生副作用,比如函数调用:

var a = foo() && bar();

这里foo()首先执行,它的返回结果决定了bar()是否执行。

&&||运算符是左关联,而? : 运算符是右关联。

=运算符是右关联:

var a,b,c;
a = b = c = 42;

a = b = c = 42实际上是这样来处理的:a = (b = (c = 42))

建议:如果运算符优先级/关联规则能够令代码更为简洁,就使用运算符优先级/关联规则,而如果()有助于提高代码可读性,就使用()

3.自动分号

有时JavaScript会自动为代码行补上缺失的分号,即自动分号插入(Automatic SemicolonInsertion,ASI)。

ASI只在换行符处起作用,而不会再代码行的中间插入分号。

如果JavaScript解析器发现代码行可能因为缺失分号而导致错误,那么它就会自动补上分号。并且,只有在代码行末尾与换行符之间除了空格和注释之外没有别的内容时,它才会这样做。

ASI的目的在于提高解析器的容错性。

解析器报错就意味着代码有问题,对ASI来说,解析器报错的唯一原因是代码中缺失了必要的分号。

我建议在所有需要的地方加上分号,将对ASI的依赖降到最低。

4.错误

JavaScript不仅有各种类型的运行时错误(TypeError、ReferenceError、SyntaxError等),它的语法中也定义了一些编译时错误。

5.函数参数

function foo(a = 42, b = a + 1){
console.log(a,b);
}
foo();//42 43
foo(undefined);//42 43
foo(5);//5 6
foo(void 0, 7);//42 7
foo(null);//null 1
/*
function foo(a = 42, b = a + 1){
console.log(
arguments.length, a, b,
arguments[0],arguments[1]
);
}
foo();//0 42 43 undefined undefined
foo(10);//1 10 11 10 undefined
foo(10,undefined);//2 10 11 10 undefined
foo(10,null);//2 10 null 10 null
*/

6.try...finally

finally中的代码总是会在try之后执行,如果有catch的话则在catch之后执行。也可以将finally中的代码看作一个回调函数,即无论出现什么情况最后一定会被调用。

function foo(){
try{
return 42;
}finally{
console.log("Hello");
}
console.log("never runs");
}
console.log(foo());
//Hello
//42

try中的throw也是如此:

function foo(){
try{
throw 42;
}finally{
console.log("Hello");
}
console.log("never runs");
}
console.log(foo());
//Hello
//Uncaught Exception: 42

如果finally中抛出异常(无论是有意还是无意),函数就会在此处终止。如果此前try中已经有return设置了返回值,则该值会被丢弃:

function foo(){
try{
return 42;
}finally{
throw "Oops!";
}
console.log("never runs");
}
console.log(foo());
//Uncaught Exception: Oops!

finally中的return会覆盖try和catch中return的返回值:

function foo(){
try{
return 42;
}finally{
//...
}
} function bar(){
try{
return 42;
}finally{
return;
}
} function baz(){
try{
return 42;
}finally{
return "Hello";
}
} foo();//42
bar();//undefined
baz();//Hello

7.switch

switch(a){
case 2:
//执行一些代码
break;
case 42:
//执行另外一些代码
break;
default:
//执行缺省代码
}

这里a与case表达式逐一进行比较(匹配算法与===相同)。如果匹配就执行该case中的代码,直到break或者switch代码块结束。

var a = "42";

switch(true){
case a == 10:
console.log("10 or '10'");
break;
case a == 42:
console.log("42 or '42'");
break;
default:
//永远执行不到这里
}
//42 or '42'

除简单值以外,case中还可以出现各种表达式,它会将表达式的结果值和true进行比较(这里是严格相等比较)。

var a = "hello world";
var b = 10; switch(true){
case (a || b == 10):
//永远执行不到这里
break;
default:
console.log("Oops");
}
//Oops

因为(a || b == 10)的结果是"hello world"而非true,所以严格相等比较不成立。此时可以通过强制表达式返回true或false,如case !!(a || b == 10)

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为止。

理论上来说,这种情况在JavaScript中是可能出现的,但在实际情况中,开发人员一般不会这样写编码。如果确实需要这样做,就应该仔细斟酌并做好注释。

JS的语法的更多相关文章

  1. ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可以引入动态加载的概念来即用即取.这 ...

  2. js基本语法汇总

    1.分类 ECMAScript js基本语法与标准 DOM Document Object Model文档对象模型 BOM Browser Object Model浏览器对象模型 tips:DOM和B ...

  3. JS高级语法与JS选择器

    元素(element)和节点(node) childNode属性和children属性的区别 <!DOCTYPE html> <html lang="en"> ...

  4. ExtJs对js基本语法扩展支持

    ExtJs对js基本语法扩展支持 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可 ...

  5. Vue.js 数据绑定语法详解

    Vue.js 数据绑定语法详解 一.总结 一句话总结:Vue.js 的模板是基于 DOM 实现的.这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强.Vue ...

  6. JavaScript进阶 - 第2章 你要懂的规则(JS基础语法)

    第2章 你要懂的规则(JS基础语法) 2-1什么是变量 什么是变量? 从字面上看,变量是可变的量:从编程角度讲,变量是用于存储某种/某些数值的存储器.我们可以把变量看做一个盒子,盒子用来存放物品,物品 ...

  7. [转载]ExtJs4 笔记(2) ExtJs对js基本语法扩展支持

    作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/) 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引 ...

  8. Vue.js 模板语法

    本章节将详细介绍 Vue.js 模板语法,如果对 HTML +Css +JavaScript 有一定的了解,学习起来将信手拈来. Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 ...

  9. 【JS基础语法】---学习roadmap---6 parts

    JS基础语法---roadmap Part 1 - 2: Part 3 - 4:   Part 5 - 6

  10. JS基本语法---while循环---练习

    JS基本语法---while循环---练习 练习1: 求6的阶乘 var ji = 1;//存储最终的阶乘的结果 var i = 1;//开始的数字 while (i <= 6) { ji *= ...

随机推荐

  1. OTRS

    更新OTRS root@localhost密码: sudo -u otrs /opt/otrs/bin/otrs.Console.pl Admin::User::SetPassword root@lo ...

  2. Linux 文件系统 -- 简述几种文件类型

    Linux 中一切皆为文件,文件类型也有多种,使用 ls -l 命令可以查看文件的属性,所显示结果的第一列的第一个字符用来表明该文件的文件类型,如下: 1.普通文件 使用 ls -l 命令后,第一列第 ...

  3. 基于Promise规范的fetch API的使用

    基于Promise规范的fetch API的使用 fetch的使用 作用:fetch 这个API,是专门用来发起Ajax请求的: fetch 是由原生 JS 提供的 API ,专门用来取代 XHR 这 ...

  4. 2018-2019-20172321 《Java软件结构与数据结构》第九周学习总结

    2018-2019-20172321 <Java软件结构与数据结构>第九周学习总结 教材学习内容总结 第15章 图 无向图 图由顶点和边组成. 顶点由名字或标号来表示,如:A.B.C.D: ...

  5. AngularJs 学习 (二)

    紧接着第一部分: 推荐阅读: http://adrianmejia.com/blog/2014/10/03/mean-stack-tutorial-mongodb-expressjs-angularj ...

  6. 调整Linux的最大文件打开数

    要调整一下Linux的最大文件打开数,否则squid在高负载时执行性能将会很低.另外,在Linux下面部署应用时,有时候会遇上 Socket/File:Can’t open so many files ...

  7. 个人作业-week2(代码复审)

    一.代码复审check list 概要部分 代码符合需求和规格说明吗? 符合要求和规格说明,-s指令和-c指令都能实现需求.并且能够处理非法输入. 代码设计是否有周全的考虑? 程序的main函数中对各 ...

  8. localStorage存储数组,对象,localStorage,sessionStorage存储数组对象

    localStorage存储数组,对象,localStorage,sessionStorage存储数组对象   前言 最近在用angular做商城购物车的功能模块,因为angular的watch监听, ...

  9. 联想本win10 virtualbox 安装centos

    (1)必须开发操作系统虚拟化功能,参考该百度经验 https://jingyan.baidu.com/article/8275fc864d423e46a03cf638.html (2)调整虚拟机硬盘和 ...

  10. Boa服务器移植

    Boa是一种非常小巧的Web服务器,其可执行代码只有大约60KB左右.作为一种单任务Web服务器,Boa只能依次完成用户的请求,而不会fork出新的进程来处理并发连接请求.但Boa支持CGI,能够为C ...