Lý do gì để sử dụng null thay vì undefined trong JavaScript?


103

Tôi đã viết JavaScript khá lâu rồi và tôi chưa bao giờ có lý do để sử dụng null. Có vẻ như điều đó undefinedluôn được ưu tiên hơn và phục vụ cùng một mục đích theo chương trình. Một số lý do thực tế để sử dụng nullthay thế là undefinedgì?


Đây là một bản sao có thể có của stackoverflow.com/questions/461966/...
lawnsea

Cũng có những phương thức như document.getElementById()vậy có thể trả về nullnhưng không undefined, vậy trong những trường hợp đó, tại sao bạn lại kiểm tra trả về undefined? (Chắc chắn, nó sẽ có tác dụng nếu bạn sử dụng ==chứ không phải ===, nhưng vẫn còn, tại sao bạn cố tình thử nghiệm cho những điều sai trái?)
nnnnnn

Có thể hữu ích nếu có những kiểu có thể đoán trước và điều này có thể hướng dẫn suy nghĩ để sử dụng cái này hay cái khác. Trong trường hợp một đối tượng luôn được trả về, cần thiết hoặc mong muốn theo thiết kế, hãy sử dụng null cho các kết quả sai lệch (ví dụ document.getElementById('does-not-exist')). Các biến var a;và hàm trả về giá trị mặc định là không xác định. Trong quá khứ, null trong phạm vi toàn cầu nên việc sử dụng nó làm chậm quá trình thực thi và khiến tôi thích các kiểu giả khác (false, '', 0) hơn là các tham chiếu miễn phí. Cá nhân tôi tránh null trừ khi có lý do thuyết phục vì tôi nhận thấy nó đơn giản hơn, nói chung là tốt hơn.
jimmont

Câu trả lời:


59

Null và undefined về cơ bản là hai giá trị khác nhau có nghĩa giống nhau. Sự khác biệt duy nhất là trong các quy ước về cách bạn sử dụng chúng trong hệ thống của mình . Như một số người đã đề cập, một số người sử dụng null nghĩa là "không có đối tượng" trong đó đôi khi bạn có thể nhận được một đối tượng trong khi không xác định có nghĩa là không có đối tượng nào được mong đợi (hoặc có lỗi). Vấn đề của tôi với điều đó là nó hoàn toàn tùy tiện và hoàn toàn không cần thiết.

Điều đó nói rằng, có một sự khác biệt chính - các biến không được khởi tạo (bao gồm các tham số hàm mà không có đối số nào được truyền, trong số những thứ khác) luôn không được xác định.

Đó là lý do tại sao trong mã của tôi, tôi không bao giờ sử dụng null trừ khi thứ gì đó tôi không kiểm soát trả về null (đối sánh regex chẳng hạn). Vẻ đẹp của điều này là nó mô phỏng mọi thứ rất nhiều. Tôi không bao giờ phải kiểm tra xem x === không xác định || x === rỗng. Và nếu bạn có thói quen sử dụng == hoặc đơn giản là những thứ như if (x) .... Thôi đi. !xsẽ đánh giá là true cho một chuỗi rỗng, 0, null, NaN - tức là những thứ bạn có thể không muốn. Nếu bạn muốn viết javascript không tệ, hãy luôn sử dụng triple === và không bao giờ sử dụng null (thay vào đó hãy sử dụng undefined). Nó sẽ làm cho cuộc sống của bạn dễ dàng hơn.


137
Tôi không đồng ý với điều này. Null được sử dụng để xác định thứ gì đó trống theo chương trình. Không xác định có nghĩa là tham chiếu không tồn tại. Giá trị null có tham chiếu được xác định là "nothing". Nếu bạn đang gọi một thuộc tính không tồn tại của một đối tượng, thì bạn sẽ nhận được không xác định. Nếu tôi cố tình làm cho thuộc tính đó trống, thì nó phải là rỗng để bạn biết rằng nó có mục đích. Nhiều thư viện javascript hoạt động theo cách này.
com2ghz

6
@ com2ghz Những gì bạn mô tả là một trong nhiều triết lý. Nhiều thư viện js thực sự hoạt động theo cách đó. Nhiều người cũng không hoạt động theo cách đó. Trong javascript, bạn có thể dễ dàng lưu trữ một giá trị không xác định rõ ràng trong một đối tượng hoặc mảng như bạn có thể với null. Ý nghĩa của cả hai hoàn toàn phụ thuộc vào ngữ cảnh. IE họ có nghĩa là những gì bạn muốn họ có nghĩa là.
BT

3
Đó là lý do tại sao JS là một ngôn ngữ kinh khủng. Giống như bạn nói, nhiều thư viện có triết lý riêng nhưng bạn gộp nhiều thư viện cho 1 dự án. Vì vậy, bạn gặp phải nhiều quy ước của các thư viện đó. Bạn cần thực hiện các lần kiểm tra giả khác nhau bao nhiêu lần. Đây sẽ không phải là lần cuối cùng bạn nối một đối tượng null vào một chuỗi và nhận được "null" dưới dạng một chuỗi. Hoặc chuyển 0 dưới dạng giá trị số và tự hỏi tại sao câu lệnh IF xử lý là t là sai.
com2ghz

2
@ com2ghz Vậy JS là một ngôn ngữ khủng khiếp vì nó có cả null và undefined? Tôi có thể đếm hàng tá các quyết định ngôn ngữ tồi trong tất cả các ngôn ngữ chính, js không phải là ngoại lệ ở đây. Tôi thực sự không bao giờ cần hoặc không muốn sử dụng kiểm tra giả trong mã của mình và luôn sử dụng ===hoặc !==. JS là một ngôn ngữ biểu đạt tuyệt vời nếu bạn biết cách sử dụng nó.
BT

6
Đúng. Tôi chỉ biết rằng null/ undefinedphân đôi là cần thiết vì phiên bản đầu tiên của JS không có hasOwnPropertyhoặc intoán tử. Bây giờ nó đã xảy ra, tôi thực sự không hiểu tại sao một trong số chúng không bị loại bỏ trong ES6 hoặc bất kỳ đề xuất ES7 nào mà tôi đã thấy.
Andy

86

Tôi thực sự không có câu trả lời, nhưng theo Nicholas C. Zakas , trang 30 của cuốn sách " JavaScript chuyên nghiệp dành cho nhà phát triển web " :

Khi xác định một biến có nghĩa là sau này giữ một đối tượng, bạn nên khởi tạo biến đó thành nullđối lập với bất kỳ thứ gì khác. Bằng cách đó, bạn có thể kiểm tra rõ ràng giá trị nullđể xác định xem biến đã được lấp đầy bằng tham chiếu đối tượng hay chưa


8
+1 vâng, tôi đồng ý và tôi luôn cố gắng nhớ khởi tạo vars thành null. Sau đó, tôi (khá) chắc chắn rằng điều đó undefinedcó nghĩa là một thảm họa đã xảy ra. Chỉ imho.
Pete Wilson,

9
@Pete - nhưng nó không cho bạn biết gì về "thảm họa", vậy vấn đề là gì? Và bạn chỉ có thể đưa ra giả định đó nếu bạn biết hàm tuân theo quy ước.
RobG

7
Mặt khác, bạn cũng có thể khởi tạo biến bằng var myVar;và kiểm tra rõ ràng giá trị undefinedđể xác định xem nó đã được lấp đầy bằng một tham chiếu đối tượng hay chưa. Quan điểm của tôi là điều này hoàn toàn mang tính học thuật - bạn có thể làm theo cách nào đó, và bất kỳ ai tư vấn cách này hơn cách khác chỉ đơn giản là thúc đẩy quy ước của riêng họ.
thdoan

1
Vấn đề duy nhất tôi gặp phải (kể từ khi tôi bắt đầu với JavaScript 15 năm trước) là bạn quá thường xuyên phải kiểm tra undefinednull. Điều này vẫn thực sự khó chịu. Tôi tránh chỉ định một biến nullchỉ để giảm số lượng nullthử nghiệm thêm .
G Man

4
@GMan - Đây là nơi duy nhất mà phép ==so sánh (trái ngược với ===) có ý nghĩa: v == null(hoặc v == undefined) sẽ kiểm tra giá trị rỗng hoặc không xác định.
Rick Love

14

Vào cuối ngày, bởi vì cả hai nullundefinedbắt buộc phải có cùng một giá trị ( Boolean(undefined) === false && Boolean(null) === false), về mặt kỹ thuật, bạn có thể sử dụng một trong hai để hoàn thành công việc. Tuy nhiên, có một cách đúng đắn, IMO.

  1. Để lại việc sử dụng undefined cho trình biên dịch JavaScript.

    undefinedđược sử dụng để mô tả các biến không trỏ đến một tham chiếu. Nó là thứ mà trình biên dịch JS sẽ chăm sóc cho bạn. Tại thời điểm biên dịch, công cụ JS sẽ đặt giá trị của tất cả các biến được nâng lên thành undefined. Khi công cụ bước qua mã và giá trị có sẵn, công cụ sẽ gán các giá trị tương ứng cho các biến tương ứng. Đối với những biến mà nó không tìm thấy giá trị, các biến sẽ tiếp tục duy trì một tham chiếu đến nguyên thủy undefined.

  2. Chỉ sử dụng null nếu bạn muốn biểu thị rõ ràng giá trị của một biến là "không có giá trị".

    Như @ com2gz trạng thái: nullđược sử dụng để xác định thứ gì đó trống theo lập trình. undefinedcó nghĩa là tham chiếu không tồn tại. Một nullgiá trị có một tham chiếu được xác định là "không có gì". Nếu bạn đang gọi một thuộc tính không tồn tại của một đối tượng, thì bạn sẽ nhận được undefined. Nếu tôi cố tình làm cho tài sản đó trống rỗng, thì nó phải nullnhư vậy để bạn biết rằng nó có mục đích.

TLDR; Không sử dụng undefinednguyên thủy. Đó là một giá trị mà trình biên dịch JS sẽ tự động đặt cho bạn khi bạn khai báo các biến mà không cần gán hoặc nếu bạn cố gắng truy cập các thuộc tính của các đối tượng mà không có tham chiếu. Mặt khác, sử dụngnull if và only nếu bạn cố ý muốn một biến có "không có giá trị".

Tôi không bao giờ đặt bất cứ thứ gì một cách rõ ràng thành không xác định (và tôi chưa gặp điều này trong nhiều cơ sở mã mà tôi đã tương tác). Ngoài ra, tôi hiếm khi sử dụng null. Lần duy nhất tôi sử dụng nulllà khi tôi muốn biểu thị giá trị của một đối số cho một hàm là không có giá trị, tức là:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello

Đây đáng lẽ phải là câu trả lời được chọn
alaboudi

13

không xác định là nơi không có khái niệm về sự vật tồn tại; nó không có kiểu, và nó chưa bao giờ được tham chiếu trước đây trong phạm vi đó; null là nơi thứ được biết là tồn tại, nhưng nó không có giá trị.


4
Làm thế nào để bạn biết nếu một nỗ lực được thực hiện để chỉ định một giá trị, nhưng nó không thành công và không xác định được chỉ định thay thế?
RobG

11

Mọi người đều có cách viết mã riêng và ngữ nghĩa bên trong của riêng họ, nhưng qua nhiều năm, tôi nhận thấy đây là lời khuyên trực quan nhất mà tôi dành cho những người đặt câu hỏi này: khi nghi ngờ, hãy làm những gì JavaScript làm .

Giả sử bạn đang làm việc với các thuộc tính đối tượng như các tùy chọn cho một plugin jQuery ... hãy tự hỏi giá trị mà JavaScript cung cấp cho một thuộc tính vẫn chưa được xác định - câu trả lời là undefined. Vì vậy, trong bối cảnh này, tôi sẽ khởi tạo các loại thứ này bằng 'undefined' để phù hợp với JavaScript (đối với các biến, bạn có thể làm var myVar;thay vìvar myVar = undefined; ).

Bây giờ giả sử bạn đang thao tác DOM ... JavaScript gán giá trị nào cho các phần tử không tồn tại? Câu trả lời là null. Đây là giá trị tôi sẽ khởi tạo nếu bạn đang tạo một biến giữ chỗ mà sau này sẽ giữ một tham chiếu đến một phần tử, đoạn tài liệu hoặc tương tự có liên quan đến DOM.

Nếu bạn đang làm việc với JSON, thì một trường hợp đặc biệt cần được thực hiện: đối với các giá trị thuộc tính không xác định, bạn nên đặt chúng thành ""hoặc nullbởi vì giá trị củaundefined không được coi là định dạng JSON thích hợp.

Với điều này đã nói, như một người đăng trước đó đã bày tỏ, nếu bạn thấy rằng bạn đang khởi tạo nội dung bằng null hoặc undefinednhiều lần trong một lần trăng xanh, thì có lẽ bạn nên xem xét lại cách bạn viết mã ứng dụng của mình.


Trong khi đây là một lập trường tốt, tôi muốn thêm câu trả lời này: stackoverflow.com/a/37980662/883303
Frederik Krautwald

@FrederikKrautwald cảm ơn vì liên kết - đó là sự phân định rất rõ ràng.
thdoan

10

Bạn có thể áp dụng quy ước được đề xuất ở đây, nhưng thực sự không có lý do chính đáng để áp dụng. Nó không được sử dụng một cách nhất quán đủ để có ý nghĩa.

Để làm cho quy ước trở nên hữu ích, trước tiên bạn phải biết rằng hàm được gọi tuân theo quy ước. Sau đó, bạn phải kiểm tra rõ ràng giá trị trả về và quyết định những gì cần làm. Nếu bạn không xác định được , bạn có thể giả định rằng một số loại lỗi đã xảy ra mà hàm được gọi đã biết . Nhưng nếu một lỗi đã xảy ra và hàm đã biết về nó, và việc gửi nó ra môi trường rộng lớn sẽ rất hữu ích, tại sao không sử dụng một đối tượng lỗi? tức là ném một lỗi?

Vì vậy, vào cuối ngày, quy ước thực tế là vô dụng trong bất kỳ điều gì khác ngoài các chương trình rất nhỏ trong môi trường đơn giản.


3

Một tài sản hữu ích trong rỗngkhông xác định không đủ điều kiện:

> null + 3
3
> undefined + 3
NaN

Tôi sử dụng nullkhi tôi muốn 'tắt' một giá trị số hoặc để khởi tạo một số. Lần sử dụng cuối cùng của tôi là thao tác chuyển đổi css:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Không chắc liệu tôi có nên sử dụng suy nghĩ thuộc tính này không ...


2

Các nút và phần tử DOM không phải là không xác định, nhưng có thể là rỗng.

  • NextSibling của con cuối cùng của một phần tử là null.

  • The beforeSibling của con đầu tiên là null.

  • Tham chiếu document.getElementById là null nếu phần tử không tồn tại trong tài liệu.

Nhưng không có trường hợp nào trong số này là giá trị không xác định ; chỉ là không có nút ở đó.


Cảm ơn vì lời giải thích. Đối với tôi, điều này không thể phản trực giác hơn.
tomekwi

Nó thực sự phụ thuộc vào những gì bạn đang cố gắng kiểm tra. Ví dụ: nếu bạn muốn xem liệu một biến toàn cục có tên là 'myVar' có tồn tại hay không, thì window.myVarsẽ trả về 'undefined nếu nó không tồn tại. Có rất nhiều thứ trả về 'không xác định' trong JavaScript, chỉ có rất nhiều thứ trả về 'null' - tất cả phụ thuộc vào ngữ cảnh.
thdoan

2

Một số người đã nói rằng có thể khởi tạo các đối tượng null. Tôi chỉ muốn chỉ ra rằng các mặc định của đối số hủy cấu trúc không hoạt động với null. Ví dụ:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Điều này yêu cầu thực hiện nullkiểm tra trước khi gọi hàm, điều này có thể xảy ra thường xuyên.


1

Tôi đang giải quyết câu hỏi chính xác này ngay bây giờ và xem xét triết lý sau:

  1. Bất kỳ hàm nào được dự định trả về kết quả sẽ trả về null nếu nó không tìm thấy kết quả
  2. Bất kỳ hàm nào KHÔNG nhằm mục đích trả về kết quả sẽ mặc nhiên trả về không xác định.

Đối với tôi, câu hỏi này rất quan trọng vì bất kỳ ai gọi một hàm trả về kết quả sẽ không có câu hỏi về việc liệu có nên kiểm tra undefined vs null hay không.

Câu trả lời này không cố gắng giải quyết:

  1. Giá trị thuộc tính của null so với không xác định
  2. Các biến trong hàm của bạn là null so với không xác định

Theo ý kiến ​​của tôi, các biến là công việc kinh doanh của riêng bạn và không phải là một phần của API của bạn, và các thuộc tính trong bất kỳ hệ thống OO nào đều được xác định và do đó nên được xác định với giá trị khác với giá trị của chúng nếu không được xác định (null đối với đã xác định, không xác định là những gì bạn nhận được khi truy cập một cái gì đó không có trong đối tượng của bạn).


1

Đây là lý do: var undefined = 1 là javascript hợp pháp, nhưng var null = 1là lỗi cú pháp. Sự khác biệt là nullmột từ khóa ngôn ngữ, trong khiundefined , vì một số lý do, không phải.

Nếu mã của bạn dựa vào các phép so sánh thì undefinednhư thể đó là một từ khóa ( if (foo == undefined)- một lỗi rất dễ mắc phải) chỉ hoạt động vì không ai xác định một biến với tên đó. Tất cả mã đó đều dễ bị ai đó xác định một cách vô tình hoặc ác ý một biến toàn cục với tên đó. Tất nhiên, chúng ta đều biết rằng việc vô tình xác định một biến toàn cục là điều hoàn toàn không thể trong javascript ...


1
Sử dụng void 0thay vì không xác định.
Frederik Krautwald

1

Chỉ muốn thêm rằng với việc sử dụng các thư viện javascript nhất định, null và undefined có thể gây ra những hậu quả không mong muốn.

Ví dụ: hàm lodash get, chấp nhận giá trị mặc định làm đối số thứ 3:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Một ví dụ khác: Nếu bạn sử dụng defaultProps trong React, nếu một thuộc tính được truyền null, các props mặc định sẽ không được sử dụng vì null được hiểu là một giá trị được xác định . ví dụ

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"

0

Tôi hoàn toàn không đồng ý rằng việc sử dụng null hoặc undefined là không cần thiết. không xác định là thứ giữ cho toàn bộ quá trình chuỗi nguyên mẫu tồn tại. Vì vậy, trình biên dịch chỉ với null không thể kiểm tra xem thuộc tính này chỉ bằng null hay nó không được xác định trong nguyên mẫu điểm cuối. Trong các ngôn ngữ được gõ động khác (fe Python), nó ném ra ngoại lệ nếu bạn muốn truy cập vào thuộc tính không được xác định, nhưng đối với các ngôn ngữ dựa trên nguyên mẫu, trình biên dịch cũng nên kiểm tra các nguyên mẫu gốc và đây là nơi mà không xác định cần nhất.

Toàn bộ ý nghĩa của việc sử dụng null chỉ là ràng buộc biến hoặc thuộc tính với đối tượng là singleton và có nghĩa là trống rỗng, và việc sử dụng null cũng có mục đích hiệu suất. 2 mã này có thời gian thực hiện khác nhau.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)

0

Biến không xác định: undefined.

Biến được biết đến nhưng không có giá trị: null.

  1. Bạn nhận được một đối tượng từ một máy chủ , server_object.
  2. Bạn tham khảo server_object.errj. Nó cho bạn biết nó undefined. Điều đó có nghĩa là nó không biết đó là gì.
  3. Bây giờ bạn tham khảo server_object.err. Nó cho bạn biết nó null. Điều đó có nghĩa là bạn đang tham chiếu đến một biến đúng nhưng nó trống; do đó không có lỗi.

Vấn đề là khi bạn khai báo một tên biến không có giá trị ( var hello) js khai báo rằng undefined: biến này không tồn tại; trong khi các lập trình viên chủ yếu có nghĩa là: “Tôi chưa cho nó một giá trị nào”, định nghĩa của null.

Vì vậy, hành vi mặc định của một lập trình viên - khai báo một biến không có giá trị là không có gì - mâu thuẫn với js - tuyên bố nó là không tồn tại. Và bên cạnh đó, !undefined!nullcả haitrue như vậy hầu hết các lập trình viên coi chúng như nhau.

Tất nhiên, bạn có thể đảm bảo rằng bạn luôn làm như vậy var hello = nullnhưng hầu hết sẽ không xả mã của họ như vậy để đảm bảo sự tỉnh táo của loại trong một ngôn ngữ được đánh máy lỏng lẻo, khi họ và !nhà điều hành coi cả hai undefinednullnhư nhau.

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.