让我们从一个有趣的微博开始吧。

末尾的c是优先级最低的逗号操作符。逗号操作符是操作符优先级的最后一行,并且很少有文章记录,它隐藏着它的锋芒。它可能不是JavaScript强势操作符,但是我喜欢它。它简单、优雅并且你应该让它成为你的朋友。所以,我们开始吧--你需要更多了解JavaScript这个害羞英雄。

它是做什么的?

逗号操作符评估它的操作数(从左到右)并返回第二个操作数的值。(MDC

var a = (7, 5);
a; // var x, y, z;
x = (y=1, z=4);
x; //
y; //
z; //

你为什么把这些变量放在括号里?

因为运算符的优先级。一个JavaScript语句可以保护多个不同的运算符,下面语句包含三个运算符(*,+和,);

return 5 * 2 + 3, 22;

在一个语句中运算符优先级决定了运算符执行的顺序。运算符优先顺序的完整列表在这里。逗号运算符是所有运算符优先级最低的操作符。让我们模拟上面的例子怎么运行的:

// 原始的
return 5 * 2 + 3, 22;
// 运行*操作符
return 10 + 3, 22;
//运行+操作符
return 13, 22;
//运行 , 操作符
return 22;

现在让我们使用这些知识来看看如果我们不把这些变量放在括号里会发生什么:它有效的拥有最高的优先级。确保操作运算符优先执行:

//原始语句
var a = (7, 5);
// 执行组
var a = 5;
//原始语句
var a = 7, 5;
//运行 = 运算符
var a, 5; //a 现在等于7
//SyntaxError: missing variable name

通过将等号右边表达式放在括号里,我们创建了一个组 - 它有效的拥有最高的优先级。这个确保了逗号运算符能首先执行:

//原始语句
var a = (7,5);
//运行组
var a = 5;

在实践中,最低的运算符优先级确实使逗号操作符非常强大。事实上逗号操作符说:去吧,先去看看所有其他小的操作符,然后再来我这决斗结果。

一些语句中包含多个逗号。它们怎么运行的?

上面的规则仍然适用。在语句中每个逗号操作符从左到右有序的运行着。

var a = (1, 2, 3, 4);
a; //

这个等于:

var a = (((1, 2), 3), 4);
a; //

逗号用于文本类型和声明怎么样?

这些是逗号分隔符而不是逗号操作符。逗号分隔符的目的是将成员划分到列表中。例如:

//设置4个数组元素
var arr = [1, 2, 3, 4]; //创建拥有2个属性的对象
var obj = {
a: 22,
f: function(){return this.a * this.a}
} //定义3个不同的变量
var a = 1, b = 2, c = 3; // 调用一个函数并传递2个参数
Math.max(4, 7);

为什么使用逗号操作符?

因为他们让你指定多个表达式,而JavaScript预计只有一个。逗号操作符很少是必要的,但是通常很有用,偶尔地非常优雅:

 var r = [], n = 0, a = 0, b = 1, next;

 function nextFibonacici(){
next = a+b;
return b =(a=b, next);
} while(n++ < 10){
r.push(nextFibonacici();)
} r; //[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
function getRandomPrime(){
while(n = Math.round(Math.random()*1000000000), !isPrime(n));
return n;
} var isPrime = function(n){
d = Math.ceil(Math.sqrt(n));
while(n%(d--) && d);
return !d;
} getRandomPrime(); //
getRandomPrime(); //

难道逗号操作符只是一个伪装的分号?

分号操作符分隔语句。逗号操作符分隔语句中的表达式。

为什么不使用逻辑与&&操作符来评估多个表达式的顺序?

逗号操作符是逻辑与&&和逻辑或操作符的亲密的表弟。三个操作符都会返回他们评估的最后一个表达式。他们的区别也简单:

 //(LHE: left hand expression,  RHE  right hand expression)

 LHE && RHE
1. 总是会执行左边的表达式
2. 如果左边是true,执行右边 LHE || RHE
1. 总是会执行左边表达式
2. 如果左边是false,执行右边 LHE, RHE
1. 总是执行左边表达式
2. 总是执行右边表达式

当两个表达式都必须要执行时,选择逗号操作符。

来点更多的例子咋样?

好的。前面我提到了逗号操作符使你指定多个表达式,而JavaScript只预定一个。这个或许是在for循环的范围:

for loops

这个是另外一个版本的斐波那契,也使用逗号操作符:

for(
var i = 2, r = [0,1];
i<15;
r.push(r[i-2]+r[i-1]), i++
);
r; // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]

另一个例子,一个实用实例,帮助商品店员为客户选择钞票和硬币。下面是一个基本的版本。我们使用逗号操作符来等分for循环的第二个表达式。这使我们在测试限制表达式之前增加货币计算器:

function toCurrency(total, values){
total *= 100;
for(
var i =0, counts = [];
counts[i] = total/values[i], total = total % values[i];
i++); return counts.map(Math.floor);
} toCurrency(32.47, [500, 100, 25, 10, 5, 1]); //[6, 2, 1, 2, 0, 2]

现在下面是相同的实用实例,增加了对用户友好的格式:

function toCurrency(total, values, sym){
total *= 100;
// do the calc
for(
var i=0, counts = [];
counts[i]=total/values[i],total=total%values[i];
i++
);
//format
var results = counts.map(function(s,i){
return s>=1&&[Math.floor(s),"x",(sym || '$')+(values[i]/100).toFixed(2)].join(' ');
});
return results.filter(Boolean).join(', ');
}
toCurrency(19.77, [500,100,25,10,5,1]);
//"3 x $5.00, 4 x $1.00, 3 x $0.25, 2 x $0.01"
toCurrency(19.77, [500,100,50,20,10,5,1], '£');
//"3 x £5.00, 4 x £1.00, 1 x £0.50, 1 x £0.20, 1 x £0.05, 2 x £0.01"
toCurrency(19.77, [500,100,50,20,10,5,2,1], '€');
//"3 x €5.00, 4 x €1.00, 1 x €0.50, 1 x €0.20, 1 x €0.05, 1 x €0.02"

下面函数在一个for循环中使用逗号操作符来同时增加和减少两个计数器。计数器用来在控制台上渲染迷人的曲线:

function renderCurve(){
for(var a=1,b=10;a*b;a++,b--)
console.log(new Array(a*b).join('*'));
} renderCurve() /*
*********
*****************
***********************
***************************
*****************************
*****************************
***************************
***********************
*****************
*********
*/

while循环

你可以使用逗号操作符来创建一个简洁的do-while循环版本。搜索tag匹配的元素祖先。我们再次使用逗号来检查限制表达式:

function firstAncestor(el, tagName) {
while(el = el.parentNode, el && (el.tagName != tagName.toUpperCase()));
return el;
} //element in http://ecma262-5.com/ELS5_HTML.htm
var a = $('Section_15.1.1.2'); firstAncestor(a, 'div'); //<div class="page">

三元条件

三元语法允许每三个组件只有一个表达式。作为一般规则,如果你要使用多个声明,你需要考虑使用if else。然而有时在三元表达式中使用逗号操作符来比较简单的表达式更具有可读性:

//player loses
lives ? (lives--, go()):(gameOver(), exit());

调试

逗号操作符提供了一种低调的方式来注入console logs到你的代码中,而不必重新格式化(你能发现在每种情况下需要调试的错误吗?)。。。

//包含一个故意的错误!!!!
// 当i>n时输出总数
var i=10,n=0,total=0;
while(console.log(i,n),i-->n++);{
total += i*n
}
/*
10 0
9 1
8 2
7 3
6 4
5 5
24
*/
//包含一个故意的错误!!!!
// 总数是数组
var arr = [1,2,3];
for(
var i=0, total=0;
i<arr.length;
console.log(i,total), total += arr[i++]
);
/*
0 0
1 1
2 3
*/
//包含一个故意的错误!!!
//数组成员增加4,并求和
//(是的有更容易的方法来做到这一点)
var testArray = [3, 5, 8, 4], total = 0;
var plusFour = testArray.map(function(e){e + 4});
plusFour.forEach(function(n){console.log(n), isNaN(n) || (total += n)}); /*
undefined
undefined
undefined
undefined
*/

迭代器绑定

var colorIndex = 0,
colors = ["FF0000", "008000", "FF0086", "A2FF00", "0000FF", "800080"]; function selectNextColor(){
return colors[colorIndex++] || colors[colorIndex = 0, colorIndex++];
}

间接调用eval

eval1通常在他们包含上下文调用(例如在运算代码中的this值与周围代码的this值一样)。这是有问题的,因为无法保证重复的eval调用源于相同的上下文。

如kangax描述,我们可以使用时尚的逗号操作符来间接调用eval这将迫使它在全局上下文中执行2

var a = {};

//attempt eval in context of object <code>a</code>
(function() {
eval("this.alert('If you can read this I must be global!')");
}).call(a);
//TypeError: this.alert is not a function //force eval in global context
(function() {
(0,eval)("this.alert('If you can read this I must be global!')");
}).call(a);
//alerts: 'If you can read this I must be global!'

¹ eval的优点的讨论超出了本文的范围。

² 虽然ES5标准确认间接调用eval应该在全局范围内运行,但是不是所有浏览器都兼容(例如,IE<=8)。

总结

你可能没有使用逗号操作符,但可以写很好的JavaScript代码。这是否意味着我只是浪费了你的时间?我希望不是。正如一个广泛的词汇让我们成为更好的演讲者和作者,所以广泛的接触语言特征让我们成为更好的程序员。我们可支配的技术越多,我们就有更多的能力写出优雅、简洁的、可读的代码。

用逗号操作符编写有趣的代码,请分享你的整洁的用法示例!

https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/

JavaScript 逗号操作符的更多相关文章

  1. JavaScript逗号操作符

    今天在CSDN看到一篇文章http://www.csdn.net/article/2014-01-06/2818025-Useful-JavaScript-Tips-Best-Practices?re ...

  2. 从头开始学JavaScript (五)——操作符(二)

    原文:从头开始学JavaScript (五)--操作符(二) 一.乘性操作符 1.乘法:*      乘法操作符的一些特殊规则: 如果操作数都是数值,按照常规的乘法计算,如果乘积超过了ECMAscri ...

  3. __VA_ARGS__与逗号操作符的巧妙结合

    class Test { public: template<class T> Test& operator,(T t) { //具体操作 return *this; } } Tes ...

  4. switch_case,&&,||,条件操作符和逗号操作符,循环语句

    一.switch-case switch-case语句主要用在多分支条件的环境中,在这种环境中使用if语句会存在烦琐且效率不高的弊端. switch(expression) { case const ...

  5. 从头开始学JavaScript (四)——操作符

    原文:从头开始学JavaScript (四)--操作符 一.一元操作符 1.自增自减操作符:分为前置型和后置型: 前置型:++a;--a; 后置型:a++;a--; 例: <script typ ...

  6. 坑:JavaScript 中 操作符“==” 和“===” 的区别

    标题:JavaScript 中 操作符"==" 和"===" 的区别 记录一些很坑的区别: 1. '' == '0' // false 0 == '' // t ...

  7. JavaScript中+操作符的特殊性

    在JavaScript中+操作符有两个作用: (1)加法运算 (2)字符串连接 在使用+操作符进行运算时,当+操作符两边都是数值类型的时候,进行加法运算; 当+操作符两边有任意一边是字符串,则进行字符 ...

  8. JavaScript剩余操作符Rest Operator

    本文适合JavaScript初学者阅读 剩余操作符 之前这篇文章JavaScript展开操作符(Spread operator)介绍讲解过展开操作符.剩余操作符和展开操作符的表示方式一样,都是三个点 ...

  9. ISO/IEC 9899:2011 条款6.5.17——逗号操作符

    6.5.17 逗号操作符 语法 1.expression: assignment-expression expression    ,    assignment-expression 语义 2.一个 ...

随机推荐

  1. 如何理解linux多用户多任务

    Linux 的单用户.多任务: 容易理解. Linux 的多用户.多任务 举个例子,比如LinuxSir.Org 服务器,上面有FTP 用户.系统管理员.web 用户.常规普通用户等.在同一时刻,比如 ...

  2. idea中deployment点击加号没有出现artifact

    转载 在主页面打开ProjectStructure,点击图示的按钮或是按ctrl+shift+alt+s快捷键 打开ProjectStructure后,按照图示依次点击Facets->+号,在弹 ...

  3. asp.net mvc 中使用 iframe 加载相应的静态html页面进行显示

     <iframe src='<%=ResolveUrl("~/Content/HTML_file/Agreement.html")%>' <%@ Page ...

  4. Spring AOP初步总结(一)

    学习AOP有段时间了,一直没空总结一下,导致有些知识点都遗忘了,之后会把以前学过的Spring核心相关的知识点总结一轮... 先大体介绍下Spring AOP的特点(均摘自"Spring i ...

  5. 解决Git在更新项目时报凭证错误(Authentication failed)

    报此错误,大概率原因是用户名和密码弄错了,我用的阿里云,在网上找了半天发现Git远程仓库用的用户名和密码不是阿里云登陆用的账户密码,必须另外设置: 链接:code.aliyun.com/profile ...

  6. linux学习笔记汇总

    linux 文件系统是采用级层树状的目录结构,采用"/"根目录的方式 目录结构: / 根目录           |---root: 存放root用户相关的文件          ...

  7. Struct和Class的区别 转

    C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能.struct能包含成员函数吗? 能!struct能继承吗? 能!!stru ...

  8. Openjudge 1.13-23:区间内的真素数

    总时间限制:  1000ms 内存限制:  65536kB 描述 找出正整数 M 和 N 之间(N 不小于 M)的所有真素数. 真素数的定义:如果一个正整数 P 为素数,且其反序也为素数,那么 P 就 ...

  9. webStorm Ctrl+s 自动格式化 然后 保存 用宏命令

    使用WebStorm的Macros宏指令,实现保存的同时格式化代码,并跳至行尾 https://blog.csdn.net/gyz718/article/details/70556188

  10. 洛谷 P1120 小木棍[数据加强版]

    这道题可能是我做过的数据最不水的一道题-- 题目传送门 这题可以说是神剪枝,本身搜索并不算难,但剪枝是真不好想(好吧,我承认我看了题解)-- 剪枝: 用桶来存储木棍 在输入的时候记录下最长的木棍和最短 ...