JS逗号、冒号与括号
JavaScript面试时候的坑洼沟洄——逗号、冒号与括号
看完了javaScript数据类型和表达式与运算符相关知识后以为可以对JavaScript笔试题牛刀小试一把了,没想到有一次次的死在逗号,冒号和括号上,不得已再看看这几个符号吧。
逗号
逗号我们常见的用法就是在连续声明一些变量的时候,可以少些很多var
1
2
3
|
var a=1, b=2, c=3; |
方法参数我们使用逗号隔开,对象属性也是逗号隔开
``` function fbn(name,title){} var person={ name:"Byron", age:"24" }; ``` 然而我们也会遇到这样的问题,在赋值表达式中出现的逗号
1
|
var a=(1,2,3); |
在表达式与运算符中提到过逗号运算符就是对应这种情况,这时表达式计算结果是最后一个子表达式结果,也就是3。千万不要误会前面的子表达式不会执行,每个子表达式都会执行,只不过“返回值”是最后一个表达式结果。
1
2
3
4
|
var a,b; a=(b=1,2); console.log(a); //2 console.log(b); //1 |
冒号
?:运算符
1
|
var p=gender ? 'male' :female; |
对象字面量
1
2
3
4
|
var obj={ name: "Byron" , age:24 }; |
switch语句
1
2
3
4
5
6
7
8
|
switch (t){ case 1: console.log( 'xxx' ); break ; case 2: console.log( 'ooo' ); break ; } |
相信这是大家所熟知的用法了,那么我们可以个题目
1
|
x:y:z:1,2,3; |
上面运算会不会报错?不报错运算结果是什么?很多同学初次看到这个会很惊讶,觉得肯定会出错,但结果却是3,来看看为什么
其实冒号还有个作用:声明label,JavaScript中语句可以有个标签前缀,我们称之为标记语句,break或continue可以和标记的语句结合使用,控制流程。如果标签有重复,就会出错。我们上面的语句可以翻译成这样
1
2
3
|
x: y: z:1,2,3 |
这样我们结合刚才说的逗号的知识就能明白为什么结果是3了,很多优化建议都是不提倡使用标签的,有没有想起C语言的goto,使用了标签控制流程,使程序相当难读懂。
1
2
3
4
5
6
7
|
var x=1; foo:{ x=2; break foo; x=3; } console.log(x); |
大括号
对象直接量声明
1
2
3
4
|
var obj={ name: "Byron" , age:24 }; |
整条语句使赋值语句,右值部分十个表达式,通过直接量构造出一个对象
函数声明或者函数直接量
1
2
3
4
5
6
|
function fn1(){ //.... }<br> var fn2= function (){ //... }; |
相信这种用法不闭多说什么了
组织复合语句
1
2
3
4
5
6
7
8
9
10
11
|
with (obj){ //... } for (){ //... } if (){ //... } else { //... } |
大括号没有带来块级作用域
熟悉JavaScript的同学肯定对这点儿已经熟知了,大括号虽然能够组织复杂的语句等,是指算是同一“块”,with甚至提供了相近的功能,但遗憾的使JavaScript只有函数作用域,没有块作用域,再JavaScript中下面做法会声明全局变量,这个小小的知识点往往引英雄竞折腰
- 在function外使用声明变量(无论是否使用var)
- 在function内不是用var 声明变量
- 直接赋值于window属性
1
2
3
4
5
|
var a=2; function fn(){ b=3; window.c=4; } |
除了这三种剩下的就是function范围内的局部变量了,在很多JavaScript规范中都有提到,尽量提早声明变量正是由于其没有块作用域
1
2
3
4
5
6
7
8
|
function fn(n){ if (n>1){ var a=n; } else { var b=n; } console.log(a); } |
这样的代码在很多语言中有语法错误,因为if和else的大括号有块作用域,变量a、b在自己对应块作用域中,出了块就访问不到了。但在JavaScript中,没有块作用域,所以我们在if、else内声明的变量console.log依然能够访问,这确实是糟糕的设计,为了减少错误可能,尽量把变量声明提前。
很多笔试题目正是针对这方面知识出题的
1
2
3
4
|
{a:1}; var x={a:1}; {a:1,b:2}; var y={a:1,b:2}; |
亲自试试是不是发现很惊讶,我们分析一下
{a:1} JavaScript有传说中的“语句优先”,也就是当大括号既可以被理解为复合语句块也可以被理解为对象直接量的时候,JavaScript会将其理解为复合语句快。{a:1}其实就是 a: 1,想想冒号的作用是不是知道为什么返回值是1了。
var x={a:1} 当{a:1} 作为右值出现的时候,明显就不是语句,而是直接量表达式了,所以把大括号当作对象直接量语法处理,结果是个对象。
{a:1,b:2}; 看了上面这个就简单了,可以翻译为:a:1,b:2 结合逗号和冒号作用,结果似乎显而易见了,就是2嘛。然而其实报错了,这是为什么?在逗号运算符后面必须是表达式,而标签语句十个label statement,是条语句,所以就报错了。
了解了这些知识我们再来试几个题目(看答案在控制台上,不要试图alert)
1
2
3
|
{foo:[1,2,3]}[0]; {a:1}+2; 2+{a:1}; |
不知道小伙伴儿们做对了没有,这几个题目核心一样,大括号虽然看起来没什么作用,但起到了语句分隔符作用,{foo:[1,2,3]}[0]可以理解为
1
2
|
{foo:[1,2,3]}; [0]; |
所以返回值是[0],同样{a:1}+2变为
1
2
|
{a:1}; +2 |
但是!为什么2+{a:1}就不一样了呢?这时加法运算符导致的,加号是左结合的,{}被解析为表达式(得是表达式相加嘛),根据数据类型中知识对象{a:1}转换为NaN
小括号
在JavaScript中小括号有几种用法
函数声明或调用表达式参数表
这个好理解,函数定义的时候需要用小括号将其参数包裹,用逗号隔开,调用的时候也一样
1
2
3
4
5
|
function fn(name,age){ //... } fn( 'Byron' ,24); var f= new fn( 'Byron' ,24) |
与一些关键字组成条件语句
我们常见的if、switch、while中的小括号就是干这个用的
1
2
3
4
5
6
7
8
9
|
if (a>0){ //... } while (i<len){ //... } for ( var i=0;i<len;i++){ //... } |
分组运算符 分组运算符内部只能包含表达式,可以改变运算符优先级,舍弃一些可能的语法树,最常见的
1
|
var x=()1+2)*3; |
相信不用多解释,很多同学会认为小括号有强制表达式运算的功能,其实这时片面的理解,这只是改变了运算符优先级,生成新的语法树后的结果。
对于简单的json字符串转为对象的时候,因为浏览器兼容性原因,不能使用JSON对象,又懒得引入json2,所以就会用eval()处理,大概写法这样
1
2
|
var jsonStr=...; var jsonObj=eval( '(' + jsonStr + ')' ); |
很多同学会问,为什么还要加上个小括号呢?像我们上面解释的大括号的作用,json字符串 "{a:1,b:2}" 这样的格式会被理解为语句,也就是传说中的label statement,语法树是这样的
{
a:1,
b:2
}
上面提到过逗号运算符不能在label statement后面,所以会报错,而加上括号后由于分组运算符只能包含表达式,所以{}变成直接量语法,这样就是我们希望的内容了。
立即调用的函数表达式
再来回头看看我们所谓的立即执行函数,一般有两种写法
1
2
3
|
( function (){})(); ( function (){}()); ! function (){}(); |
搜了很多资料,终于看到了靠谱解释,总结一下,首先我们需要搞清楚函数表达式和函数声明区别,ECMAScript规范中定义的相当模糊:
函数声明必须带有标示符(Identifier)(就是大家常说的函数名称),而函数表达式则可以省略这个标示符:
函数声明:
function 函数名称 (参数:可选){ 函数体 }
函数表达式:
function 函数名称(可选)(参数:可选){ 函数体 }
其实我们常用的区分方式是根据上下文,如果function fn(){}作为右值出现(赋值表达式右边)那么就是表达式,否则就是函数声明。有几种看起来不常规的方式需要我们注意
1
2
|
new function fn(){}; //表达式,因为在new 表达式中 ( function (){}()); //表达式,在分组运算符中 |
这样我们就能理解第二种写法了,就是利用分组运算符改变了语法树。同样第三种写法其实是利用了一元运算符后面跟表达式的原理,我们也可以写成
1
2
3
|
+ function (){}() - function (){}() ~ function (){}() |
知乎上长天之云甚至写出了这么多
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
( function () {}() ); ( function () {} )(); [ function () {}() ]; //////////////////////////////// ~ function () {}(); ! function () {}(); + function () {}(); - function () {}(); //////////////////////////////// delete function () {}(); typeof function () {}(); void function () {}(); new function () {}(); new function () {}; ///////////////////////////////// var f = function () {}(); ///////////////////////////////// 1, function () {}(); 1 ^ function () {}(); 1 > function () {}(); |
所以我们应该称立即执行函数为立即调用的函数表达式!
中括号
相对而言中括号是个最简单的符号了,一般有几种语义
*数组相关
我们知道数组可以通过中括号来直接量实例化
1
|
var a=[1,2,3]; |
*获取对象属性值
这也是很常见的用法
1
2
3
4
|
var a=[1,2,3]; var b={name: 'Byron' }; a[2]; b[ 'name' ]; |
看几个有意思的小题目
1
2
|
[1,2,3,4,5][0..toString.length]; //0.等同于0.0 'foo' .split( '' ) + []; |
最后
不总结不知道,一总结下一跳啊,几个小小的符号竟然这么百转回肠,总结完之后才知道自己以前不了解这些知识,死在笔试题上一点儿都不冤,准备换工作的同学也了解一下以备万一吧。
参考
JS逗号、冒号与括号的更多相关文章
- JavaScript面试时候的坑洼沟洄——逗号、冒号与括号
看完了javaScript数据类型和表达式与运算符相关知识后以为可以对JavaScript笔试题牛刀小试一把了,没想到有一次次的死在逗号,冒号和括号上,不得已再看看这几个符号吧. 逗号 逗号我们常见的 ...
- JS中冒号的作用
JS中冒号的作用1.声明对象的成员2.switch语句分支3.三元表达式 1.声明对象的成员 var Book = { Name: '法', Price: 100, Discount : functi ...
- JS逗号运算符的用法详解
逗号运算符的用法详解 注意: 一.由于目前正在功读JavaScript技术,所以这里拿JavaScript为例.你可以自己在PHP中试试. 二.JavaScript语法比较复杂,因此拿JavaScri ...
- js逗号表达式
在js中的某些场景,","是一种运算符号,只不过他的优先级要低于普通的原酸符,在变量声明或者return中,经常看到逗号表达式. 声明变量: var a=1,b=2,c=3; co ...
- js 逗号操作符
有一道js面试题,题目是这样的:下列代码的执行结果是什么,为什么? var i, j, k; for (i=0, j=0; i<10, j<6; i++, j++) { k = i+j; ...
- ThinkPHP模板中JS等带花括号处会被解析错误的解决办法
如下图,当本人在ThinkPHP框架的模板中写jQuery代码的时候,写了一些注释,并且注重是斜线和换括号{是连着一起的,这层语法上来时是没问题的,但是在ThinkPHP 的模板引擎解析下,会被解析掉 ...
- 逗号运算符与括号 - C语言
例1 int x; int a=(x=2),12;// 赋值优先级高于逗号,相当于a=x=2,12是多余的 printf("a=%d",a); 结果:a=2 例2 int x; i ...
- JS 逗号表达式
JavaScript中逗号运算符 JavaScript中逗号运算符(,)是顺序执行两个表达式.使用方法: expression1, expression2 其中expression1是任何表达式.ex ...
- js 两个小括号 ()() 的用法
实现一个函数fn, 使fn(1)(2)的结果为两个参数的和,刚开始没反应过来,其实细细一想第二个括号就是函数再调用的问题,废话不多说,代码奉上: var fn = function(n) { func ...
随机推荐
- 大数据系列修炼-Scala课程01
简介 由于本人刚毕业,也是从事软件开发相关的工作.想再学习一下关于大数据.移动互联网.云计算相关的技术.为我的未来打好基础.并且从零开始学习大数据相关的知识,脚踏实地的走好每一步,听行业前辈说毕业生刚 ...
- 【足迹C++primer】47、Moving Objects(1)
Moving Objects(1) * 功能:Moving Objects * 时间:2014年7月17日08:46:45 * 作者:cutter_point */ #include<iostr ...
- css+html菜单适应性学习的宽度
本文就是利用css和html自适应于文本菜单的长度. 后效果图实现,例如下列: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvajkwMzgyOTE4Mg= ...
- JAVA转让JS功能
今天,在发展中使用js和Java互动.通常我们使用更多的是js转让Java方法.可以使用dwr.Ajax.jquery.突然发现Java转让js然后,我真的没见过,今天,互联网提供以下信息,顺便总结: ...
- JS 精度问题处理
/除法函数,用来得到精确的除法结果 //说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显.这个函数返回较为精确的除法结果. //调用:accDiv(arg1,arg2) ...
- 记录近期小改Apriori至MapReduce上的心得
·背景 前一阵,一直在研究一些ML的东东,后来工作关系暂停了一阵.现在继续把剩下一些热门的算法再吃吃透,"无聊+逗比"地把他们搞到MapReduce上.这次选择的入手对象为Apri ...
- linux 编译java并打包
一.首先是编译简单java文件(不引用外部jar包)如test.java public class test(){ System.out.println("hello world!" ...
- java抽象类和接口的区别(转载)
1.Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这大概就是Java抽象类唯一的优点吧,但这个优点非常有用. 如果向一个抽象类里加入 ...
- MySQL的C语言编程(一)
原文:MySQL的C语言编程(一) 初学MySQL,记录一下MySQL用c语言编程时遇到的问题. 这是我的源程序: int main(void) { MYSQL *mysql=NULL; if((my ...
- sudo找不到npm的解决办法及及使用cnpm加速[已解决]
sudo ln -s /usr/local/bin/node /usr/bin/node sudo ln -s /usr/local/lib/node /usr/lib/node sudo ln -s ...