JavaScript 逗号操作符

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

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

它是做什么的?

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

var a = (7, 5);
a;   //5

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

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

因为运算符的优先级。一个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;  //4

这个等于:

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

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

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

//设置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预计只有一个。逗号操作符很少是必要的,但是通常很有用,偶尔地非常优雅:

 1 var r = [], n = 0, a = 0, b = 1, next;
 2
 3 function nextFibonacici(){
 4     next = a+b;
 5     return b =(a=b, next);
 6 }
 7
 8 while(n++ < 10){
 9     r.push(nextFibonacici();)
10 }
11
12 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();  //298207139
getRandomPrime();  //308547853

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

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

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

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

 1 //(LHE: left hand expression,  RHE  right hand expression)
 2
 3 LHE && RHE
 4 1. 总是会执行左边的表达式
 5 2. 如果左边是true,执行右边
 6
 7 LHE || RHE
 8 1. 总是会执行左边表达式
 9 2. 如果左边是false,执行右边
10
11 LHE, RHE
12 1. 总是执行左边表达式
13 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/

时间: 2024-10-13 02:09:38

JavaScript 逗号操作符的相关文章

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

一.乘性操作符 1.乘法:*      乘法操作符的一些特殊规则: 如果操作数都是数值,按照常规的乘法计算,如果乘积超过了ECMAscript数值的表示范围,则返回infinity或者-infinity 如果有一个操作数是NaN,那返回结果就是NaN 如果是infinity与0相乘,返回NaN 如果infinity与非0数相乘,返回infinity或者-infinity infinity与infinity相乘,返回infinity 如果有一个操作数不是数值,后台会先调用number()将其转化为

JavaScript 逗号运算符

   思考   关于逗号选择器并不是很重要的一个知识点,但是我在写这篇博客查阅资料的时候发现一个很奇怪的问题. 在<JavaScript高级程序设计>这本书中说:逗号选择器多用于声明多个变量,除此之外还可以用于赋值. 在 MDN中并不认为 var 语句中的逗号属于逗号操作符,而将其看作是 var 语句中的特殊符号. 姑且认为var中的逗号可以理解为逗号分隔,不是逗号运算符. 使用逗号运算符可以在一条语句中执行多个操作. 在<JavaScript高级程序设计>这本书中认为逗号操作符,

第39课 逗号操作符的分析

1. 逗号操作符 (1)逗号表达式用于将多个子表达式连接为一个表达式 (2)逗号表达式的值为最后一个子表达式的值 (3)逗号表达式的前N-1个子表达式可以没有返回值 (4)逗号表达式按照从左向右的顺序计算每个子表达式的值 exp1,exp2,exp3,…,expN; [实例分析]逗号表达式的示例 #include <iostream> using namespace std; void func(int i) { cout << "func(): i = " &

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

一.switch-case switch-case语句主要用在多分支条件的环境中,在这种环境中使用if语句会存在烦琐且效率不高的弊端. switch(expression) { case const expression1: .... case const expression2; ... default: ... } 在执行过程中,expression的值会与每个case的值比较,实现switch语句的功能.关键字case和它所关联的值被称作case标号.每个case标号的值都必须是一个整形常

逗号操作符

不能用逗号操作符将两个声明组合起来,这是因为声明已经将逗号用于其他用途-----分割列表中的变量.例如: int j = 0,i = 3; 到目前为止,逗号操作符最常见的用途是将两个或更多的表达式放到一个for循环表达式中.不过C++还为这个操作符提供了另外两个特性.首先,它确保先计算第一个表达式,然后计算第二个表达式(换句话说,逗号操作符是一个顺序点).如下所示的表达式是安全的: i = 20,j = 2 * i;//i set to 20,j set to 40 其次,C++规定,逗号表达式

从头认识java-2.6 逗号操作符

这一章节我们来聊一下逗号操作符. 注意:不是逗号分割符. package com.ray.ch03; public class Test { public static void main(String[] args) { for (int i = 0, j = 0; i < 5 && j < 4; i++, j += 2) { System.out.println("i:" + i + " j:" + j); } } } 输出: i:0

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

原文:从头开始学JavaScript (四)--操作符 一.一元操作符 1.自增自减操作符:分为前置型和后置型: 前置型:++a;--a; 后置型:a++;a--; 例: 1 <script type="text/javascript"> 2 var a, b,i= 1,j=1; 3 a=i++; 4 b=++j; 5 alert("a="+a+",i="+i+",b="+b+",j="+j);

细说javascript typeof操作符

细说javascript typeof操作符 typeof定义 typeof是一元运算符,用来返回操作数类型的字符串.下面是ECAMScript5.1关于typeof的标准定义: NOTE:上面表格标红处应为“object”. typeof疑惑 Value Class Type ------------------------------------- null null object "foo" String string new String("foo") St

逗号操作符重载分析(三十三)

我们之前在 C 语言中也学习过了逗号表达式,那么我们就先来再次重新看看逗号表达式.逗号操作符(,)可以构成逗号表达式,逗号表达式用于将多个子表达式连接为一个表达式,它的值为最后一个子表达式的值.逗号表达式中的前 N-1 个子表达式可以没有返回值,它是按照从左向右的顺序计算每个子表达式的值.例如:exp1,exp2,exp3,...,expN 下来我们以代码为例进行逗号表达式的说明 #include <iostream> #include <string> using namespa