Khi nào thì toán tử dấu phẩy hữu ích?


88

Tôi đã đọc câu hỏi này về "toán tử dấu phẩy" trong biểu thức ( ,) và tài liệu MDN về nó, nhưng tôi không thể nghĩ ra tình huống mà nó hữu ích.

Vậy, toán tử dấu phẩy hữu ích khi nào?


2
var i, j, k;vs var i; var j, var k?
Salman A

15
@SalmanA. Tôi không chắc nó có liên quan gì đến ,nhà điều hành. Dòng đó cũng hợp lệ C#, nhưng ,toán tử không tồn tại ở đó.
gdoron đang hỗ trợ Monica

2
@SalmanA. Tôi đã làm. Không tìm thấy nó, Enlight tôi ...
gdoron đang hỗ trợ Monica

5
@SalmanA a ,không phải lúc nào cũng là ,toán tử (và nó không bao giờ là ,toán tử trong C #). Vì vậy, C # có thể thiếu ,toán tử trong khi vẫn sử dụng tự do ,như một phần của cú pháp.
Seth Carnegie

8
Tôi nghĩ rằng các câu trả lời ở đây đã tóm tắt một thực tế ,là toán tử không được sử dụng rộng rãi (và không phải mọi sự xuất hiện của a ,đều là toán tử dấu phẩy) . Nhưng bạn có thể mượn nó và một Mảng để thực hiện hoán đổi biến nội tuyến mà không cần tạo biến tạm thời. Cho rằng bạn muốn hoán đổi các giá trị của ab, bạn có thể làm a = [b][b = a,0]. Điều này đặt dòng điện bvào Mảng. Thứ hai []là ký hiệu truy cập tài sản. Chỉ mục được truy cập 0, nhưng không phải trước khi gán acho b, hiện được an toàn vì bđược giữ lại trong Mảng. các ,phép chúng tôi làm nhiều biểu thức trong [].

Câu trả lời:


128

Phần sau có lẽ không hữu ích lắm vì bạn không tự viết nó, nhưng một trình thu nhỏ có thể thu nhỏ mã bằng cách sử dụng toán tử dấu phẩy. Ví dụ:

if(x){foo();return bar()}else{return 1}

sẽ trở thành:

return x?(foo(),bar()):1

Các ? :nhà điều hành có thể được sử dụng hiện nay, kể từ khi các nhà điều hành dấu phẩy (đến một mức độ nhất định) cho phép hai câu lệnh được viết như một tuyên bố.

Đây hữu ích ở chỗ nó cho phép đối với một số nén gọn gàng (39 -> 24 byte ở đây).


Tôi muốn nhấn mạnh một thực tế rằng các dấu phẩy trong var a, bkhông toán tử phẩy vì nó không tồn tại trong một biểu hiện . Dấu phẩy có một ý nghĩa đặc biệt trong các var câu lệnh . a, btrong một biểu thức sẽ tham chiếu đến hai biến và đánh giá b, điều này không đúng với var a, b.


3
Bạn nghĩ thế nào về điều đó? Bạn đã đọc nó ở đâu? Nó có thực sự được sử dụng không?
gdoron đang hỗ trợ Monica

16
Hôm trước, tôi chỉ làm rối tung lên với Trình biên dịch đóng cửa để xem nó thực sự làm gì, và tôi đã nhận thấy sự thay thế này.
pimvdb

2
Một cách sử dụng tương tự mà tôi nghĩ hữu ích trong mã của bạn sẽ là để gán nhiều biến trong câu lệnh if nội tuyến. Ví dụ: if (condition) var1 = val1, var2 = val2;Cá nhân tôi nghĩ rằng tránh dấu ngoặc nếu có thể sẽ làm cho mã dễ đọc hơn.
Aidiakapi

2
Khoảng thời gian duy nhất tôi sử dụng toán tử dấu phẩy là khi tôi thêm các câu lệnh nhật ký vào biểu thức (foo => (console.log ('foo', foo), foo)) hoặc nếu tôi quá thông minh với việc giảm số lần lặp . (pair.reduce ((acc, [k, v]) => (acc [k] = v, acc), {}))
Joseph Sikorski

38

Toán tử dấu phẩy cho phép bạn đặt nhiều biểu thức vào một nơi mà một biểu thức được mong đợi. Giá trị kết quả của nhiều biểu thức được phân tách bằng dấu phẩy sẽ là giá trị của biểu thức được phân tách bằng dấu phẩy cuối cùng.

Cá nhân tôi không sử dụng nó thường xuyên vì không có nhiều trường hợp trong đó nhiều hơn một biểu thức được mong đợi và không có cách nào ít khó hiểu hơn để viết mã hơn là sử dụng toán tử dấu phẩy. Một khả năng thú vị là ở cuối forvòng lặp khi bạn muốn nhiều hơn một biến được tăng lên:

// 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
}

Ở đây bạn thấy rằng i++, j++có thể được đặt ở một nơi cho phép một biểu thức. Trong trường hợp cụ thể này, nhiều biểu thức được sử dụng cho ảnh hưởng bên nên không quan trọng khi các biểu thức ghép nhận giá trị của giá trị cuối cùng, nhưng có những trường hợp khác thực sự quan trọng.


38

Toán tử Dấu phẩy thường hữu ích khi viết mã chức năng trong Javascript.

Hãy xem xét đoạn mã này tôi đã viết cho một SPA một thời gian trước có một cái gì đó giống như sau

const actions = _.chain(options)
                 .pairs() // 1
                 .filter(selectActions) // 2
                 .map(createActionPromise) // 3
                 .reduce((state, pair) => (state[pair[0]] = pair[1], state), {}) // 4
                 .value();

Đây là một kịch bản khá phức tạp, nhưng trong thế giới thực. Chịu đựng với tôi trong khi tôi giải thích những gì đang xảy ra và trong quá trình này, hãy tạo trường hợp cho Toán tử Dấu phẩy.


Điều này sử dụng chuỗi của gạch dưới để

  1. Loại bỏ tất cả các tùy chọn được chuyển cho chức năng này bằng cách sử dụng pairs nó sẽ chuyển { a: 1, b: 2}thành[['a', 1], ['b', 2]]

  2. Mảng các cặp thuộc tính này được lọc theo những cặp thuộc tính nào được coi là 'hành động' trong hệ thống.

  3. Sau đó, chỉ mục thứ hai trong mảng được thay thế bằng một hàm trả về một lời hứa đại diện cho hành động đó (sử dụng map)

  4. Cuối cùng lời gọi tới reducesẽ hợp nhất từng "mảng thuộc tính" ( ['a', 1]) lại thành một đối tượng cuối cùng.

Kết quả cuối cùng là một phiên bản đã biến đổi của optionsđối số, chỉ chứa các khóa thích hợp và có giá trị được hàm gọi tiêu thụ.


Chỉ nhìn vào

.reduce((state, pair) => (state[pair[0]] = pair[1], state), {})

Bạn có thể thấy hàm giảm bắt đầu với một đối tượng trạng thái trống statevà đối với mỗi cặp đại diện cho một khóa và giá trị, hàm trả về cùng một stateđối tượng sau khi thêm một thuộc tính vào đối tượng tương ứng với cặp khóa / giá trị. Do cú pháp hàm mũi tên của ECMAScript 2015, thân hàm là một biểu thức và do đó, Toán tử dấu phẩy cho phép một hàm "lặp" ngắn gọn và hữu ích .

Cá nhân tôi đã gặp rất nhiều trường hợp khi viết Javascript theo phong cách chức năng hơn với ECMAScript 2015 + Hàm mũi tên. Phải nói rằng, trước khi gặp các hàm mũi tên (chẳng hạn như tại thời điểm viết câu hỏi), tôi chưa bao giờ sử dụng toán tử dấu phẩy theo bất kỳ cách cố ý nào.


2
Đây là câu trả lời thực sự hữu ích duy nhất về cách / khi nào một lập trình viên có thể sử dụng toán tử dấu phẩy. Rất hữu ích đặc biệt trongreduce
hgoebl

1
Với ES6 +, đây phải là câu trả lời được chấp nhận.
Ardee Aram

Nice câu trả lời, nhưng nếu tôi có thể đề nghị một cái gì đó hơi dễ đọc hơn: .reduce((state, [key, value]) => (state[key] = value, state), {}). Và tôi nhận ra điều này đánh bại mục đích của câu trả lời nhưng .reduce((state, [key, value]) => Object.assign(state, { [key]: value }), {})sẽ loại bỏ hoàn toàn sự cần thiết của toán tử dấu phẩy.
Patrick Roberts

Mặc dù Object.assign ngày nay có lẽ dễ thành ngữ hơn hoặc thậm chí chỉ là toán tử lây lan, tôi không chắc chúng đã được sử dụng rộng rãi vào thời điểm đó hay chưa. Tôi cũng sẽ chỉ ra rằng mặc dù toán tử dấu phẩy khó hiểu hơn một chút, điều này có thể tạo ra ít rác hơn rất nhiều trong các tình huống mà tập dữ liệu rất lớn. Tuy nhiên, cấu trúc hủy chắc chắn sẽ giúp dễ đọc!
Syynth

18

Một cách sử dụng khác cho toán tử dấu phẩy là ẩn các kết quả bạn không quan tâm trong repl hoặc bảng điều khiển, hoàn toàn là một sự tiện lợi.

Ví dụ: nếu bạn đánh giá myVariable = aWholeLotOfTexttrong repl hoặc bảng điều khiển, nó sẽ in tất cả dữ liệu bạn vừa gán. Đây có thể là các trang và các trang, và nếu bạn không muốn xem nó, thay vào đó bạn có thể đánh giá myVariable = aWholeLotOfText, 'done'và repl / console sẽ chỉ in 'xong'.

Oriel đã chỉ ra một cách chính xác rằng các chức năng toString()hoặc tùy chỉnh get()thậm chí có thể làm cho điều này trở nên hữu ích.


1
Ha, ý kiến ​​rất hay! (Cuối cùng một câu trả lời mà thực sự trả lời câu hỏi không giống như hầu hết tất cả các câu trả lời {và 3 câu trả lời đã bị xóa mà bạn cần 20K uy tín để xem ...})
gdoron đang hỗ trợ Monica

1
Nếu giá trị được gán là một đối tượng, bảng điều khiển có thể cố gắng hiển thị nó một cách độc đáo. Để làm điều đó, nó có thể gọi getters ví dụ, có thể thay đổi trạng thái của đối tượng. Sử dụng dấu phẩy có thể ngăn chặn điều này.
Oriol

@Oriol - Đẹp! Bạn hoàn toàn chính xác. Bằng cách nào đó điều này có khả năng hữu ích cảm thấy hơi thất vọng :)
Julian de Bhal

13

Toán tử dấu phẩy không dành riêng cho JavaScript, nó có sẵn trong các ngôn ngữ khác như C và C ++ . Là một toán tử nhị phân, điều này hữu ích khi toán hạng đầu tiên, thường là một biểu thức, có tác dụng phụ mong muốn được yêu cầu bởi toán hạng thứ hai. Một ví dụ từ wikipedia:

i = a += 2, a + b;

Rõ ràng là bạn có thể viết hai dòng mã khác nhau, nhưng sử dụng dấu phẩy là một lựa chọn khác và đôi khi dễ đọc hơn.


1
Hãy coi đây là một giải pháp thay thế, mặc dù định nghĩa về điều tốt có thể khác nhau ở mỗi người. Tuy nhiên, tôi không thể tìm thấy bất kỳ ví dụ nào mà bạn PHẢI sử dụng dấu phẩy. Một điều tương tự khác là toán tử ternary ?:. Điều đó luôn có thể được thay thế bằng if-else nhưng đôi khi ?: làm cho mã dễ đọc hơn if-else. Khái niệm tương tự cũng đi với dấu phẩy.
taskinoor

BTW, tôi không xem xét việc sử dụng dấu phẩy trong khai báo biến hoặc khởi tạo nhiều biến trong vòng lặp. Trong những trường hợp đó, dấu phẩy thường tốt hơn.
taskinoor

2
điều này có vẻ khó hiểu af ... wtf.
Timmerz

6

Tôi không đồng ý với Flanagan và nói rằng, dấu phẩy thực sự hữu ích và cho phép viết mã dễ đọc và thanh lịch hơn, đặc biệt là khi bạn biết mình đang làm gì:

Đây là bài viết rất chi tiết về cách sử dụng dấu phẩy:

Một số ví dụ từ đó cho bằng chứng minh chứng:

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

Một trình tạo fibonacci:

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

Tìm phần tử mẹ đầu tiên, phần tử tương tự của .parent()hàm jQuery :

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">

7
Tôi không chắc chắn nếu tôi có thể nói bất kỳ điều đó là dễ đọc hơn nhưng nó chắc chắn khá bắt mắt nên 1
Chris Marisic

1
Bạn không cần dấu phẩy trong vòng lặp while trong ví dụ cuối cùng, while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))sẽ ổn trong ngữ cảnh đó.
PitaJ

5

Tôi chưa tìm thấy cách sử dụng thực tế nào khác ngoài điều đó nhưng đây là một tình huống mà James Padolsey sử dụng kỹ thuật này một cách độc đáo để phát hiện IE trong vòng lặp while:

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;

}());

Hai dòng này phải thực thi:

div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]

Và bên trong toán tử dấu phẩy, cả hai đều được đánh giá mặc dù người ta có thể tạo cho chúng những câu lệnh riêng biệt bằng cách nào đó.


3
Đây có thể là một do- whilevòng lặp.
Casey Chu

5

Có một điều gì đó "kỳ quặc" có thể được thực hiện trong JavaScript khi gọi một hàm gián tiếp bằng cách sử dụng toán tử dấu phẩy.

Có một mô tả dài ở đây: Lệnh gọi hàm gián tiếp trong JavaScript

Bằng cách sử dụng cú pháp này:

(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);
  
  }());

Bạn có thể có quyền truy cập vào biến toàn cục vì evalhoạt động khác nhau khi được gọi trực tiếp và được gọi là gián tiếp.


4

Tôi thấy toán tử dấu phẩy hữu ích nhất khi viết các trợ giúp như thế này.

const stopPropagation = event => (event.stopPropagation(), event);
const preventDefault = event => (event.preventDefault(), event);
const both = compose(stopPropagation, preventDefault);

Bạn có thể thay thế dấu phẩy bằng một dấu || hoặc &&, nhưng sau đó bạn cần biết hàm trả về những gì.

Quan trọng hơn, dấu phân cách bằng dấu phẩy truyền đạt ý định - mã không quan tâm toán hạng bên trái đánh giá là gì, trong khi các lựa chọn thay thế có thể có một lý do khác để tồn tại ở đó. Điều này làm cho nó dễ hiểu hơn và dễ dàng cấu trúc lại. Nếu kiểu trả về của hàm luôn thay đổi, đoạn mã trên sẽ không bị ảnh hưởng.

Đương nhiên, bạn có thể đạt được điều tương tự theo những cách khác, nhưng không ngắn gọn như vậy. Nếu || và && đã tìm thấy một vị trí được sử dụng phổ biến, toán tử dấu phẩy cũng vậy.


Tương tự như những gì Ramda \ Lodash làm với tap( ramdajs.com/docs/#tap ). Về cơ bản, bạn đang thực thi một hiệu ứng phụ và sau đó trả về giá trị ban đầu; rất hữu ích trong lập trình chức năng :)
avalanche1

1

Một trường hợp điển hình mà tôi sử dụng nó là trong khi phân tích cú pháp đối số tùy chọn. Tôi nghĩ rằng nó làm cho nó dễ đọc hơn và ngắn gọn hơn để phân tích cú pháp đối số không chi phối thân hàm.

/**
 * @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();

  // ...
}

Mặc dù bản thân tôi không ủng hộ nó, nhưng đây là ví dụ duy nhất mà bất kỳ ai đưa ra mà tôi nghĩ rằng một người có thể nói là tốt hơn để dễ đọc hơn so với danh sách tương đương của các câu biểu cảm riêng lẻ mà tôi không nghĩ rằng họ hoàn toàn mất trí.
Dấu chấm phẩy

1

Giả sử bạn có một mảng:

arr = [];

Khi bạn pushvào mảng đó, bạn hiếm khi quan tâm đến pushgiá trị trả về của ', cụ thể là độ dài mới của mảng, mà thay vào đó là chính mảng:

arr.push('foo')  // ['foo'] seems more interesting than 1

Sử dụng toán tử dấu phẩy, chúng ta có thể đẩy vào mảng, chỉ định mảng là toán hạng cuối cùng thành dấu phẩy, và sau đó sử dụng kết quả - chính mảng - cho một lệnh gọi phương thức mảng tiếp theo, một loại chuỗi:

(arr.push('bar'), arr.push('baz'), arr).sort(); // [ 'bar', 'baz', 'foo' ]

-2

Một lĩnh vực khác mà toán tử dấu phẩy có thể được sử dụng là Code Obfuscation .

Giả sử một nhà phát triển viết một số mã như thế này:

var foo = 'bar';

Bây giờ, cô ấy quyết định làm xáo trộn mã. Công cụ được sử dụng có thể thay đổi mã như sau:

var Z0b=(45,87)>(195,3)?'bar':(54,65)>(1,0)?'':'baz';// Z0b == 'bar'

Demo: http://jsfiddle.net/uvDuE/


1
@gdoron Vui lòng xem câu trả lời này stackoverflow.com/a/17903036/363573 về Toán tử dấu phẩy trong C ++. Bạn sẽ nhận thấy bình luận của James Kanze về sự xáo trộn.
Stephan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.