JS的语法
1.语句和表达式
var a = 3 * 6;
var b = a;
b;
这里,3 * 6
是一个表达式(结果为18)。第二行的a也是一个表达式,第三行的b也是。表达式a和b的结果值都是18。
var a = 3 * 6
和var b = a
称为声明语句,因为它们声明了变量。
a = 3 * 6
和b = 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的语法的更多相关文章
- ExtJs4 笔记(2) ExtJs对js基本语法扩展支持
本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可以引入动态加载的概念来即用即取.这 ...
- js基本语法汇总
1.分类 ECMAScript js基本语法与标准 DOM Document Object Model文档对象模型 BOM Browser Object Model浏览器对象模型 tips:DOM和B ...
- JS高级语法与JS选择器
元素(element)和节点(node) childNode属性和children属性的区别 <!DOCTYPE html> <html lang="en"> ...
- ExtJs对js基本语法扩展支持
ExtJs对js基本语法扩展支持 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可 ...
- Vue.js 数据绑定语法详解
Vue.js 数据绑定语法详解 一.总结 一句话总结:Vue.js 的模板是基于 DOM 实现的.这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强.Vue ...
- JavaScript进阶 - 第2章 你要懂的规则(JS基础语法)
第2章 你要懂的规则(JS基础语法) 2-1什么是变量 什么是变量? 从字面上看,变量是可变的量:从编程角度讲,变量是用于存储某种/某些数值的存储器.我们可以把变量看做一个盒子,盒子用来存放物品,物品 ...
- [转载]ExtJs4 笔记(2) ExtJs对js基本语法扩展支持
作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/) 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引 ...
- Vue.js 模板语法
本章节将详细介绍 Vue.js 模板语法,如果对 HTML +Css +JavaScript 有一定的了解,学习起来将信手拈来. Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 ...
- 【JS基础语法】---学习roadmap---6 parts
JS基础语法---roadmap Part 1 - 2: Part 3 - 4: Part 5 - 6
- JS基本语法---while循环---练习
JS基本语法---while循环---练习 练习1: 求6的阶乘 var ji = 1;//存储最终的阶乘的结果 var i = 1;//开始的数字 while (i <= 6) { ji *= ...
随机推荐
- Nginx内置的嵌入变量
Nginx核心模块ngx_http_core_module自带有许多内置嵌入的变量,这些变量方便我们配置和使用nginx,在nginx的配置文件中我们可以以$开头直接使用这些变量,这些变量表示客户端请 ...
- 简介make命令和makefile文件
一.为什么要用到 make 命令和 makefile 文件 在 Linux 下编写一个程序,每次编译都需要在命令行一行一行的敲命令.如果是一个很小的程序还好说,命令不怎的复杂,编译速度也挺快,但是对于 ...
- mkdir命令详情
基础命令学习目录首页 原文链接:https://blog.csdn.net/zwlove5280/article/details/74618041 mkdir 是创建目录的命令. 创建一级目录 mkd ...
- chown命令详情
基础命令学习目录首页 原文链接:https://www.jb51.net/article/98255.htm chown将指定文件的拥有者改为指定的用户或组,用户可以是用户名或者用户ID:组可以是组名 ...
- Javascript开发者 常用知识
Javascript是一种日益增长的语言,特别是现在ECMAScript规范按照每年的发布时间表发布.伴随着这门语言的规模化和快速发展,掌握JS(不仅仅是jQuery)的重要性,变得更加重要. 这不是 ...
- Java第二次实验20135204
一.实验过程: 1.先创建一个学号命名的文档: 2.一个百分制成绩转化为等级: 3.新建一个包,另一个测试: 4.打开UML,建模软件umbrello进行建模: 相关程序: 5.我的保存: 二.遇到的 ...
- An internal error occurred during: "Launching MVC on Tomcat 7.x".
删除工作空间下的“/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.genuitec.eclipse.ast.deploy.core ...
- install4j 工具为java程序打包exe
用 install4j 工具为java程序打包exe 制作人:mark 制作时间:2013-05-02 用Eclipse 将程序源码打包成jar文件. 打包jar方法我不做介绍了,相信大家都会,不会的 ...
- Software Defined Networking(Week 2, part 3)
Control of Packet-switch Network 我们已经讨论过中心控制网络的原理,但主要是以电话网络做模型的.现在我们来看看对于分组交换网络的控制是如何改进的. Why Separa ...
- Java编写的电梯模拟系统《结对作业》
作业代码:https://coding.net/u/liyi175/p/Dianti/git 伙伴成员:李伊 http://home.cnblogs.com/u/Yililove/ 对于这次作业,我刚 ...