1. 程式人生 > 程式設計 >處理JavaScript值為undefined的7個小技巧

處理JavaScript值為undefined的7個小技巧

前言

我剛剛開始學習JavaScript時,大約是八年前,當時我對於undefined 和 null 比較困惑 ,因為他們都表示空值。

處理JavaScript值為undefined的7個小技巧

他們有什麼明確的區別嗎?他們似乎都可以定義一個空值,而且 當你進行 在做null ===undefined 的比較時,結果是true。

現在的大多數語言,像Ruby,Python or Java,他們有一個單獨的空值(nil 或 null),這似乎才是一個合理的方式。

而在JavaScript裡,當你要獲取一個變數或物件(未初始化)的值時,js引擎會返回 undefined。

let company; 
company; // => undefined 
let person = { name: 'John Smith' }; 
person.age; // => undefined 

另一方面,物件引用錯誤會返回null。JavaScript本身並不會給將變數或者物件屬性的值設為 null。

一些js原生的方法會返回null,比如string.prototypt.match() 引數不是物件時,會返回null,來表示物件缺失。

let array = null; 
array;  // => null 
let movie = { name: 'Starship Troopers',musicBy: null }; 
movie.musicBy; // => null 
'abc'.match(/[0-9]/); // => null 

由於JavaScript的寬容特性,開發人員有訪問未初始化值的誘惑。我也犯了這種不好的做法。

通常這種冒險行為會產生“未定義”的相關錯誤,從而快速結束指令碼。相關的常見錯誤訊息是:

  • TypeError:'undefined'不是函式
  • TypeError:無法讀取未定義的屬性' ''
  • 和類似type errors。

JavaScript開發能夠理解這個笑話:

function undefined() { 
 // problem solved 
} 

為了減少這種錯誤的風險,您必須瞭解產生“undefined”時的情況。

更重要的是抑制其外觀並在應用程式中傳播,從而提高程式碼的耐用性。

我們來詳細探討undefined及其對程式碼安全的影響。

1、 什麼是undefined

JavaScript 的 6 基本型別:

  • Boolean: true or false
  • Number: 1,6.7,0xFF
  • String: "Gorilla and banana"
  • Symbol: Symbol("name") (starting ES2015)
  • Null: null
  • Undefined: undefined.

And a separated object type: {name: "Dmitri"},["apple","orange"].

從6個基本型別undefined是一個特殊的值,它的型別為Undefined。根據[ECMAScript規範](https://www.ecma-international.org/ecma-262/7.0/#sec-undefined-value):

未定義的值原始值在變數未被賦值時使用。

該標準明確規定,在訪問未初始化的變數,不存在的物件屬性,不存在的陣列元素等時,您將收到未定義的值。

例如:Try in repl.it

let number; 
number; // => undefined 
 
let movie = { name: 'Interstellar' }; 
movie.year; // => undefined 
 
let movies = ['Interstellar','Alexander']; 
movies[3]; // => undefined 

ECMAScript規範定義了“未定義”值的型別:

未定義型別是唯一值為“未定義”值的型別。

typeof undefined === 'undefined'; // => true 
let nothing; 
typeof nothing === 'undefined'; // => true 

2、 建立未定義的常見場景

2.1 未初始化的變數

一個尚未賦值的宣告變數( uninitialized )預設為undefined。

Plain and simple:

let myvariable; 
myvariable; // => undefined

解決未初始化變數問題的一種有效方法是儘可能分配一個初始值_。

變數在未初始化狀態下存在的越少越好。理想情況下,您可以在宣告值const myvariable ='初始值'後立即分配一個值,但這並非總是可行。

Tip 1: 贊成const,否則使用let,但是告別var

在我看來,ECMAScript 2015的優秀功能之一是使用const和let宣告變數的新方法。這是一個很大的進步,這些宣告是塊範圍的(與舊函式作用域var相反)並存在於[暫時死區](https://rainsoft.io/variables-lifecycle-and-why-let- 沒有被吊起/#5letvariableslifecycle)直到宣告行。

當變數只接收一個值時,我建議使用const宣告。

它建立一個[不可變繫結](https://mathiasbynens.be/notes/es6-const)。

const的一個很好的特性是 - 你必須給初始值賦予變數const myvariable ='initial'。變數不會暴露於未初始化的狀態,並且訪問undefined根本不可能。

讓我們檢查一下驗證單詞是否是迴文的函式:

function isPalindrome(word) { 
 const length = word.length; 
 const half = Math.floor(length / 2); 
 for (let index = 0; index `< half; index++) { 
 if (word[index] !== word[length - index - 1]) { 
 return false; 
 } 
 } 
 return true; 
} 
isPalindrome('madam'); // =>` true 
isPalindrome('hello'); // => false 
處理JavaScript值為undefined的7個小技巧

var宣告的問題是整個函式範圍內的[變數提升](https://rainsoft.io/javascript-hoisting-in-details/#hoistingandvar)。

你可以在函式範圍的末尾宣告一個var變數,但是它仍然可以在宣告之前被訪問:並且你會得到一個undefined。

function bigFunction() { 
 // code... 
 myvariable; // => undefined 
 // code... 
 var myVariable = 'Initial value'; 
 // code... 
 myVariable; // => 'Initial value' 
} 
bigFunction(); 

相反,在宣告行之前不能訪問let(包括const)變數。發生這種情況是因為該變數在宣告之前處於[暫時死區](https://rainsoft.io/variables-lifecycle-and-why-let-is-not-hoisted/#5letvariableslifecycle)中。

這很好,因為你訪問undefined的機會較少。

上面的例子用let改寫後,會出錯。

function bigFunction() { 
 // code... 
 myVariable; // => Throws 'ReferenceError: myVariable is not defined' 
 // code... 
 let myVariable = 'Initial value'; 
 // code... 
 myVariable; // => 'Initial value' 
} 
bigFunction(); 

Tip 2: 增強內聚性

[Cohesion](https://en.wikipedia.org/wiki/Cohesion_(computer_science))描述了模組(名稱空間,類,方法,程式碼塊)的元素所屬的程度。 內聚的測量通常被描述為高內聚或低內聚_。

高內聚是最好的,因為它建議設計模組的元素只專注於單個任務。它使模組:

  • Focused and understandable: easier to understand what the module does
  • 功能單一且容易理解
  • Maintainable and easier to refactor: the change in the module affects fewer modules
  • 易於維護和複用
  • Reusable: being focusing on a single task,it makes the module easier to reuse
  • 重複利用
  • Testable: you would easier test a module that's focused on a single task
  • 易於測試
處理JavaScript值為undefined的7個小技巧

高內聚力伴隨[鬆耦合](https://en.wikipedia.org/wiki/Loose_coupling)是設計良好的系統的特點。

一個程式碼塊本身可能被認為是一個小模組。為了從高內聚的好處中受益,您需要儘可能使變數儘可能靠近使用它們的程式碼塊。

例如,如果一個變數完全存在於形成塊範圍的邏輯,則宣告並允許該變數僅存在於該塊內(使用const或let宣告)。不要將這個變數暴露給外部塊作用域,因為外部塊不應該關心這個變數。

不必要的擴充套件變數生命週期的一個典型例子是在函式內使用for迴圈:

function someFunc(array) { 
 var index,item,length = array.length; 
 // some code... 
 // some code... 
 for (index = 0; index < length; index++) { 
 item = array[index]; 
 // some code... 
 } 
 return 'some result'; 
} 

index,item和length變數在函式體的開頭宣告。然而,它們只用於接近尾聲。那麼這種方法有什麼問題?

在頂部的宣告和for語句中的用法之間,變數index,item都是未初始化的並且暴露給undefined。它們在整個功能範圍內的生命週期不合理。

更好的方法是將這些變數儘可能靠近他們的使用地點:

function someFunc(array) { 
 // some code... 
 // some code... 
 const length = array.length; 
 for (let index = 0; index `< length; index++) { 
 const item = array[index]; 
 // some 
 } 
 return 'some result'; 
} 

為什麼修改後的版本比最初版本更好?讓我們來看看:

  • 變數不會暴露於未初始化的狀態,因此您沒有訪問未定義的風險
  • 儘可能將變數移動到它們的使用地點增加了程式碼的可讀性
  • 高度連貫的程式碼塊在需要時更容易重構並提取為分離的函式

2.2 訪問不存在的屬性

When accessing a **non-existing object property**,JavaScript returnsundefined`. 當訪問不再的屬性時,會返回undefined 

看例子:

let favoriteMovie = { 
 title: 'Blade Runner' 
}; 
favoriteMovie.actors; // => undefined 

本身訪問不存在的屬性不會引發錯誤。嘗試從不存在的屬性值獲取資料時出現真正的問題。這是最常見的undefined相關陷阱,反映在眾所周知的錯誤訊息'TypeError:Can not read property of undefined`中。

讓我們稍微修改前面的程式碼片段來說明一個“TypeError”丟擲:

let favoriteMovie = { 
 title: 'Blade Runner' 
}; 
favoriteMovie.actors[0]; 
// TypeError: Cannot read property '0' of undefined 

允許訪問不存在的屬性的JavaScript的寬容性質是混淆的來源:該屬性可能被設定,或者可能不是。繞過這個問題的理想方法是限制物件始終定義它所擁有的屬性。

不幸的是,您經常無法控制您使用的物件。這些物件在不同情況下可能具有不同的屬性集。所以你必須手動處理所有這些場景。

讓我們實現一個函式append(array,toAppend),它在陣列的開始和/或結尾新增新的元素。toAppend引數接受一個具有屬性的物件:

  • first: element inserted at the beginning of array
  • last: element inserted at the end of array.
function append(array,toAppend) { 
 const arrayCopy = array.slice(); 
 if (toAppend.first) { 
 arrayCopy.unshift(toAppend.first); 
 } 
 if (toAppend.last) { 
 arrayCopy.push(toAppend.last); 
 } 
 return arrayCopy; 
} 
append([2,3,4],{ first: 1,last: 5 }); // => [1,2,4,5] 
append(['Hello'],{ last: 'World' }); // => ['Hello','World'] 
append([8,16],{ first: 4 });  // => [4,8,16] 
append([10],{ first: 0,last: false }); // => [10] 

下面的提示解釋瞭如何正確檢查屬性是否存在。

Tip 3: 檢查屬性是否存在

幸運的是,JavaScript提供了很多方法來確定物件是否具有特定屬性:

*obj.prop!== undefined:直接與undefined進行比較

  • typeof obj.prop!=='undefined':驗證屬性值的型別 *obj.hasOwnProperty('prop'):驗證物件是否擁有自己的屬性
  • obj`中的'prop':驗證物件是否有自己的或繼承的屬性

我的建議是使用in運算子。它有一個簡短而甜美的語法。in操作符存在意味著明確的目的是檢查物件是否具有特定的屬性,而不訪問實際的屬性值。

![不要寫var,寫const並在JavaScript中放置](https://p0.ssl.qhimg.com/t010effea86a232d8a4.png)

obj.hasOwnProperty('prop')也是一個不錯的解決方案。它比in運算子略長,並且只在物件自己的屬性中進行驗證。

涉及與'undefined'比較的兩種方式可能會起作用......但在我看來obj.prop!== undefined和typeof obj.prop!=='undefined`看起來冗長而怪異,並且暴露直接處理undefined的懷疑路徑。

讓我們使用in運算子來改進append(array,toAppend)函式:

function append(array,toAppend) { 
 const arrayCopy = array.slice(); 
 if ('first' in toAppend) { 
 arrayCopy.unshift(toAppend.first); 
 } 
 if ('last' in toAppend) { 
 arrayCopy.push(toAppend.last); 
 } 
 return arrayCopy; 
} 
append([2,5] 
append([10],last: false }); // => [0,10,false]

Tip 4: 用物件結構的方式訪問物件的屬性

訪問物件屬性時,如果該屬性不存在,有時需要指示預設值。

你可以使用in伴隨著三元運算子來實現:

const object = { }; 
const prop = 'prop' in object ? object.prop : 'default'; 
prop; // => 'default' 

當要檢查的屬性數量增加時,三元運算子語法的使用會變得艱鉅。對於每個屬性,你必須建立一個新的程式碼行來處理預設值,增加類似外觀的三元運算子的醜陋牆。

為了使用更優雅的方法,讓我們熟悉稱為object destructuring的一個偉大的ES2015功能。[物件解構](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring)允許直接將物件屬性值直接提取到變數中,並設定預設值if 該屬性不存在。

避免直接處理undefined的簡便語法。

事實上,現在的屬性解析看起來簡短且明瞭:

const object = { }; 
const { prop = 'default' } = object; 
prop; // => 'default' 

為了看到實際情況,讓我們定義一個有用的函式,將字串包裝在引號中。quote(subject,config)接受第一個引數作為要包裝的字串。第二個引數config是一個具有以下屬性的物件:

char:引號字元,例如 (單引號)或(雙引號),預設為`。 skipIfQuoted:如果字串已被引用,則跳過引用的布林值。預設為true。

應用物件解構的好處,讓我們實現反引號的使用:

function quote(str,config) { 
 const { char = '"',skipIfQuoted = true } = config; 
 const length = str.length; 
 if (skipIfQuoted 
 && str[0] === char 
 && str[length - 1] === char) { 
 return str; 
 } 
 return char + str + char; 
} 
quote('Hello World',{ char: '*' }); // => '*Hello World*' 
quote('"Welcome"',{ skipIfQuoted: true }); // => '"Welcome"' 
 
`` 
`const {char =''',skipIfQuoted = true} = config`解構賦值在一行中從`config`物件中提取屬性`char`和`skipIfQuoted`如果某些屬性在`config`物件中不可用, 解構賦值將預設值設定為:''''''為'char','false'為'skipIfQuoted`。 
 
幸運的是,該功能還有改進的空間。 
讓我們將解構賦值移到引數部分。併為`config`引數設定一個預設值(一個空物件`{}`),以在預設設定足夠時跳過第二個引數。 
 
[Try in repl.it](https://repl.it/HK1b/0) 
 
```javascript 
function quote(str,{ char = '"',skipIfQuoted = true } = {}) { 
 const length = str.length; 
 if (skipIfQuoted 
 && str[0] === char 
 && str[length - 1] === char) { 
 return str; 
 } 
 return char + str + char; 
} 
quote('Hello World',{ char: '*' }); // => '*Hello World*' 
quote('Sunny day');   // => '"Sunny day"' 

請注意,解構賦值將替換函式簽名中的“config”引數。我喜歡這樣:quote()變成一行更短。在解構賦值右側的= {}確保在第二個引數沒有在quote('Sunny day')`中被指定時使用空物件。

物件解構是一個強大的功能,可以有效地處理從物件中提取屬性。我喜歡在訪問的屬性不存在時指定要返回的預設值的可能性。因此,避免了“未定義”以及與處理它有關的問題。

Tip 5: 用預設屬性填充物件

如果不需要像解構分配那樣為每個屬性建立變數,則缺少某些屬性的物件可以用預設值填充。

ES2015Object.assign(target,source1,source2,...)將所有可列舉屬性的值從一個或多個源物件複製到目標物件中。該函式返回目標物件。

例如,您需要訪問unsafeOptions物件的屬性,該屬性並不總是包含其全部屬性。

為了在unsafeOptions中訪問一個不存在的屬性時避免undefined,讓我們做一些調整:

  • 定義一個儲存預設屬性值的物件defaults
  • 呼叫Object.assign({},defaults,unsafeOptions)來構建一個新的物件options。新物件接收來自unsafeOptions的所有屬性,但缺少的屬性來自defaults。
const unsafeOptions = { 
 fontSize: 18 
}; 
const defaults = { 
 fontSize: 16,color: 'black' 
}; 
const options = Object.assign({},defaults,unsafeOptions); 
options.fontSize; // => 18 
options.color; // => 'black' 

Object.assign()將第一個引數作為目標物件{}。目標物件從unsafeOptions源物件接收fontSize屬性的值。並且來自defaults源物件的color屬性的值,因為unsafeOptions不包含color。列舉源物件的順序很重要:稍後的源物件屬性將覆蓋先前的物件屬性。

您現在可以安全地訪問options物件的任何屬性,包括最初在unsafeOptions中不可用的options.color。

幸運的是,使用預設屬性填充物件的方式更簡單輕鬆。我建議使用一個新的JavaScript特性(現在在[stage 3](https://tc39.github.io/process-document/)),它允許[在物件初始化器中傳播屬性](https://github.com/ TC39/提議物件,其餘的擴充套件)。

代替Object.assign()呼叫,使用物件擴充套件語法將來自源物件的所有屬性和可列舉屬性複製到目標物件中:

const unsafeOptions = { 
 fontSize: 18 
}; 
const defaults = { 
 fontSize: 16,color: 'black' 
}; 
const options = { 
 ...defaults,...unsafeOptions 
}; 
options.fontSize; // => 18 
options.color; // => 'black' 

物件初始值設定項從defaults和unsafeOptions源物件傳播屬性。指定源物件的順序很重要:稍後的源物件屬性會覆蓋先前的物件屬性。

使用預設屬性值填充不完整的物件是使程式碼安全和穩定的有效策略。不管情況如何,物件總是包含全部屬性:'undefined'不能生成。

2.3 函式的引數

函式引數預設預設為undefined。

通常,應使用相同數量的引數呼叫使用特定數量的引數定義的函式。在這種情況下,這些引數將獲得您期望的值:

function multiply(a,b) { 
 a; // => 5 
 b; // => 3 
 return a * b; 
} 
multiply(5,3); // => 15 

當您在呼叫中省略引數時會發生什麼?函式內部的引數變成undefined。

讓我們稍微修改前面的例子,只用一個引數呼叫函式:

function multiply(a,b) { 
 a; // => 5 
 b; // => undefined 
 return a * b; 
} 
multiply(5); // => NaN 

Tip 6: 給引數預設值

有時函式不需要呼叫的全套引數。可以簡單地為沒有值的引數設定預設值。

看例子:

function multiply(a,b) { 
 if (b === undefined) { 
 b = 2; 
 } 
 a; // => 5 
 b; // => 2 
 return a * b; 
} 
multiply(5); // => 10 

The function is invoked with a single argument multiply(5). Initially a parameter is 2 and b is undefined. The conditional statement verifies whether b is undefined. If it happens,b = 2 assignment sets a default value.

儘管提供了分配預設值的方式,但我不建議直接比較'undefined'。它很冗長,看起來像一個黑客。

更好的方法是使用ES2015 [預設引數](https://www.sitepoint.com/es6-default-parameters/)功能。 它很短,很有表現力,並且與'undefined`沒有直接的對比。

例子修改,新增預設值:

function multiply(a,b = 2) { 
 a; // => 5 
 b; // => 2 
 return a * b; 
} 
multiply(5);  // => 10 
multiply(5,undefined); // => 10 

ES2015的預設引數功能非常直觀和高效。始終使用它來為可選引數設定預設值。

2.4 函式返回值

隱式地,沒有return語句,JavaScript函式返回undefined。

在JavaScript中,沒有任何return語句的函式隱式地返回undefined:

function square(x) { 
 const res = x * x; 
} 
square(2); // => undefined 

square()函式不返回任何計算結果。函式呼叫結果是'未定義的'。

當return語句存在時會發生同樣的情況,但是附近沒有表示式:

function square(x) { 
 const res = x * x; 
 return; 
} 
square(2); // => undefined 

return;語句被執行,但它不返回任何表示式。呼叫結果也是undefined。

當然,在'return'附近表示要返回的表示式按預期工作:

function square(x) { 
 const res = x * x; 
 return res; 
} 
square(2); // => 4 

Tip 7: 不要相信自動分號插入

以下JavaScript語句列表必須以分號(;)結尾:

  • 空的陳述
  • let,const,var,import,export宣告
  • 表示式語句
  • 偵錯程式語句
  • 繼續語句,break語句
  • 丟擲宣告
  • return語句

如果你使用上述語句之一,請務必在末尾指明分號:

function getNum() { 
 // Notice the semicolons at the end 
 let num = 1; 
 return num; 
} 
getNum(); // => 1 

在let宣告和return宣告結尾處寫了一個強制性分號。

當你不想新增這些分號時會發生什麼?例如減少原始檔的大小。

在這種情況下,ECMAScript提供了[Automatic Semicolon Insertion](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-automatic-semicolon-insertion)(ASI)機制,該機制可以插入 你丟失的分號。

在ASI的幫助下,你可以從前面的示例中刪除分號:

function getNum() { 
 // Notice that semicolons are missing 
 let num = 1 
 return num 
} 
getNum() // => 1 

以上文字是有效的JavaScript程式碼。缺少的分號會自動插入。

乍一看,它看起來很有希望。ASI機制讓你跳過不必要的分號。您可以使JavaScript程式碼更小,更易於閱讀。

ASI有一個小而煩人的陷阱。當一個換行符位於return和返回的表示式'return \ n expression之間時,ASI自動在換行符之前插入一個分號; \ n表示式。

在函式內部意味著什麼return;語句?該函式返回undefined。如果您不詳細瞭解ASI的機制,那麼意外返回的“未定義”是誤導性的。

例如,讓我們研究getPrimeNumbers()呼叫的返回值:

function getPrimeNumbers() { 
 return 
 [ 2,5,7,11,13,17 ] 
} 
getPrimeNumbers() // => undefined 

在return語句和陣列文字表達式之間存在一個新行。 JavaScript在return後自動插入一個分號,解釋程式碼如下:

function getPrimeNumbers() { 
 return; 
 [ 2,17 ]; 
} 
getPrimeNumbers(); // => undefined 

語句return;使getPrimeNumbers()函式返回undefined而不是期望的陣列。

通過刪除return和陣列literal之間的換行符可以解決問題:

function getPrimeNumbers() { 
 return [ 
 2,17 
 ]; 
} 
getPrimeNumbers(); // => [2,17] 

我的建議是研究[確切地說](http://www.bradoncode.com/blog/2015/08/26/javascript-semi-colon-insertion/) 自動分號插入的作用,以避免這種情況。

Of course,never put a newline between return and the returned expression.

2.5 void 運算

void運算,計算一個表示式,不返回計算結果,所以返回值為undefined

void 1;   // => undefined 
void (false);  // => undefined 
void {name: 'John Smith'}; // => undefined 
void Math.min(1,3); // => undefined 

[void use]運算子的[一個用例](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void#JavaScript_URIs)是將表示式評估抑制為undefined,依賴 關於評估的一些副作用。

3、陣列中的undefined

You get when accessing an array element with an out of bounds index. 當你試圖想要獲取一個超出陣列界限範圍的下標時,會返回 undefined

const colors = ['blue','white','red']; 
colors[5]; // => undefined 
colors[-1]; // => undefined

陣列colors 有3個元素array has 3 elements,對應的下標分別是 0,1 and 2。 因為在該陣列中不存在下標5和-1,所以當你t訪問colors[5] 和 colors[-1]會返回undefined.

在JavaScript中你可能遇到所謂的稀疏陣列。這些是有間隙的陣列,即在某些索引中沒有定義元素。

當在一個稀疏陣列中訪問一個間隙(又名空槽)時,你也會得到一個'undefined`。

以下示例將生成稀疏陣列並嘗試訪問其空插槽:

const sparse1 = new Array(3); 
sparse1; // => [`<empty slot>`,`<empty slot>`,`<empty slot>`] 
sparse1[0]; // => undefined 
sparse1[1]; // => undefined 
const sparse2 = ['white','blue'] 
sparse2; // => ['white','blue'] 
sparse2[1]; // => undefined 

sparse1 是通過呼叫建構函式“Array”建構函式來建立的。它有3個空插槽。sparse2是用字面量的形式來建立了一個第二個元素為空的陣列。在任何這些稀疏陣列中,訪問一個空插槽的結果都是“undefined”。

在處理陣列時,為了避免捕獲undefined,一定要使用有效的陣列索引,並避免建立稀疏陣列。

4、undefined and null 之間的不同

這裡有個合理的問題:undefined and null他們之間的主要區別是什麼?都是一個指定值用來表示一個空狀態。

主要的區別是:undefined是用來表示一個變數的值沒有被定義。null 這是代表一個物件不存在。

我們來看一下這些區別:

當變數number 被定義,但是沒有給它賦值進行初始化:

let number; 
number; // => undefined 

因此變數number的值為 undefined,.這明確表明了則是一個沒有初始化的變數

同樣的,當你獲取一個物件存在的屬性時,也會發生這樣的情況:該屬性未初始化。

const obj = { firstName: 'Dmitri' }; 
obj.lastName; // => undefined 

上面例子,因為 obj沒有lastName屬性,所以JavaScript會把 obj.lastName 解析為 undefined.

還有另一種情況,當一個變數期待是一個物件或者是一個方法返回一個物件時,但是由於某些原因,你不能例項化一個物件。。那麼這樣的情況下,null就會是一個有意義的指示器,來表示物件缺失。

例如:clone()` 是一個用來複制JavaScript物件的 函式,這個函式期望能夠返回的是一個物件。

function clone(obj) { 
 if (typeof obj === 'object' && obj !== null) { 
 return Object.assign({},obj); 
 } 
 return null; 
} 
clone({name: 'John'}); // => {name: 'John'} 
clone(15);  // => null 
clone(null);  // => null 

然後,可能會傳入一個不是物件的引數:15,null。這種情況下,該函式就不能進行物件複製,所以會返回 null -- 來表示物件缺失

typeof 運算 能夠看出兩個值之間的區別

typeof undefined; // => 'undefined' 
typeof null; // => 'object' 

The 全等運算子 === 對於undefined 和null,也顯示不相等。

let nothing = undefined; 
let missingObject = null; 
nothing === missingObject; // => false 

5、總結

undefined的存在是JavaScript隨意性所造成的,它允許一下任意情況的使用:

  • uninitialized variables
  • 未初始化的物件
  • non-existing object properties or methods
  • 物件沒有的方法或屬性
  • out of bounds indexes to access array elements
  • 陣列的超出長度下標的元素
  • the invocation result of a function that returns nothing
  • 當方法呼叫返回空時

大多數情況下,直接與'undefined'進行比較是一種不好的做法,因為你可能依賴於上面提到的允許但不鼓勵的做法。

一個有效的策略是減少程式碼中未定義關鍵字的出現。在此期間,請總是以令人驚訝的方式記住它的潛在外觀,並通過應用下列有益習慣來防止這種情況發生:

  • 減少未初始化變數的使用
  • 使變數生命週期變短並接近其使用的來源
  • 儘可能為變數分配一個初始值
  • 支援const,否則使用let
  • 使用預設值作為無意義的函式引數
  • 驗證屬性的存在或用預設屬性填充不安全的物件
  • 避免使用稀疏陣列

到此這篇關於處理JavaScript值為undefined的7個小技巧的文章就介紹到這了,更多相關js值為undefined的技巧內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!