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. mysql以zip安装,解决the service already exists(转载)

    喵喵亲测可用: 转自:https://www.cnblogs.com/dichters/p/5929209.html mysql以zip安装, mysqld -install 报错:​The serv ...

  2. Hyperledger Fabric CA User’s Guide——配置设置(四)

    配置设置 Fabric CA提供了三种方案去配置Fabric CA服务端和客户端,优先顺序是: CLI flags(标识) 环境变量 配置文件 在本文档的其余部分中,我们将对配置文件进行更改.但是,可 ...

  3. dvwa——sql手动注入和sqlmap自动注入

    手动注入 low: 源码: <?php if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; ...

  4. 插件使用_kindeditor

    1.官网 进入官网:http://kindeditor.net/demo.php 插件下载:http://kindeditor.net/down.php 2.使用 (1)文件夹说明 ├── asp a ...

  5. 安装hive的web界面

    参考: http://blog.csdn.net/xinghalo/article/details/52433914 报错参考; http://blog.163.com/artsn@126/blog/ ...

  6. iOS学习资源搜集

    swift 2.0 新的开始 iOS7初学者入门 斯坦福大学公开课:iOS 8开发 苹果官方开发 中文 iOS/Mac 开发博客列表    git

  7. fcn模型训练及测试

    1.模型下载 1)下载新版caffe: https://github.com/BVLC/caffe 2)下载fcn代码: https://github.com/shelhamer/fcn.berkel ...

  8. User survey(用户调研)

    郑文武——小学二年级学生 姓名 郑文武  性别.年龄 男.9岁                      职业 学生 收入 父母给的零花钱 知识层次和能力 会使用手机 生活/工作情况 努力学习但数学成 ...

  9. 怎样实现SDO服务

    SDO是CANopen协议中最复杂的一部分,带有应答机制,有多种传输方式,并且完整的SDO功能节点需提供1个SDO server和多个SDO client,因此SDO的实现异常困难,协议多种传输方式的 ...

  10. profibus总线和profibus dp的区别

    profibus总线和profibus dp的区别:PROFBUS是一种国际性的开放式的现场总线标准,它既可以用于高速并且对于时间苛求的数据传输,也可以用于大范围的复杂通讯场合.PROFBUS-DP是 ...