What does it do?
The comma operator evaluates both of its operands (from left to right) and returns the value of the second operand. (MDC)
var a = (7, 5); a; //5 var x, y, z x = (y=1, z=4); x; //4 y; //1 z; //4
Why did you wrap those variable assignments in parentheses?
Because of operator precedence. A JavaScript statement can contain multiple, disparate operators. The following statement has three operators (*, + and ,) :
return 5 * 2 + 3, 22;
Operator precedence determines the order in which operators are evaluated within a statement. The full list, in order of precedence is here. The comma operator has the lowest precedence of any operator. Lets simulate how this applies to the above example:
//original return 5 * 2 + 3, 22; //apply * operator return 10 + 3, 22; //apply + operator return 13, 22; //apply , operator return 22;
Now let’s use that knowledge to see what would happen if we hadn’t wrapped the variable assignment in parentheses:
//original var a = 7, 5; //apply = operator var a, 5; //a is now 7 //SyntaxError: missing variable name
By wrapping the right hand expression in parentheses we create a group – which, effectively has the highest precedence. This ensures that the comma operator gets applied first:
//original var a = (7, 5); //apply group var a = 5;
In practice, lowest operator precedence actually makes the comma operator quite powerful. In effect it says: go ahead and see to all those other little operations first, then watch me come and clobber the result.
Some statements contain multiple commas. How does that work?
The above rule still applies. Each comma operator in the statement is processed in sequence from left to right.
var a = (1, 2, 3, 4); a; //4
This is equivalent to:
var a = (((1, 2), 3), 4); a; //4
What about commas used in type literals and declarations?
These are comma separators not comma operators. The purpose of a comma separator is to delimit members in a list. For example:
//set 4 array elements
var arr = [1, 2, 3, 4];
//create an object with 2 properties
var obj = {
a: 22,
f: function() {return this.a*this.a}
}
//define 3 distinct variables
var a = 1, b = 2, c = 3;
//invoke a function passing 2 arguments
Math.max(4, 7);
Why use comma operators?
Because they let you specify more than one expression where JavaScript expects only one. Comma operators are rarely essential but often useful and just occasionally downright elegant:
var r = [], n = 0, a = 0, b = 1, next;
function nextFibonacci() {
next = a + b;
return b = (a = b, next);
}
while(n++ < 10) {
r.push(nextFibonacci());
}
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(); //425593109
getRandomPrime(); //268274719
Isn’t the comma operator just a semicolon in disguise?
Semicolons partition statements. Comma operators partition expressions within statements.
Why wouldn’t I just use the && operator to evaluate multiple expressions sequentially?
The comma operator is a close cousin of the && and || operators. All three operators will return the last expression they evaluate. The distinction is straightforward:
//(LHE: left hand expression, RHE right hand expression) LHE && RHE 1. Always evaluate LHE 2. If LHE is true, evaluate RHE LHE || RHE 1. Always evaluate LHE 2. If LHE is false, evaluate RHE LHE, RHE 1. Always evaluate LHE 2. Always evaluate RHE
Choose the comma operator when both expressions must always be evaluated.
How about some more examples?
Okay. Earlier on I mentioned that comma operators let you specify more than one expression where JavaScript expects only one. This is perhaps most useful within the confines of the for loop:
for loops
Here’s an alternate version of a fibonacci generator, also using the comma operator:
for (
var i=2, r=[0,1];
i<15;
r.push(r[i-1] + r[i-2]), i++
);
r //"0,1,1,2,3,5,8,13,21,34,55,89,144,233,377"
For another example, consider a utility that helps a store clerk select the bills and coins that make up a customer’s change. Here’s the basic version. We use a comma operator to bisect the second statement of the for loop. This lets us neatly increment our currency counter before testing against the limiting expression:
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]
Now here’s the same utility with added formatting for user-friendliness:
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"
This following function uses the comma operator to simultaneously increment and decrement two counters within a for loop. The product of the counters is used to render a rather fetching curve in the console:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--)
console.log(new Array(a*b).join('*'));
}
renderCurve();
/*
*********
*****************
***********************
***************************
*****************************
*****************************
***************************
***********************
*****************
*********
*/
while loops
You can use a comma operator to create a succinct version of the do-while loop. This routine searches an elements ancestry looking for a tag name match. Again we use the comma to perform an action prior to checking the limiting expression:
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">
Ternary conditionals
Ternary syntax allows for only one statement in each of its three components. As a general rule, if you need to use more statements you should consider using if elseinstead. However it’s sometimes more readable when the comma operator is used to combine short succinct expressions within a ternary statement:
//player loses lives ? (lives--, go()) : (gameOver(), exit());
Debugging
The comma operator provides an unobtrusive way to inject console logs into your code without having to reformat (can you spot the errors that necessitated debugging in each case?)…
//CONTAINS AN INTENTIONAL ERROR!!!
//sum products while i > n
var i=10, n=0, total=0;
while(console.log(i,n), i-- > n++); {
total += i*n
}
//CONTAINS AN INTENTIONAL ERROR!!!
//sum an array
var arr = [1,2,3];
for (
var i=0, total=0;
i<arr.length;
console.log(i,total), total += arr[i++]);
)
//CONTAINS AN INTENTIONAL ERROR!!!
//add 4 to members of array and sum it
//(yes there are easier ways to do this!)
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)});
Binding with iterators
@wavded posted this nifty technique for unobtrusively resetting iterators. Again, you don’t need to do it this way – but the tidiness appeals to me:
var colorIndex = 0,
colors = ["FF0000", "008000", "FF0086", "A2FF00", "0000FF", "800080"];
function selectNextColor(){
return colors[colorIndex++] || colors[colorIndex = 0, colorIndex++];
}
Indirect calls to eval
eval¹ calls are normally invoked within their containing context (i.e. the this value in the evaluated code will be the same as the the this value of the surrounding code). This is problematic since there is no guarantee that repeated eval calls will originate in the same context.
As @kangax describes here, we can use the comma operator to fashion an indirect call to eval which will force it to execute in the global context²:
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!'
¹ discussion of the merits of eval are beyond the scope of this article
² although the ES5 standard confirms that indirect calls to eval should run in the global context, not every browser is compliant (i.e. IE <= 8).
Wrap Up
You could probably write perfectly good JavaScript code without ever using the comma operator. Does this mean I just wasted your time? I hope not. Just as an extensive vocabulary makes us better speakers and writers, so a comprehensive access to language features should make us better coders. The more techniques we have at our disposal the greater our ability to write elegant, succinct and readable code. Have fun with comma operators and please share your neat usage examples!
现在很多网站都用不规则矩形来罗列图片,ipad上面很多应该用也都是用的不规则的矩形,但是还要让他们各自都靠近排列,不能有空隙,
这个东西让我想起了俄罗斯方块,这个实现起来很简单,容器里面所有的块元素用绝对定位排列,如果能放的下就放在这里,如果放不下了,在队列中找到能放得下的元素放置,
实在找不到,则换行排列下一行,具体思路是这样。代码里有详细的注释直接看代码吧。
下面是一个demo:
1.js太多要分开了,现在我要这样写了,
view->每个页面对应一个js文件,里面对应的是元素绑定,和错误正确的提示信息,主要就是与dom耦合紧密的。
logic->里面对应的是逻辑操作,比如大量的插件,与dom分离。
base->主要就是基础类库,兼容性封装,与逻辑无关。
view -> logic->base
view -> base
有问题再说!!!
源码地址:http://zhifeiji.aliapp.com/script/validate.js
* 这个验证插件是这样的指定一个form表单
* 里面只需要有如下的结构就可以了
*
* <input name="email" data-validate="vType=requried,when=blur,fail=email不正确,success=不错哦;vType=email,when=blur,fail=密码不能为空&setClass:fail,success=setClass:show;" />
*
* 设置说明:data-validate这个属性标明要验证的格式
* 每个验证用分号隔开(注意英文的哦),vType表示要验证的类型,which表示那个元素触发(默认是自己), when表示什么事件会触发这个判定,fail表示验证失败会出现什么提示这里&表示and,可以有多个操作,
* setClass表示要设置的类用:分开后跟类名,removeClass表示移除类表示你要移除哪个类,这里可以添加html代码,但是不建议添加,这样会使你的html看起来非常混乱,基本上够了
*
* 说明:
* 1 class类中不能使用-,可以使用下划线(_)
* 2 验证的表单框,禁止使用onclick=functino这样绑定事件(!importent)
* 3 addClass removeClass 里面的样式不要相同,否则后果自负
* 4 这里只对submit做了处理,如果是ajax提交需要自己写了哦,这里提供ajax接口
* 5 如果验证一组,则可以通过参数传入该组信息进行分析
* 6 如果要在框的box要改变,那就传参数吧,然后修改方法
* 7 支持多表单,支持多信息提示,比如验证密码的复杂度,每个复杂度定义一个方法,这样就行了,这样能满足大部分情况,支持ajax验证,ajax提交信息,都需要根据具体情况添加你自己的方法了
* 8 validFun,是写验证方法的地方,会自动分配不同方法到不同元素的事件上
*
*
* addForm参数是: {id:formid,which:"self",when:"click"}
*
* 生成后的结构是:{id:formid,ele:form,whichEle:"self",when:""}
*
* 生成事件队列是很有必要的,每个元素的每个事件要有一个验证队列以便于管理
*
* form 数据结构不合理存在问题,需要重新设计,因为如果一个验证失败了下面的验证还会继续,下面的验证结构会覆盖上面的验证结果,不合理
*
* 应改为队列,每个元素的每个验证事件都要有一个事件队列如果一个失败了,就取消后面要执行的验证同时记录每个失败的验证最后统一整理
* which,相应的改为要验证哪个元素,而不是由哪个元素来验证,否则就杯具了config,是写配置信息的地方,正则表达式都在这里
*
*
使用实例,自己用,写一下笔记
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>居中</title>
<style type="text/css">
.succMail {
border: green 1px solid;
}
.failMail {
border: red 1px solid;
}
.succNum {
border: green 1px solid;
background: #cccccc;
}
.failNum {
border: green 1px solid;
background: #eeeeee;
}
.onSucc {
border: 1px solid #a5c760;
background: #f4ffd4;
}
.onFail {
border: 1px solid red;
background: #FFDBDB;
}
</style>
<script type="text/javascript" src="validatePrject/validate.js">
</script>
</head>
<body>
<form id="form1">
<p>
6-8位数字:<input id="s1" name="number" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=不能为空哦!&addClass:onFail&removeClass:onSucc,success=你已经输入值了!&addClass:onFail&removeClass:onSucc;vType=number,when=blur, fail= <span>一定要输入数字哦!</span>&addClass:onFail&removeClass:onSucc,success = 你输入的是正确的!&addClass:onSucc&removeClass:onFail ;vType=len(<8&>6),when=blur,fail=长度太长了哦!&addClass:onFail&removeClass:onSucc,success=长度很合适呵呵!&addClass:onSucc&removeClass:onFail ;" />
</p>
<p>
email:<input id="s2" name="email" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=邮箱不能为空!,success=正确哦!;vType=email,when=blur, fail= <span>email不正确哦!</span>& addClass : failMail & removeClass : succMail,success =email输入正确哦!&addClass:succMail&removeClass:failMail;" />
</p>
<p>
<input id="s3" name="userName" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=username 错误& removeClass: right &addClass : worgnt,success=username正确;vType=email,when=blur, fail= <idv>密码不能为空</st>& addClass : rigte & removeClass : worgn & addClass: soms,success =duahobin&addClass:set;" />
</p>
<p>
选择框:
<select name="sx" data-validate="vType=required,when=change,fail=性别必须要选择& removeClass: right &addClass : worgnt,success=干的好!;">
<option></option>
<option value="m">男</option>
<option value="w">女</option>
</select>
</p>
<p>
多选:<input type="checkbox" /><span>读书</span>
<input type="checkbox" /><span>看书</span>
<!-- 如果是组的话就只能过滤了用参数传进来所有组成员 -->
</p>
<p>
qq号:<input id="qq" name="qq" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=username 错误& removeClass: right &addClass : worgnt,success=username正确;vType=email,when=blur, fail= <idv>密码不能为空</st>& addClass : rigte & removeClass : worgn & addClass: soms,success =duahobin&addClass:set;" />
</p><input type="submit" value="提交"/>
</form><input id="testVd" type="button" name="vem" value="验证" />
<form id="form2">
<p>
6-8位数字:<input id="s1" name="number" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=不能为空哦!&addClass:onFail&removeClass:onSucc,success=你已经输入值了!&addClass:onFail&removeClass:onSucc;vType=number,when=blur, fail= <span>一定要输入数字哦!</span>&addClass:onFail&removeClass:onSucc,success = 你输入的是正确的!&addClass:onSucc&removeClass:onFail ;vType=len(<8&>6),when=blur,fail=长度太长了哦!&addClass:onFail&removeClass:onSucc,success=长度很合适呵呵!&addClass:onSucc&removeClass:onFail ;" />
</p>
<p>
email:<input id="s2" name="email" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=邮箱不能为空!,success=正确哦!;vType=email,when=blur, fail= <span>email不正确哦!</span>& addClass : failMail & removeClass : succMail,success =email输入正确哦!&addClass:succMail&removeClass:failMail;" />
</p>
<p>
<input id="s3" name="userName" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=username 错误& removeClass: right &addClass : worgnt,success=username正确;vType=email,when=blur, fail= <idv>密码不能为空</st>& addClass : rigte & removeClass : worgn & addClass: soms,success =duahobin&addClass:set;" />
</p>
<p>
选择框:
<select name="sx" data-validate="vType=required,when=change,fail=性别必须要选择& removeClass: right &addClass : worgnt,success=干的好!;">
<option></option>
<option value="m">男</option>
<option value="w">女</option>
</select>
</p>
<p>
多选:<input type="checkbox" /><span>读书</span>
<input type="checkbox" /><span>看书</span>
<!-- 如果是组的话就只能过滤了用参数传进来所有组成员 -->
</p>
<p>
qq号:<input id="qq" name="qq" style="displayasdf;" class="asdf" data-validate="vType=required,when=blur,fail=username 错误& removeClass: right &addClass : worgnt,success=username正确;vType=email,when=blur, fail= <idv>密码不能为空</st>& addClass : rigte & removeClass : worgn & addClass: soms,success =duahobin&addClass:set;" />
</p><input type="submit" value="提交"/>
</form>
<script type="text/javascript">
validator.addForm({
id: "form1",
which: "form1",
when: "submit"
});
validator.addForm({
id: "form2",
which: "form2",
when: "submit"
});
</script>
</body>
</html>
这段时间没事干就写个小日历连续,有很多东西碰到。
1.支持css3支持良好的浏览器,ie9 还凑合,ie8就杯具
2.每个js文件尽量独立,不影响其他的js文件还可以异步加载
3.不同浏览器器要有不同的版本的js,ie8 就加载ie8的js,标准就加载标准的js,好处兼容少,性能好,但是会有一些重复代码,个人认为比较好,比yui那种不管什么都加载来要好
4.还有很多要注意的地方没有优化,时间仓促,有兴趣自己搞吧,
地址:zhifeiji.aliapp.com
来两张效果图:




