成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

7個處理JavaScript值為undefined的技巧

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

 前言

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

[[335254]]

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

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

而在JavaScript里,當你要獲取一個變量或對象(未初始化)的值時,js引擎會返回 undefined。

 

  1. let company; 
  2. company;    // => undefined 
  3. let person = { name'John Smith' }; 
  4. person.age; // => undefined 

另一方面,對象引用錯誤會返回null。JavaScript本身并不會給將變量或者對象屬性的值設為 null。

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

 

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

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

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

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

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

 

  1. function undefined() { 
  2.   // 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

 

  1. let number; 
  2. number;     // => undefined 
  3.  
  4. let movie = { name'Interstellar' }; 
  5. movie.year; // => undefined 
  6.  
  7. let movies = ['Interstellar''Alexander']; 
  8. movies[3];  // => undefined   

ECMAScript規范定義了“未定義”值的類型:

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

 

  1. typeof undefined === 'undefined'; // => true 

 

  1. let nothing; 
  2. typeof nothing === 'undefined';   // => true   

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

2.1 未初始化的變量

一個尚未賦值的聲明變量( uninitialized )默認為undefined。

Plain and simple:

 

  1. let myvariable; 
  2. 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根本不可能。

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

 

  1. function isPalindrome(word) { 
  2.   const length = word.length; 
  3.   const half = Math.floor(length / 2); 
  4.   for (let index = 0; index `< half; index++) { 
  5.     if (word[index] !== word[length - index - 1]) { 
  6.       return false
  7.     } 
  8.   } 
  9.   return true
  10. isPalindrome('madam'); // =>` true 
  11. isPalindrome('hello'); // => false   

 

7個處理JavaScript值為undefined的技巧

 

 

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

你可以在函數范圍的末尾聲明一個var變量,但是它仍然可以在聲明之前被訪問:并且你會得到一個undefined。

 

  1. function bigFunction() { 
  2.   // code... 
  3.   myvariable; // => undefined 
  4.   // code... 
  5.   var myVariable = 'Initial value'
  6.   // code... 
  7.   myVariable; // => 'Initial value' 
  8. bigFunction(); 

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

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

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

 

  1. function bigFunction() { 
  2.   // code... 
  3.   myVariable; // => Throws 'ReferenceError: myVariable is not defined' 
  4.   // code... 
  5.   let myVariable = 'Initial value'
  6.   // code... 
  7.   myVariable; // => 'Initial value' 
  8. 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
  • 易于測試

 

7個處理JavaScript值為undefined的技巧

 

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

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

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

不必要的擴展變量生命周期的一個典型例子是在函數內使用for循環:

 

  1. function someFunc(array) { 
  2.   var index, item, length = array.length; 
  3.   // some code... 
  4.   // some code... 
  5.   for (index = 0; index < length; index++) { 
  6.     item = array[index]; 
  7.     // some code... 
  8.   } 
  9.   return 'some result'

index,item和length變量在函數體的開頭聲明。然而,它們只用于接近尾聲。那么這種方法有什么問題?

在頂部的聲明和for語句中的用法之間,變量index,item都是未初始化的并且暴露給undefined。它們在整個功能范圍內的生命周期不合理。

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

 

  1. function someFunc(array) { 
  2.   // some code... 
  3.   // some code... 
  4.   const length = array.length; 
  5.   for (let index = 0; index `< length; index++) { 
  6.     const item = array[index]; 
  7.     // some 
  8.   } 
  9.   return 'some result'

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

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

2.2 訪問不存在的屬性

 

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

看例子:

 

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

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

讓我們稍微修改前面的代碼片段來說明一個“TypeError”拋出:

 

  1. let favoriteMovie = { 
  2.   title: 'Blade Runner' 
  3. }; 
  4. favoriteMovie.actors[0]; 
  5. // 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.

 

  1. function append(array, toAppend) { 
  2.   const arrayCopy = array.slice(); 
  3.   if (toAppend.first) { 
  4.     arrayCopy.unshift(toAppend.first); 
  5.   } 
  6.   if (toAppend.last) { 
  7.     arrayCopy.push(toAppend.last); 
  8.   } 
  9.   return arrayCopy; 
  10. append([2, 3, 4], { first: 1, last: 5 }); // => [1, 2, 3, 4, 5] 
  11. append(['Hello'], { last'World' });     // => ['Hello''World'
  12. append([8, 16], { first: 4 });            // => [4, 8, 16]   

 

  1. append([10], { first: 0, lastfalse }); // => [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)函數:

 

  1. function append(array, toAppend) { 
  2.   const arrayCopy = array.slice(); 
  3.   if ('first' in toAppend) { 
  4.     arrayCopy.unshift(toAppend.first); 
  5.   } 
  6.   if ('last' in toAppend) { 
  7.     arrayCopy.push(toAppend.last); 
  8.   } 
  9.   return arrayCopy; 
  10. append([2, 3, 4], { first: 1, last: 5 }); // => [1, 2, 3, 4, 5] 
  11. append([10], { first: 0, lastfalse });  // => [0, 10, false

Tip 4: 用對象結構的方式訪問對象的屬性

訪問對象屬性時,如果該屬性不存在,有時需要指示默認值。

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

 

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

當要檢查的屬性數量增加時,三元運算符語法的使用會變得艱巨。對于每個屬性,你必須創建一個新的代碼行來處理默認值,增加類似外觀的三元運算符的丑陋墻。

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

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

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

 

  1. const object = {  }; 
  2. const { prop = 'default' } = object; 
  3. prop; // => 'default'   

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

char:引號字符,例如 (單引號)或(雙引號),默認為`。 skipIfQuoted:如果字符串已被引用,則跳過引用的布爾值。默認為true。

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

 

  1. function quote(str, config) { 
  2.   const { char = '"', skipIfQuoted = true } = config; 
  3.   const length = str.length; 
  4.   if (skipIfQuoted 
  5.       && str[0] === char 
  6.       && str[length - 1] === char) { 
  7.     return str; 
  8.   } 
  9.   return char + str + char
  10. quote('Hello World', { char'*' });        // => '*Hello World*' 
  11. quote('"Welcome"', { skipIfQuoted: true }); // => '"Welcome"' 
  12.  
  13. `` 
  14. `const {char =''',skipIfQuoted = true} = config`解構賦值在一行中從`config`對象中提取屬性`char`和`skipIfQuoted`如果某些屬性在`config`對象中不可用, 解構賦值將默認值設置為:''''''為'char','false'為'skipIfQuoted`。 
  15.  
  16. 幸運的是,該功能還有改進的空間。 
  17. 讓我們將解構賦值移到參數部分。并為`config`參數設置一個默認值(一個空對象`{}`),以在默認設置足夠時跳過第二個參數。 
  18.  
  19. [Try in repl.it](https://repl.it/HK1b/0) 
  20.  
  21. ```javascript 
  22. function quote(str, { char = '"', skipIfQuoted = true } = {}) { 
  23.   const length = str.length; 
  24.   if (skipIfQuoted 
  25.       && str[0] === char 
  26.       && str[length - 1] === char) { 
  27.     return str; 
  28.   } 
  29.   return char + str + char
  30. quote('Hello World', { char'*' }); // => '*Hello World*' 
  31. 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。

 

  1. const unsafeOptions = { 
  2.   fontSize: 18 
  3. }; 
  4. const defaults = { 
  5.   fontSize: 16, 
  6.   color: 'black' 
  7. }; 
  8. const options = Object.assign({}, defaults, unsafeOptions); 
  9. options.fontSize; // => 18 
  10. 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()調用,使用對象擴展語法將來自源對象的所有屬性和可枚舉屬性復制到目標對象中:

 

  1. const unsafeOptions = { 
  2.   fontSize: 18 
  3. }; 
  4. const defaults = { 
  5.   fontSize: 16, 
  6.   color: 'black' 
  7. }; 
  8. const options = { 
  9.   ...defaults, 
  10.   ...unsafeOptions 
  11. }; 
  12. options.fontSize; // => 18 
  13. options.color;    // => 'black' 

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

使用默認屬性值填充不完整的對象是使代碼安全和穩定的有效策略。不管情況如何,對象總是包含全部屬性:'undefined'不能生成。

2.3 函數的參數

函數參數默認默認為undefined。

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

 

  1. function multiply(a, b) { 
  2.   a; // => 5 
  3.   b; // => 3 
  4.   return a * b; 
  5. multiply(5, 3); // => 15   

當您在調用中省略參數時會發生什么?函數內部的參數變成undefined。

讓我們稍微修改前面的例子,只用一個參數調用函數:

 

  1. function multiply(a, b) { 
  2.   a; // => 5 
  3.   b; // => undefined 
  4.   return a * b; 
  5. multiply(5); // => NaN   

Tip 6: 給參數默認值

有時函數不需要調用的全套參數。可以簡單地為沒有值的參數設置默認值。

看例子:

 

  1. function multiply(a, b) { 
  2.   if (b === undefined) { 
  3.     b = 2; 
  4.   } 
  5.   a; // => 5 
  6.   b; // => 2 
  7.   return a * b; 
  8. 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`沒有直接的對比。

例子修改,添加默認值:

 

  1. function multiply(a, b = 2) { 
  2.   a; // => 5 
  3.   b; // => 2 
  4.   return a * b; 
  5. multiply(5);            // => 10 
  6. multiply(5, undefined); // => 10   

ES2015的默認參數功能非常直觀和高效。始終使用它來為可選參數設置默認值。

2.4 函數返回值

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

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

 

  1. function square(x) { 
  2.   const res = x * x; 
  3. square(2); // => undefined   

square()函數不返回任何計算結果。函數調用結果是'未定義的'。

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

 

  1. function square(x) { 
  2.   const res = x * x; 
  3.   return
  4. square(2); // => undefined   

return;語句被執行,但它不返回任何表達式。調用結果也是undefined。

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

 

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

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

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

  • 空的陳述
  • let,const,var,import,export聲明
  • 表達式語句
  • 調試器語句
  • 繼續語句,break語句
  • 拋出聲明
  • return語句

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

 

  1. function getNum() { 
  2.   // Notice the semicolons at the end 
  3.   let num = 1; 
  4.   return num; 
  5. 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的幫助下,你可以從前面的示例中刪除分號:

 

  1. function getNum() { 
  2.   // Notice that semicolons are missing 
  3.   let num = 1 
  4.   return num 
  5. getNum() // => 1   

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

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

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

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

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

 

  1. function getPrimeNumbers() { 
  2.   return 
  3.     [ 2, 3, 5, 7, 11, 13, 17 ] 
  4. getPrimeNumbers() // => undefined   

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

 

  1. function getPrimeNumbers() { 
  2.   return
  3.   [ 2, 3, 5, 7, 11, 13, 17 ]; 
  4. getPrimeNumbers(); // => undefined   

語句return;使getPrimeNumbers()函數返回undefined而不是期望的數組。

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

 

  1. function getPrimeNumbers() { 
  2.   return [ 
  3.     2, 3, 5, 7, 11, 13, 17 
  4.   ]; 
  5. getPrimeNumbers(); // => [2, 3, 5, 7, 11, 13, 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

 

  1. void 1;                    // => undefined 
  2. void (false);              // => undefined 
  3. void {name'John Smith'}; // => undefined 
  4. 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

 

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

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

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

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

以下示例將生成稀疏數組并嘗試訪問其空插槽:

 

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

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

在處理數組時,為了避免捕獲undefined,一定要使用有效的數組索引,并避免創建稀疏數組。

4、undefined and null 之間的不同

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

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

我們來看一下這些區別:

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

 

  1. let number; 
  2. number; // => undefined 

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

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

 

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

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

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

例如:clone()` 是一個用來復制JavaScript對象的 函數,這個函數期望能夠返回的是一個對象。

 

  1. function clone(obj) { 
  2.   if (typeof obj === 'object' && obj !== null) { 
  3.     return Object.assign({}, obj); 
  4.   } 
  5.   return null
  6. clone({name'John'}); // => {name'John'
  7. clone(15);             // => null 
  8. clone(null);           // => null   

然后,可能會傳入一個不是對象的參數:15,null。這種情況下,該函數就不能進行對象復制,所以會返回 null -- 來表示對象缺失

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

 

  1. typeof undefined; // => 'undefined' 
  2. typeof null;      // => 'object' 

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

 

  1. let nothing = undefined; 
  2. let missingObject = null
  3. 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
  • 使用默認值作為無意義的函數參數
  • 驗證屬性的存在或用缺省屬性填充不安全的對象
  • 避免使用稀疏數組

 

責任編輯:華軒 來源: 前端Q
相關推薦

2010-05-24 14:06:31

JavaScript

2012-02-13 13:44:46

JavaScript

2023-10-16 07:55:15

JavaScript對象技巧

2025-02-13 13:14:49

JavaScriptnullundefined

2023-07-17 15:28:03

JavaScrip開發

2023-07-24 07:11:43

2010-10-08 10:03:52

JavaScript圖像

2020-09-29 08:14:46

JavaScript開發代碼

2024-08-21 14:55:02

2023-11-26 17:54:07

JavaScript開發

2022-12-25 16:03:31

JavaScript技巧

2023-08-11 17:39:43

JavaScriptWeb 應用程序

2022-12-22 14:44:06

JavaScript技巧

2020-06-09 09:13:12

JavaScript重構對象

2019-07-04 19:06:04

技術人工智能大數據

2024-07-26 00:00:05

JavaScript單行技巧

2020-12-07 08:01:59

JavaScript入門技巧

2023-06-28 00:02:40

2023-08-18 15:12:00

JavaScript開發

2019-12-20 14:32:55

JavaScript函數開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美精品导航 | 成人精品国产免费网站 | 在线免费黄色小视频 | 精品国产伦一区二区三区观看说明 | 一区二区三区四区不卡 | 中文一区| 亚洲一区二区精品视频在线观看 | 欧美理伦片在线播放 | 丁香综合| 欧美久久久久久久久中文字幕 | 欧美a在线看 | 自拍视频一区二区三区 | 一区二区三区四区毛片 | 日韩欧美在线视频观看 | 9久久精品 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 99热在线免费 | 国产精品不卡一区 | 国产精品日韩欧美一区二区三区 | 久久精品亚洲国产奇米99 | 国产人成在线观看 | 国产高清一区二区 | 日韩中文久久 | 国产精品免费观看 | 国产精品久久福利 | 先锋资源网站 | 婷婷综合在线 | 久久草视频 | 五月婷亚洲 | 欧美成视频 | 精品国产久 | 亚洲a视频| 伊人一区| 国产高清精品一区二区三区 | 国产伦精品一区二区三区四区视频 | 亚洲中字在线 | 精品一区二区在线观看 | 狠狠天天 | 欧美日韩一二区 | 成人一级视频在线观看 | 国产成人精品一区二区在线 |