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?
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?
,
nhà điều hành. Dòng đó cũng hợp lệ C#
, nhưng ,
toán tử không tồn tại ở đó.
,
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.
,
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 a
và b
, bạn có thể làm a = [b][b = a,0]
. Điều này đặt dòng điện b
và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 a
cho 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:
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 là 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, b
là khô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, b
trong 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
.
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.
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 for
vò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.
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.
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]]
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.
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
)
Cuối cùng lời gọi tới reduce
sẽ 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 state
và đố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.
reduce
.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.
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 = aWholeLotOfText
trong 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.
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.
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">
while ((el = el.parentNode) && (el.tagName != tagName.toUpperCase()))
sẽ ổn trong ngữ cảnh đó.
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 đó.
do
- while
vòng lặp.
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ì eval
hoạt động khác nhau khi được gọi trực tiếp và được gọi là gián tiếp.
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.
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 :)
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();
// ...
}
Giả sử bạn có một mảng:
arr = [];
Khi bạn push
vào mảng đó, bạn hiếm khi quan tâm đến push
giá 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' ]
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'
var i, j, k;
vsvar i; var j, var k
?