簡體   English   中英

有什么理由在 JavaScript 中使用 null 而不是 undefined?

[英]What reason is there to use null instead of undefined in JavaScript?

我已經寫 JavaScript 很長時間了,我從來沒有理由使用null 似乎undefined總是更可取,並且以編程方式服務於相同的目的。 使用null而不是undefined的一些實際原因是什么?

我真的沒有答案,但根據Nicholas C 的說法。 Zakas ,他的書Web 開發人員的專業 JavaScript的第 30 頁:

當定義一個打算稍后保存 object 的變量時,建議將變量初始化為null而不是其他任何東西。 這樣,您可以稍后顯式檢查值null以確定變量是否已填充 object 引用

nullundefined本質上是兩個不同的值,它們的含義相同。 唯一的區別在於如何在系統中使用它們的約定 正如一些人所提到的,有些人使用null來表示“無對象”,有時您可能會得到 object 而未定義意味着沒有 object 是預期的(或存在錯誤)。 我的問題是它完全武斷,完全沒有必要。

也就是說,有一個主要區別 - 未初始化的變量(包括未傳遞參數的 function 參數等)始終未定義。

這就是為什么在我的代碼中我從不使用 null 除非我無法控制的東西返回 null (例如正則表達式匹配)。 這樣做的好處是它簡化了很多事情。 我永遠不必檢查x === undefined || x === null x === undefined || x === null ,我可以檢查x === undefined 如果你習慣使用==或者只是if(x)...之類的東西,請停止它。

!x對於空字符串0nullNaN將評估為 true - 即您可能不想要的東西。 如果您想編寫不糟糕的 javascript,請始終使用三等號===並且永遠不要使用null (改用undefined )。 它會讓你的生活更輕松。

歸根結底,因為nullundefined都強制轉換為相同的值( Boolean(undefined) === false && Boolean(null) === false ),所以從技術上講,您可以使用其中任何一個來完成工作。 但是,有正確的方法,IMO。

  1. undefined的用法留給 JavaScript 編譯器。

    undefined用於描述不指向引用的變量。 這是 JS 編譯器會為您處理的事情。 在編譯時,JS 引擎會將所有提升變量的值設置為undefined 當引擎逐步執行代碼並且值變得可用時,引擎將為相應的變量分配相應的值。 對於那些沒有找到值的變量,這些變量將繼續保持對原語undefined的引用。

  2. 如果您明確想要將變量的值表示為“無值”,則僅使用 null。

    正如@com2gz 所說: null用於以編程方式定義一些空的東西。 undefined表示引用不存在。 null值定義了對“無”的引用。 如果您正在調用 object 的不存在屬性,那么您將得到undefined 如果我故意使該屬性為空,那么它必須是null所以你知道它是故意的。

TLDR; 不要使用undefined的原語。 當您聲明沒有賦值的變量或嘗試訪問沒有引用的對象的屬性時,JS 編譯器會自動為您設置一個值。 另一方面,當且僅當您有意希望變量具有“無值”時,才使用null

我從來沒有明確地將任何東西設置為未定義(我在與之交互的許多代碼庫中都沒有遇到過這個)。 另外,我很少使用null 我使用null的唯一時間是當我想將 function 的參數值表示為沒有值時,即:

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

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

undefined 是不存在事物概念的地方; 它沒有類型,並且之前從未在 scope 中被引用過; null 是已知事物存在的地方,但沒有任何價值。

每個人都有自己的編碼方式和自己的內部語義,但多年來我發現這是我給問這個問題的人最直觀的建議:當有疑問時,做 JavaScript 所做的事情

假設您正在使用 object 屬性,例如 jQuery 插件的選項...問問自己 JavaScript 給出的屬性尚未定義的值是什么——答案undefined 因此,在這種情況下,我將使用 'undefined' 初始化這些類型的事物,以與 JavaScript 一致(對於變量,您可以使用var myVar;而不是var myVar = undefined; )。

現在假設您正在進行 DOM 操作...... JavaScript 分配給不存在的元素什么值? 答案是null 如果您正在創建一個占位符變量,該變量稍后將保存對與 DOM 相關的元素、文檔片段或類似內容的引用,我將使用此值進行初始化。

如果您使用 JSON,則需要進行特殊情況:對於未定義的屬性值,您應該將它們設置為""null ,因為undefined的值不被認為是正確的 Z0ECD11C1D7A2877401DZ48A23 格式。

話雖如此,正如之前的海報所表達的那樣,如果你發現你正在用nullundefined在藍月亮中多次初始化,那么也許你應該重新考慮你如何 go 來編碼你的應用程序。

您可能會采用此處建議的約定,但確實沒有充分的理由這樣做。 它的使用不夠一致,沒有足夠的意義。

為了使約定有用,您首先必須知道被調用的 function 遵循約定。 然后你必須明確地測試返回的值並決定做什么。 如果你得到undefined ,你可以假設發生了某種被稱為 function 知道的錯誤。 但是,如果發生錯誤,並且 function 知道它,並且將其發送到更廣泛的環境中很有用,為什么不使用錯誤 object 呢? 即拋出錯誤?

因此,歸根結底,除了簡單環境中的非常小的程序之外,該約定實際上毫無用處。

一些人說可以將對象初始化為null 我只是想指出解構參數默認值不適用於null 例如:

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

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

這需要在調用 function之前執行null檢查,這可能經常發生。

null中一個有用的屬性undefined不符合條件:

> null + 3
3
> undefined + 3
NaN

當我想“關閉”一個數值或初始化一些數值時,我使用null 我最后一次使用的是操作 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); });

不知道我是否應該使用這個屬性的想法......

DOM 節點和元素不是未定義的,但可能是 null。

  • 元素的最后一個子元素的 nextSibling 是 null。

  • 第一個孩子的前一個兄弟姐妹是 null。

  • 如果文檔中不存在該元素,則 document.getElementById 引用為 null。

但在這些情況下,值都不是undefined 那里沒有節點。

在 JavaScript 中,值null表示有意缺少任何 object 值。 null表示缺少標識,表示一個變量指向沒有object。

全局undefined屬性表示原始值undefined undefined是自動分配給變量的原始值。 undefined表示引用不存在。

我完全不同意使用 null 或 undefined 是不必要的。 undefined 是使整個原型鏈接過程保持活力的東西。 因此,僅使用 null 的編譯器無法檢查此屬性是否等於 null,或者它未在端點原型中定義。 在其他動態類型語言(fe Python)中,如果你想訪問未定義的屬性,它會拋出異常,但對於基於原型的語言,編譯器還應該檢查父原型,這是最需要未定義的地方。

Whole meaning of using null is just bind variable or property with object which is singleton and have meaning of emptiness,and also null usage have performance purposes. 這兩個代碼有不同的執行時間。

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)

我現在正在解決這個確切的問題,並研究以下理念:

  1. 任何旨在返回結果的 function 如果找不到結果,則應返回 null
  2. 任何不打算返回結果的 function 都會隱式返回 undefined。

對我來說,這個問題很重要,因為任何調用返回結果的 function 的人都應該毫無疑問是否測試未定義與 null。

此答案不嘗試解決:

  1. null 與未定義的屬性值
  2. 函數中的變量是 null 與未定義

在我看來,變量是您自己的事情,而不是您的 API 的一部分,並且任何 OO 系統中的屬性都已定義,因此應使用與未定義時不同的值定義(null 表示已定義,未定義是您的get 訪問不在您的對象中的東西)。

這是一個原因: var undefined = 1是合法的 javascript,但var null = 1是語法錯誤。 不同之處在於null是語言關鍵字,而undefined由於某種原因不是。

如果您的代碼依賴於與undefined的比較,就好像它是一個關鍵字( if (foo == undefined) - 一個非常容易犯的錯誤),它只會起作用,因為沒有人使用該名稱定義變量。 所有這些代碼都容易受到意外或惡意使用該名稱定義全局變量的人的攻擊。 當然,我們都知道在javascript中意外定義一個全局變量是完全不可能的……

只是想補充一點,使用某些 javascript 庫,null 和 undefined 可能會產生意想不到的后果。

例如,lodash 的get function,它接受一個默認值作為第三個參數:

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'

另一個例子:如果你在 React 中使用 defaultProps,如果傳遞了一個屬性null ,則不會使用默認道具,因為null 被解釋為定義的值 例如

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"

未知變量: undefined

已知變量但沒有值: null

  1. 您從服務器server_object收到 object 。
  2. 您引用server_object.errj 它告訴你它是undefined 這意味着它不知道那是什么。
  3. 現在您引用server_object.err 它告訴你它是null 這意味着您引用了一個正確的變量,但它是空的; 因此沒有錯誤。

問題是當你聲明一個沒有值的變量名( var hello )時,js 將其聲明為undefined :這個變量不存在; 而程序員的主要意思是:“我還沒有給它一個值”, null的定義。

因此,程序員的默認行為——將沒有值的變量聲明為空——與 js 不一致——將其聲明為不存在。 此外, !undefined!null都是true ,所以大多數程序員將它們視為等價的。

你當然可以確保你總是做var hello = null但大多數人不會亂扔他們的代碼以確保在故意松散類型的語言中類型健全,當他們和! 運算符將undefinednull視為等效。

這里已經有一些很好的答案,但不是我想要的。 nullundefined兩者“在技術上”都在虛假方面做同樣的事情,但是當我閱讀代碼並看到一個“null”時,我期待它是用戶定義的 null,某些東西被明確設置為包含 no值,如果我通讀代碼並看到“未定義”,那么我假設它是從未被任何東西初始化或分配的代碼。 通過這種方式,代碼可以與您溝通是否是由未初始化的東西或 null 值引起的。 因此,您真的不應該手動將“未定義”分配給某些東西,否則它會干擾您(或其他開發人員)閱讀代碼的方式。 如果另一個開發人員看到“未定義”,他們不會直觀地認為是您將其設置為未定義,他們會認為它沒有被初始化,而實際上它是。 對我來說,這是最大的問題,當我閱讀代碼時,我想看看它告訴我什么,我不想猜測和弄清楚東西是否“實際上”被初始化了。

更不用說在 typescript 中使用它們意味着兩件不同的事情。 使用:

interface Example {
    name?: string
}

表示名稱可以是未定義的或字符串,但不能是 null。 如果你想要它 null 你必須明確使用:

interface Example {
  name: string | null
}

即使這樣,您也將被迫至少使用“null”對其進行初始化。

當然,只有在tsconfig.json中使用"strictNullChecks": true

根據我們最近遇到的一個問題,下面的示例說明了為什么我更喜歡使用undefined而不是null ,除非有特定的理由不這樣做:

function myfunc (myArg) {
    if (typeof myArg === 'string') {
        console.log('a', myArg);
    } else if (typeof abc === 'object') {
        console.log('b', myArg);
        if (myArg.id) {
           console.log('myArg has an id');
        } else {
           console.log('myArg has an id');
        }
    } else {
        console.log('no value');
    }
}

以下值將很好地發揮作用:

'abc'
{}
undefined
{ id: 'xyz' }

另一方面,假設nullundefined在這里是等價的會破壞代碼。 原因是null屬於object類型,其中undefined屬於undefined類型。 因此,這里的代碼中斷了,因為您無法在null上測試成員。

我見過大量代碼外觀相似的案例,其中null只是在問問題:

if (typeof myvar === 'string') {
  console.log(myvar);
} else if (typeof myvar === 'object') {
  console.log(myvar.id);  
}

此處的解決方法是顯式測試 null:

if (typeof myvar === 'string') {
  console.log(myvar);
} else if (myvar !== null && typeof myvar === 'object') {
  console.log(myvar.id);  
}

我的態度是針對一種語言的弱點和該語言程序員的典型行為進行編碼,因此這里的哲學是默認使用“未定義”。

要編寫簡單的代碼,您需要降低復雜性和變化。 當 object 上的變量或屬性沒有值時,它是未定義的,並且要為 null 分配一個 null 值。

未聲明與 Null

null既是Object “類型”,又是稱為null的 7 個唯一原始值類型之一

undefined既是稱為undefined (window.undefined) 的全局 scope 屬性,也是稱為undefined的 7 個唯一原始值類型之一

它是我們用作我們感興趣的值的原始類型

null的情況下,作為值類型,這意味着已將空值分配給變量。 這可能意味着一個變量有一個空值,但它仍然是一個值。 它還初始化變量,使其存在,而不是undefined

undefined是一個特例。 當您創建一個變量時,默認情況下它在賦值之前被賦值為undefined ,這意味着該變量不存在或存在但沒有賦值。 null一樣,它也是原始值類型 但與null不同,這意味着該變量不存在。 這就是為什么在檢查值是null還是空之前,最好先檢查變量是否存在並使用 undefined 分配了一個變量。 undefined表示編譯中沒有變量或 object 存在。 該變量要么沒有被聲明,要么被聲明為缺少值,因此沒有被初始化 所以undefined是避免許多類型錯誤並取代null的好方法。

這就是為什么我不會依賴nullundefined的“真實”檢查真/假,即使它們會返回錯誤響應,因為undefined意味着缺少功能、object 或變量,而不僅僅是真/假檢查。 它暗示了更多的東西。

我們先來看undefined的:

        //var check1;// variable doesnt even exist so not assigned to "undefined"
        var check2;// variable declared but not initialized so assigned "undefined"
        var check3 = 'hello world';// variable has a value so not undefined

        console.log('What is undefined?');

        //console.log(check1 === undefined);// ERROR! check1 does not exist yet so not assigned undefined!
        console.log(check2 === undefined);// True
        console.log(check3 === undefined);// False
        console.log(typeof check1 === 'undefined');// True
        console.log(typeof check2 === 'undefined');// True
        console.log(typeof check3 === 'undefined');// False

如您所見,未聲明的變量或已聲明但未初始化的變量都被分配了一種undefined的類型。 請注意,未初始化的聲明變量被分配一個undefined的值,原始值類型但不存在的變量是未定義類型

null與缺少變量或尚未賦值的變量無關,因為null仍然是一個值。 所以任何帶有null的東西都已經被聲明初始化了。 另請注意,與未定義類型不同,分配了null值的變量實際上是object類型。 例如...

        var check4 = null;
        var check5 = 'hello world';

        console.log('What is null?');

        console.log(check4 === undefined);// False
        console.log(check5 === undefined);// False
        console.log(typeof check4 === 'undefined');// False
        console.log(typeof check5 === 'undefined');// False
        console.log(typeof check4);// return 'object'
        console.log(typeof check5);// return 'string'

正如您所看到的,每種行為都不同,但兩者都是原始值,您可以分配任何變量。 只需了解它們代表變量和對象的不同狀態即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM