我看了这个关于表达式(以下简称“逗号操作”的问题,
)和MDN文档有关,但我想不出一个场景的地方是有用的。
那么,逗号运算符什么时候有用?
,
操作员有什么关系。该行在其中也有效C#
,但是,
运算符在那里不存在。
,
并不总是,
运算符(并且,
在C#中也不是运算符)。因此,C#可能缺少,
运算符,而仍然可以自由使用,
作为语法的一部分。
Answers:
以下内容可能不是很有用,因为您不是自己编写的,但是minifier可以使用逗号运算符收缩代码。例如:
if(x){foo();return bar()}else{return 1}
会成为:
return x?(foo(),bar()):1
? :
现在可以使用该运算符,因为逗号运算符(在一定程度上)允许将两个语句写为一个语句。
这是有用的,因为它允许一些整齐压缩(39 -这里> 24字节)。
我想强调的是,在逗号var a, b
是不是逗号运算符,因为它没有一个中存在的表达。var
语句中的逗号具有特殊含义。a, b
在表达式中将引用两个变量并求和为b
,而不是var a, b
。
if (condition) var1 = val1, var2 = val2;
我个人认为尽可能避免使用方括号会使代码更具可读性。
逗号运算符使您可以将多个表达式放在期望一个表达式的位置。 用逗号分隔的多个表达式的结果值将是最后一个逗号分隔的表达式的值。
我个人并不经常使用它,因为在很多情况下期望不只一个表达式,并且没有比使用逗号运算符更容易混淆的代码编写方式了。一种有趣的可能性是,for
当您希望递增多个变量时,在循环的结尾:
// j is initialized to some other value
// as the for loop executes both i and j are incremented
// because the comma operator allows two statements to be put in place of one
for (var i = 0; i < items.len; i++, j++) {
// loop code here that operates on items[i]
// and sometimes uses j to access a different array
}
在这里,您可以看到i++, j++
可以将其放置在允许一个表达式的地方。在这种特殊情况下,多个表达式可用于副作用,因此复合表达式采用最后一个表达式的值并不重要,但是在其他情况下,这实际上可能很重要。
用Java编写功能代码时,逗号运算符通常非常有用。
考虑一下我为SPA写的这段代码,其中包含以下内容
const actions = _.chain(options)
.pairs() // 1
.filter(selectActions) // 2
.map(createActionPromise) // 3
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
.value();
这是一个相当复杂但真实的场景。在我解释正在发生的事情时,请耐心等待,在此过程中,请为逗号运算符辩护。
分解传递给此函数的所有选项,使用pairs
它将{ a: 1, b: 2}
变为[['a', 1], ['b', 2]]
该属性对数组将被系统中被视为“操作”的属性对过滤。
然后,将数组中的第二个索引替换为一个函数,该函数返回表示该操作的Promise(使用map
)
最终,对的调用reduce
会将每个“属性数组”(['a', 1]
)合并回最终对象。
最终结果是options
参数的转换版本,该参数仅包含适当的键,并且其值可由调用函数使用。
看着只是
.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})
您可以看到reduce函数以一个空状态对象开头state
,并且对于每个表示键和值的对,该函数state
在将属性添加到与键/值对相对应的对象后,将返回同一对象。由于ECMAScript 2015的箭头函数语法,函数主体是一个表达式,因此,逗号运算符允许使用简洁而有用的“ iteratee”函数。
我个人遇到过很多案例,同时使用ECMAScript 2015 + Arrow Functions以更实用的样式编写Javascript。话虽如此,在遇到箭头功能之前(例如在编写问题时),我从未以任何故意的方式使用逗号运算符。
reduce
.reduce((state, [key, value]) => (state[key] = value, state), {})
。而且我意识到这违反了答案的目的,但.reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})
将完全不需要逗号运算符。
逗号运算符的另一种用途是纯粹为了方便而将您不关心的结果隐藏在repl或控制台中。
例如,如果您myVariable = aWholeLotOfText
在repl或控制台中进行评估,它将打印您刚刚分配的所有数据。这可能是页面和页面,如果不想看到它,可以评估myVariable = aWholeLotOfText, 'done'
,并且repl / console只会打印“ done”。
Oriel正确指出†定制toString()
或get()
功能甚至可以使此功能有用。
逗号运算符不特定于JavaScript,它在其他语言(例如C和C ++)中可用。作为二进制运算符,当第一操作数(通常是表达式)具有第二操作数所需的所需副作用时,这很有用。维基百科的一个例子:
i = a += 2, a + b;
显然,您可以编写两行不同的代码,但是使用逗号是另一种选择,有时更易读。
我不同意Flanagan,并且说逗号非常有用,并且允许编写更易读和优雅的代码,尤其是当您知道自己在做什么的时候:
这是有关逗号用法的非常详细的文章:
那里有几个例子可以证明这一点:
function renderCurve() {
for(var a = 1, b = 10; a*b; a++, b--) {
console.log(new Array(a*b).join('*'));
}
}
斐波那契发生器:
for (
var i=2, r=[0,1];
i<15;
r.push(r[i-1] + r[i-2]), i++
);
// 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377
查找第一个父元素,类似于jQuery.parent()
函数:
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">
while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))
在这种情况下就可以了。
除此之外,我还没有发现它的实际用途,但是在以下情况下,James Padolsey在while循环中很好地使用了该技术来进行IE检测:
var ie = (function(){
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while ( // <-- notice no while body here
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
);
return v > 4 ? v : undef;
}());
必须执行这两行:
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
在逗号运算符内部,虽然可以使它们以某种方式成为独立的语句,但两者都被评估。
do
-while
循环。
在JavaScript中,可以通过使用逗号运算符间接调用函数来完成“奇数”操作。
这里有很长的描述: JavaScript中的间接函数调用
通过使用以下语法:
(function() {
"use strict";
var global = (function () { return this || (1,eval)("this"); })();
console.log('Global === window should be true: ', global === window);
var not_global = (function () { return this })();
console.log('not_global === window should be false: ', not_global === window);
}());
您可以访问全局变量,因为eval
直接调用和间接调用的工作方式不同。
我发现在编写此类助手时,逗号运算符最有用。
const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);
您可以用||代替逗号 或&&,但是您需要知道该函数返回什么。
更为重要的是,逗号分隔符传达了意图-代码不在乎左操作数的计算结果,而替代方法可能还有另一个原因。反过来,这使得它更易于理解和重构。如果函数的返回类型发生变化,则上面的代码将不受影响。
当然,您可以通过其他方式实现同一目标,但并非那么简单。如果|| &&&找到了常用的地方,逗号运算符也找到了。
tap
(ramdajs.com/docs/#tap)。本质上,您正在执行副作用,然后返回初始值。在函数式编程中非常有用:)
我最终使用它的一种典型情况是在可选参数解析期间。我认为这使它更具可读性和简洁性,因此参数解析不会控制函数主体。
/**
* @param {string} [str]
* @param {object} [obj]
* @param {Date} [date]
*/
function f(str, obj, date) {
// handle optional arguments
if (typeof str !== "string") date = obj, obj = str, str = "default";
if (obj instanceof Date) date = obj, obj = {};
if (!(date instanceof Date)) date = new Date();
// ...
}
可以使用逗号运算符的另一个区域是代码混淆。
假设开发人员编写了如下代码:
var foo = 'bar';
现在,她决定混淆代码。使用的工具可能会更改如下代码:
var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'
var i, j, k;
与var i; var j, var k
?