日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
5年前,學(xué)習(xí)Null和Undefined,現(xiàn)在有了新的認(rèn)知,看看這位人才怎么說?

許多編程語言都有一個稱為null的非值。它指示一個變量當(dāng)前不指向一個對象,例如,當(dāng)它還沒有初始化的時候。

德城ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!

相比之下,JavaScript有兩個這樣的非值:undefined和null。在這篇博文中,我們將研究它們有什么不同,以及如何最好地使用或避免它們。

1. undefined vs. null

這兩種值非常相似,經(jīng)常互換使用。因此,它們的區(qū)別是微妙的。

1.1 ECMAScript語言規(guī)范:undefined vs. null

ECMAScript語言規(guī)范對其描述如下。

  • undefined是 "當(dāng)一個變量沒有被賦值時使用"
  • null "表示有意不存在任何對象值"

1.2 兩個非值--一個無法消除的錯誤

在JavaScript中擁有兩個非值現(xiàn)在被認(rèn)為是一個設(shè)計錯誤(甚至被JavaScript的創(chuàng)造者Brendan Eich認(rèn)為)。

那為什么不從 JavaScript 中刪除其中的一個值呢?JavaScript 的一個核心原則是絕不破壞向后兼容。這個原則有很多好處。它最大的缺點是,設(shè)計上的錯誤無法被刪除。

1.3 undefined和null的歷史

在Java中(它啟發(fā)了JavaScript的許多方面),初始化值取決于變量的靜態(tài)類型。

  • 具有對象類型的變量被初始化為null。
  • 每個原始類型都有自己的初始化值。例如,int變量被初始化為0。

在JavaScript中,每個變量都可以容納對象值和基本類型值。因此,如果null意味著 "不是一個對象",那么JavaScript也需要一個初始化值,意味著 "既不是一個對象也不是一個原始值"。這個初始化值就是 undefined。

undefined 的出現(xiàn)

如果一個變量myVar還沒有被初始化,它的值是undefined。

 
 
 
 
  1. let myVar; 
  2. assert.equal(myVar, undefined); 

如果一個屬性.unknownProp丟失,訪問該屬性會產(chǎn)生undefined的值。

 
 
 
 
  1. const obj = {}; 
  2. assert.equal(obj.unknownProp, undefined); 

如果一個函數(shù)有一個沒有參數(shù)的返回語句,該函數(shù)隱含地返回undefined。

 
 
 
 
  1. function myFunc() { 
  2.   return; 
  3. assert.equal(myFunc(), undefined); 

如果一個參數(shù)x被省略了,語言將該參數(shù)初始化為undefined。

 
 
 
 
  1. function myFunc() { 
  2.   return; 
  3. assert.equal(myFunc(), undefined); 
  4. myFunc(); 

通過obj?.someProp的可選鏈路,如果obj未定義或為空,則返回未定義。

 
 
 
 
  1. > undefined?.someProp 
  2. undefined 
  3. > null?.someProp 
  4. undefined 

3.null 出現(xiàn)情況

一個對象的原型要么是一個對象,要么在原型鏈的末端是null。Object.prototype沒有原型。

 
 
 
 
  1. > Object.getPrototypeOf(Object.prototype) 
  2. null 

如果我們將一個正則表達式(如/a/)與一個字符串(如'x')相匹配,我們要么得到一個帶有匹配數(shù)據(jù)的對象(如果匹配成功),要么得到空(如果匹配失敗)。

 
 
 
 
  1. > /a/.exec('x') 
  2. null 

JSON數(shù)據(jù)格式不支持undefined,只支持null。

 
 
 
 
  1. > JSON.stringify({a: undefined, b: null}) 
  2. '{"b":null}' 

4.特別處理 undefined 或 null 的運算符

4.1 undefined 和參數(shù)默認(rèn)值

在以下情況下,將使用參數(shù)默認(rèn)值。

  • 缺少一個參數(shù)。
  • 一個參數(shù)的值是undefined。

例如:

 
 
 
 
  1. function myFunc(arg='abc') { 
  2.   return arg; 
  3. assert.equal(myFunc('hello'), 'hello'); 
  4. assert.equal(myFunc(), 'abc'); 
  5. assert.equal(myFunc(undefined), 'abc'); 

undefined也觸發(fā)了參數(shù)的默認(rèn)值,這說明它是一個元值。

下面的例子說明了這一點的用處。

 
 
 
 
  1. function concat(str1='', str2='') { 
  2.   return str1 + str2; 
  3. function twice(str) { // (A) 
  4.   return concat(str, str); 

在A行,我們沒有為str指定一個參數(shù)默認(rèn)值。當(dāng)這個參數(shù)缺失時,我們把這個狀態(tài)轉(zhuǎn)發(fā)給concat(),讓它選擇一個默認(rèn)值。

4.2 undefined 的和解構(gòu)的默認(rèn)值

解構(gòu)中的缺省值與參數(shù)缺省值的工作原理類似--如果一個變量在數(shù)據(jù)中沒有匹配,或者它與undefined的變量匹配,就會使用它們。

 
 
 
 
  1. const [a='a'] = []; 
  2. assert.equal(a, 'a'); 
  3.  
  4. const [b='b'] = [undefined]; 
  5. assert.equal(b, 'b'); 
  6.  
  7. const {prop: c='c'} = {}; 
  8. assert.equal(c, 'c'); 
  9.  
  10. const {prop: d='d'} = {prop: undefined}; 
  11. assert.equal(d, 'd'); 

4.3 undefined 和 null 以及可選鏈

當(dāng)通過 value?.prop 進行可選的鏈接時

  • 如果value是undefined或null,則返回 undefined。也就是說,只要value.prop會拋出一個異常,就會發(fā)生這種情況。
  • 否則,返回value.prop。
 
 
 
 
  1. function getProp(value) { 
  2.   // optional static property access 
  3.   return value?.prop; 
  4. assert.equal( 
  5.   getProp({prop: 123}), 123); 
  6. assert.equal( 
  7.   getProp(undefined), undefined); 
  8. assert.equal( 
  9.   getProp(null), undefined); 

下面兩個操作的效果類似。

 
 
 
 
  1. obj?.[?expr?] // optional dynamic property access 
  2. func?.(?arg0?, ?arg1?) // optional function or method call 

4.4 undefined 和 null 和 nullish 聚結(jié)

nullish 合并算子??如果一個值undefined或為null,則允許我們使用默認(rèn)值:

 
 
 
 
  1. > undefined ?? 'default value' 
  2. 'default value' 
  3. > null ?? 'default value' 
  4. 'default value' 
  5.  
  6. > 0 ?? 'default value' 
  7. > 123 ?? 'default value' 
  8. 123 
  9. > '' ?? 'default value' 
  10. '' 
  11. > 'abc' ?? 'default value' 
  12. 'abc' 

null合并賦值操作符??=:

 
 
 
 
  1. function setName(obj) { 
  2.   obj.name ??= '(Unnamed)'; 
  3.   return obj; 
  4. assert.deepEqual( 
  5.   setName({}), 
  6.   {name: '(Unnamed)'} 
  7. ); 
  8. assert.deepEqual( 
  9.   setName({name: undefined}), 
  10.   {name: '(Unnamed)'} 
  11. ); 
  12. assert.deepEqual( 
  13.   setName({name: null}), 
  14.   {name: '(Unnamed)'} 
  15. ); 
  16. assert.deepEqual( 
  17.   setName({name: 'Jane'}), 
  18.   {name: 'Jane'} 
  19. ); 

5. 處理 undefined 和 null

下面分享一下我們自己的代碼中處理undefined 和null的最常見方法。

5.1 undefined 或 null 都不能作為實際值使用

舉例,我們可能希望一個屬性file.title永遠(yuǎn)存在,并且永遠(yuǎn)是一個字符串。有兩種常見的方法來實現(xiàn)這一點。

這里,只檢查undefined和null,而不檢查一個值是否是字符串。你必須自己決定是否要把它作為一個額外的安全措施來實施。

5.1 undefined 和 null 都是禁止的

如下所示

 
 
 
 
  1. function createFile(title) { 
  2.   if (title === undefined || title === null) { 
  3.     throw new Error('`title` must not be nullish'); 
  4.   } 
  5.   // ··· 

為什么選擇這種方法?

我們想把undefined和null當(dāng)作一樣的東西,因為JavaScript代碼經(jīng)常這樣做--比如說。

 
 
 
 
  1. // 檢測一個屬性是否存在 
  2. if (!obj.requiredProp) { 
  3.   obj.requiredProp = 123; 
  4.  
  5. const myValue = myParameter ?? 'some default'; 

如果我們的代碼中出現(xiàn)了問題,出現(xiàn)了undefined或null,我們希望它盡可能快地失敗。

5.1.2 undefined 和 null 都會觸發(fā)默認(rèn)值

如下所示

 
 
 
 
  1. function createFile(title) { 
  2.   title ??= '(Untitled)'; 
  3.   // ··· 

我們不能在這里使用參數(shù)缺省值,因為它只由undefined 觸發(fā)。相反,我們依靠nullish 合并賦值運算符??=。

為什么選擇這種方法?

  • 我們想把undefined和null同等對待(見上一節(jié))。
  • 我們希望我們的代碼能夠穩(wěn)健地、無聲地處理 undefined 和null。

5.2 undefined 或 null 都是“關(guān)閉”值

例如,我們可能希望一個屬性file.title是一個字符串或 "關(guān)閉"(文件沒有標(biāo)題)。有幾種方法可以實現(xiàn)這一點。

5.2.1 null是 "關(guān)閉的 "值

 
 
 
 
  1. function createFile(title) { 
  2.   if (title === undefined) { 
  3.     throw new Error('`title` must not be undefined'); 
  4.   } 
  5.   return {title}; 

另外,undefined可以觸發(fā)一個默認(rèn)值。

 
 
 
 
  1. function createFile(title = '(Untitled)') { 
  2.   return {title}; 

為什么選擇這種方法?

  • 我們需要一個表示“關(guān)閉”的非值。
  • 我們不希望我們的非值觸發(fā)參數(shù)默認(rèn)值和解構(gòu)默認(rèn)值。
  • 我們想把非值字符串化為JSON(這是我們不能用undefined做的)。

5.2.2 undefined 是"關(guān)閉的 "值。

 
 
 
 
  1. function createFile(title) { 
  2.   if (title === null) { 
  3.     throw new Error('`title` must not be null'); 
  4.   } 
  5.   return {title}; 

為什么選擇這種方法?

  • 我們需要一個表示“關(guān)閉”的非值。
  • 我們確實想讓我們的非值觸發(fā)參數(shù)默認(rèn)值和解構(gòu)默認(rèn)值。

5.2.3 為什么不同時使用undefined和null作為 "關(guān)閉 "的值?

當(dāng)接收一個值時,把undefined和null都當(dāng)作 "不是一個值 "是有意義的。然而,當(dāng)我們創(chuàng)建值時,我們希望不含糊,以便處理這些值時保持簡單。

這指向了一種不同的方法。如果我們需要一個 "關(guān)閉"的值,但又不想使用undefined或null作為這樣的值,怎么辦?請往下看。

5.3 處理“關(guān)閉”的其他方式

5.3.1 特殊值

我們可以創(chuàng)建一個特殊的值,每當(dāng)屬性.title被關(guān)閉時,我們就使用這個值。

 
 
 
 
  1. const UNTITLED = Symbol('UNTITLED'); 
  2. const file = { 
  3.   title: UNTITLED, 
  4. }; 

5.3.2 空對象模式

空對象模式來自于面向?qū)ο蟮木幊獭?/p>

  • 一個共同的超類的所有子類都有相同的接口。
  • 每個子類都實現(xiàn)了一個實例運行的不同模式。
  • 其中一個模式是 "null"。

在下面的例子中,UntitledFile實現(xiàn)了 "null" 模式。

 
 
 
 
  1. // 抽象的超類 
  2. class File { 
  3.   constructor(content) { 
  4.     if (new.target === File) { 
  5.       throw new Error('Can’t instantiate this class'); 
  6.     } 
  7.     this.content = content; 
  8.   } 
  9.  
  10. class TitledFile extends File { 
  11.   constructor(content, title) { 
  12.     super(content); 
  13.     this.title = title; 
  14.   } 
  15.   getTitle() { 
  16.     return this.title; 
  17.   } 
  18.  
  19. class UntitledFile extends File { 
  20.   constructor(content) { 
  21.     super(content); 
  22.   } 
  23.   getTitle() { 
  24.     return '(Untitled)'; 
  25.   } 
  26.  
  27. const files = [ 
  28.   new TitledFile('Dear diary!', 'My Diary'), 
  29.   new UntitledFile('Reminder: pick a title!'), 
  30. ]; 
  31.  
  32. assert.deepEqual( 
  33.   files.map(f => f.getTitle()), 
  34.   [ 
  35.     'My Diary', 
  36.     '(Untitled)', 
  37.   ]); 

我們也可以只對標(biāo)題使用空對象模式(而不是對整個文件對象)。

5.3.3 Maybe 類型

Maybe 類型是一種函數(shù)編程技術(shù)。

 
 
 
 
  1. function getTitle(file) { 
  2.   switch (file.title.kind) { 
  3.     case 'just': 
  4.       return file.title.value; 
  5.     case 'nothing': 
  6.       return '(Untitled)'; 
  7.     default: 
  8.       throw new Error(); 
  9.   } 
  10.  
  11. const files = [ 
  12.   { 
  13.     title: {kind: 'just', value: 'My Diary'}, 
  14.     content: 'Dear diary!', 
  15.   }, 
  16.   { 
  17.     title: {kind: 'nothing'}, 
  18.     content: 'Reminder: pick a title!', 
  19.   }, 
  20. ]; 
  21.  
  22. assert.deepEqual( 
  23.   files.map(f => getTitle(f)), 
  24.   [ 
  25.     'My Diary', 
  26.     '(Untitled)', 
  27.   ]); 

我們可以通過Arrays對 "just "和 "nothing "進行編碼。我們的方法的好處是,它得到了TypeScript的良好支持(通過判別性聯(lián)合)。

6.我的方法

我不喜歡用undefined作為 "關(guān)閉 "的值,有三個原因。

  • undefined經(jīng)常意外地出現(xiàn)在JavaScript中。
  • ndefined會觸發(fā)參數(shù)和結(jié)構(gòu)化的默認(rèn)值(出于同樣的原因,有些人喜歡undefined)。

因此,如果我需要一個特殊的值,我會使用以下兩種方法中的一種。

  • 我使用null作為一個 "關(guān)閉 "的值。(作為一個旁觀者,這種方法在TypeScript中得到了比較好的支持)。)
  • 我通過上述的技術(shù)之一來避免undefined和null。這樣做的好處是比較干凈,壞處是涉及更多的工作。

作者:Michael Thiessen

譯者:前端小智

來源:dev原文:https://2ality.com/2021/01/undefined-null-revisited.html


分享文章:5年前,學(xué)習(xí)Null和Undefined,現(xiàn)在有了新的認(rèn)知,看看這位人才怎么說?
文章路徑:http://m.5511xx.com/article/coigesi.html