parseInt vs unary plus, khi nào nên sử dụng?


149

Sự khác biệt giữa dòng này là gì:

var a = parseInt("1", 10); // a === 1

và dòng này

var a = +"1"; // a === 1

Thử nghiệm jsperf này cho thấy toán tử đơn nguyên nhanh hơn nhiều trong phiên bản chrome hiện tại, giả sử nó là dành cho node.js!?

Nếu tôi cố gắng chuyển đổi các chuỗi không phải là số cả hai trả về NaN:

var b = parseInt("test" 10); // b === NaN
var b = +"test"; // b === NaN

Vậy khi nào tôi nên sử dụng parseInthơn unary plus (đặc biệt là trong node.js) ???

chỉnh sửa : và sự khác biệt đối với toán tử dấu ngã kép là ~~gì?


Câu trả lời:


169

Xin vui lòng xem câu trả lời này cho một bộ trường hợp đầy đủ hơn




Vâng, đây là một vài sự khác biệt tôi biết:

  • Một chuỗi rỗng ""đánh giá đến a 0, trong khi parseIntđánh giá nó thành NaN. IMO, một chuỗi trống phải là a NaN.

    +'' === 0;              //true
    isNaN(parseInt('',10)); //true
  • Các unary +hành động giống như parseFloatvì nó cũng chấp nhận số thập phân.

    parseIntmặt khác dừng phân tích cú pháp khi thấy một ký tự không phải là số, giống như khoảng thời gian được dự định là dấu thập phân ..

    +'2.3' === 2.3;           //true
    parseInt('2.3',10) === 2; //true
  • parseIntparseFloatphân tích cú pháp và xây dựng chuỗi từ trái sang phải . Nếu họ thấy một ký tự không hợp lệ, nó sẽ trả về những gì đã được phân tích cú pháp (nếu có) dưới dạng một số và NaNnếu không được phân tích thành một số.

    Mặt khác, unary +sẽ trả về NaNnếu toàn bộ chuỗi không chuyển đổi thành số.

    parseInt('2a',10) === 2; //true
    parseFloat('2a') === 2;  //true
    isNan(+'2a');            //true
  • Như đã thấy trong bình luận của @Alex K. , parseIntparseFloatsẽ phân tích theo ký tự. Điều này có nghĩa là các ký hiệu hex và số mũ sẽ thất bại vì xeđược coi là các thành phần không phải là số (ít nhất là trên cơ sở 10).

    Các unary +sẽ chuyển đổi chúng đúng cách mặc dù.

    parseInt('2e3',10) === 2;  //true. This is supposed to be 2000
    +'2e3' === 2000;           //true. This one's correct.
    
    parseInt("0xf", 10) === 0; //true. This is supposed to be 15
    +'0xf' === 15;             //true. This one's correct.

6
Ngoài ra khi sử dụng cơ số+"0xf" != parseInt("0xf", 10)
Alex K.

Tôi thích câu trả lời của bạn nhất từ ​​trước đến nay, bạn cũng có thể giải thích sự khác biệt của toán tử dấu ngã kép ~ ~ là gì không?
hereandnow78

@ hereandnow78 Điều đó sẽ được giải thích ở đây . Nó tương đương với bitwise Math.floor(), về cơ bản cắt bỏ phần thập phân.
Giuse

4
Trên thực tế, "2e3"không phải là một đại diện số nguyên hợp lệ cho 2000. Đó là một số dấu phẩy động hợp lệ mặc dù: parseFloat("2e3")sẽ mang lại chính xác 2000như câu trả lời. Và "0xf"yêu cầu ít nhất là cơ sở 16, đó là lý do tại sao parseInt("0xf", 10)trả về 0, trong khi parseInt("0xf", 16)trả về giá trị của 15 bạn đang mong đợi.
Bart

2
@Joseph the Dreamer và @ hereandnow78: Dấu ngã kép cắt bỏ phần thập phân của số, trong khi Math.floor trả về số thấp nhất gần nhất. Họ làm việc như nhau cho số dương, nhưng Math.floor(-3.5) == -4~~-3.5 == -3.
Albin

261

Bảng chuyển đổi mọi thứ thành số cuối cùng: Bảng chuyển đổi


2
Vui lòng thêm "NaN"vào bảng này.
chharvey

Nó có thể là giá trị thêm một isNaNcột vào bảng này: ví dụ, isNaN("")là sai (tức là nó được coi là một số), nhưng parseFloat("")NaN, có thể là một Gotcha, nếu bạn đang cố gắng sử dụng isNaNđể xác nhận đầu vào trước khi đi qua nó đểparseFloat
Retsam

Bạn cũng nên thêm '{valueOf: function(){return 42}, toString: function(){return "56"}}'vào danh sách. Các kết quả hỗn hợp là thú vị.
m Hurju

3
Vì vậy, tóm tắt của bảng +chỉ là một cách viết ngắn hơn Number, và những người lông thú chỉ là những cách điên rồ để làm điều đó thất bại trong các trường hợp cạnh?
Mihail Malostanidis

Là [] .undef là một thứ, hay đó chỉ là một cách tạo ra không xác định? Không thể tìm thấy bất kỳ bản ghi "undef" nào liên quan đến JS thông qua Google.
jcairney

10

Bảng trong câu trả lời của Jun435 tôi tin là toàn diện, tuy nhiên chúng ta có thể tóm tắt với các mẫu sau:

  • Unary plus không đối xử với tất cả các giá trị giả như nhau, nhưng tất cả chúng đều xuất hiện sai lệch.
  • Unary plus gửi truetới 1, nhưng "true"đến NaN.
  • Mặt khác, parseInttự do hơn cho các chuỗi không phải là chữ số thuần túy. parseInt('123abc') === 123, trong khi +báo cáo NaN.
  • Numbersẽ chấp nhận số thập phân hợp lệ, trong khi parseIntchỉ bỏ mọi thứ qua số thập phân. Do đó, parseIntbắt chước hành vi C, nhưng có lẽ không lý tưởng để đánh giá đầu vào của người dùng.
  • Cả hai cắt khoảng trắng trong chuỗi.
  • parseInt, là một trình phân tích cú pháp được thiết kế xấu , chấp nhận đầu vào bát phân và thập lục phân. Unary plus chỉ mất hexademical.

Các giá trị giả sẽ chuyển đổi Numbertheo sau những gì có ý nghĩa trong C: nullfalseđều bằng không. ""về 0 không hoàn toàn tuân theo quy ước này nhưng đủ ý nghĩa với tôi.

Do đó, tôi nghĩ rằng nếu bạn đang xác thực đầu vào của người dùng, unary plus có hành vi đúng cho mọi thứ trừ việc nó chấp nhận số thập phân (nhưng trong trường hợp thực tế của tôi, tôi quan tâm hơn đến việc bắt đầu vào email thay vì userId, giá trị bị bỏ qua hoàn toàn, v.v.), trong khi parseInt là quá tự do.


2
"Unary plus chỉ mất thập lục phân" Ý bạn không phải là số thập phân?
krillgar

0

Hãy cẩn thận, parseInt nhanh hơn + toán tử đơn nguyên trong Node.JS, thật sai khi + hoặc | 0 nhanh hơn, chúng chỉ nhanh hơn đối với các phần tử NaN.

Kiểm tra này:

var arg=process.argv[2];

rpt=20000;
mrc=1000;

a=[];
b=1024*1024*1024*1024;
for (var i=0;i<rpt;i++)
 a[i]=Math.floor(Math.random()*b)+' ';

t0=Date.now();
if ((arg==1)||(arg===undefined))
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  c=a[i]-0;
 }
t1=Date.now();
if ((arg==2)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  d=a[i]|0;
 }
}
t2=Date.now();
if ((arg==3)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  e=parseInt(a[i]);
 }
}
t3=Date.now();
 if ((arg==3)||(arg===undefined)) {
 for (var j=0;j<mrc;j++) for (var i=0;i<rpt;i++) {
  f=+a[i];
 }
}
t4=Date.now();

console.log(a[i-1],c,d,e,f);
console.log('Eseguiti: '+rpt*mrc+' cicli');
console.log('parseInt '+(t3-t2));
console.log('|0 '+(t2-t1));
console.log('-0 '+(t1-t0));
console.log('+ '+(t4-t3));

-3

Xem xét hiệu suất quá. Tôi đã ngạc nhiên khi parseIntđánh bại unary plus trên iOS :) Điều này hữu ích cho các ứng dụng web chỉ tiêu thụ CPU nặng. Như một quy tắc chung, tôi đề nghị những người chọn tham gia JS xem xét bất kỳ toán tử JS nào khác so với quan điểm hiệu suất di động hiện nay.

Vì vậy, hãy di động trước ;)


Vì các bài đăng khác giải thích họ làm những việc hoàn toàn khác nhau, vì vậy bạn không thể dễ dàng trao đổi một thứ cho những người khác
Bergi

@Bergi, phải, nhưng họ cũng có nhiều điểm chung. Hãy cho tôi biết chỉ một giải pháp hiệu suất trong JavaScript chắc chắn là lựa chọn đúng đắn duy nhất? Nói chung đó là lý do tại sao các quy tắc ngón tay cái ra khỏi đó cho chúng ta. Phần còn lại là nhiệm vụ cụ thể.
Arman McHitarian

3
@ArmanMcHitaryan đây là vi mô hóa vô dụng và nó không có giá trị. Kiểm tra bài viết này - fabien.potencier.org/article/8/ từ
webvitaly

@webvitaly, bài viết hay. Luôn có những anh chàng rất định hướng ngoài kia, những người chỉ thích viết mã "nhanh nhất có thể" và trong một số dự án cụ thể không tệ. Đó là lý do tại sao tôi đã đề cập đến "những người lựa chọn JS để xem xét". Tất nhiên đây không phải là PHẢI :), nhưng bản thân tôi cũng thấy nó dễ đọc hơn nhiều.
Arman McHitarian

Bạn có một trích dẫn cho điều này? Liên kết của bạn bị hỏng.
djechlin
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.