成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

JavaScript中7個(gè)處理undefined的小技巧

JavaScript中7個(gè)處理undefined的小技巧

當(dāng)原作者開(kāi)始學(xué)習(xí)JS時(shí),遇到了一個(gè)奇怪的情況,既存在undefined 的值,也存在表示空值的null。它們之間的明顯區(qū)別是什么?它們似乎都定義了空值,而且,比較null == undefined的計(jì)算結(jié)果為true。

大多數(shù)現(xiàn)代語(yǔ)言,如Ruby、Python或Java都有一個(gè)空值(nilnull),這似乎是一種合理的方式。

對(duì)于JavaScript,解釋器在訪問(wèn)尚未初始化的變量或?qū)ο髮傩詴r(shí)返回undefined。例如:

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

另一方面,null表示缺少的對(duì)象引用,JS本身不會(huì)將變量或?qū)ο髮傩栽O(shè)置為null

一些原生方法,比如String.prototype.match(),可以返回null來(lái)表示丟失的對(duì)象??纯聪旅娴氖纠?/p>

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

由于 JS 的寬容特性,開(kāi)發(fā)人員很容易訪問(wèn)未初始化的值,我也犯了這樣的錯(cuò)誤。

通常,這種危險(xiǎn)的操作會(huì)生成 undefined 的相關(guān)錯(cuò)誤,從而快速地結(jié)束腳本。相關(guān)的常見(jiàn)錯(cuò)誤消息有:

  • TypeError: 'undefined' is not a function

  • TypeError: Cannot read property '<prop-name>' of undefined

  • type errors

JS 開(kāi)發(fā)人員可以理解這個(gè)笑話的諷刺:

function undefined() {     // problem solved }

為了降低此類錯(cuò)誤的風(fēng)險(xiǎn),必須理解生成undefined的情況。更重要的是抑制它的出現(xiàn)并阻止在應(yīng)用程序中傳播,從而提高代碼的持久性。

讓咱們?cè)敿?xì)討論 undefined 及其對(duì)代碼安全性的影響。

1、undefined 是什么鬼

JS 有6種基本類型

  • Boolean: truefalse

  • Number: 1, 6.7, 0xFF

  • String: "Gorilla and banana"

  • Symbol: Symbol("name") (starting ES2015)

  • Null: null

  • Undefined: undefined

和一個(gè)單獨(dú)的Object 類型:{name: "Dmitri"}, ["apple", "orange"]。

根據(jù)ECMAScript規(guī)范,從6種原始類型中,undefined是一個(gè)特殊的值,它有自己的Undefined類型。

未為變量賦值時(shí)默認(rèn)值為undefined

該標(biāo)準(zhǔn)明確定義,當(dāng)訪問(wèn)未初始化的變量、不存在的對(duì)象屬性、不存在的數(shù)組元素等時(shí),將接收到一個(gè)undefined 的值。例如:

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

上述代碼大致流程:

  • 未初始化的變量number

  • 一個(gè)不存在的對(duì)象屬性movie.year

  • 或者不存在數(shù)組元素movies[3]

都會(huì)被定義為undefined

ECMAScript規(guī)范定義了 undefined 值的類型

Undefined type是其唯一值為undefined 值的類型。

在這個(gè)意義上,typeof undefined返回“undefined”字符串

typeof undefined === "undefined"; // => true

當(dāng)然typeof可以很好地驗(yàn)證變量是否包含undefined的值

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

2、導(dǎo)致undefined的常見(jiàn)場(chǎng)景

2.1 未初始化變量

尚未賦值(未初始化)的聲明變量默認(rèn)為undefined

let myVariable; myVariable; // => undefined

myVariable已聲明,但尚未賦值,默認(rèn)值為undefined

解決未初始化變量問(wèn)題的有效方法是盡可能分配初始值。 變量在未初始化狀態(tài)中越少越好。 理想情況下,你可以在聲明const myVariable ='Initial value'之后立即指定一個(gè)值,但這并不總是可行的。

技巧1:使用 let 和 const 來(lái)代替 var

在我看來(lái),ES6 最好的特性之一是使用const和let聲明變量的新方法。const和let具有塊作用域(與舊的函數(shù)作用域var相反),在聲明行之前都存在于暫時(shí)性死區(qū)。

當(dāng)變量一次性且永久地接收到一個(gè)值時(shí),建議使用const聲明,它創(chuàng)建一個(gè)不可變的綁定。

const的一個(gè)很好的特性是必須為變量const myVariable ='initial'分配一個(gè)初始值。 變量未暴露給未初始化狀態(tài),并且訪問(wèn)undefined是不可能的。

以下示例檢查驗(yàn)證一個(gè)單詞是否是回文的函數(shù):

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

length 和 half 變量被賦值一次。將它們聲明為const似乎是合理的,因?yàn)檫@些變量不會(huì)改變。

如果需要重新綁定變量(即多次賦值),請(qǐng)應(yīng)用let聲明。只要可能,立即為它賦一個(gè)初值,例如,let index = 0。

那么使用 var 聲明呢,相對(duì)于ES6,建議是完全停止使用它。

JavaScript中7個(gè)處理undefined的小技巧

var 聲明的變量提會(huì)被提升到整個(gè)函數(shù)作用域頂部。可以在函數(shù)作用域末尾的某個(gè)地方聲明var變量,但是仍然可以在聲明之前訪問(wèn)它:對(duì)應(yīng)變量的值是 undefined。

相反,用let 或者 const 聲明的變量之前不能訪問(wèn)該變量。之所以會(huì)發(fā)生這種情況,是因?yàn)樽兞吭诼暶髦疤幱跁簳r(shí)死區(qū)。這很好,因?yàn)檫@樣就很少有機(jī)會(huì)訪問(wèn)到 undefined 值。

使用let(而不是var)更新的上述示例會(huì)引發(fā)ReferenceError 錯(cuò)誤,因?yàn)闊o(wú)法訪問(wèn)暫時(shí)死區(qū)中的變量。

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

技巧2:增加內(nèi)聚性

內(nèi)聚描述模塊的元素(命名空間、類、方法、代碼塊)內(nèi)聚在一起的程度。凝聚力的測(cè)量通常被稱為高凝聚力或低內(nèi)聚。

高內(nèi)聚是優(yōu)選的,因?yàn)樗ㄗh設(shè)計(jì)模塊的元素以僅關(guān)注單個(gè)任務(wù),它構(gòu)成了一個(gè)模塊。

  • 專注且易懂:更容易理解模塊的功能

  • 可維護(hù)且更容易重構(gòu):模塊中的更改會(huì)影響更少的模塊

  • 可重用:專注于單個(gè)任務(wù),使模塊更易于重用

  • 可測(cè)試:可以更輕松地測(cè)試專注于單個(gè)任務(wù)的模塊

JavaScript中7個(gè)處理undefined的小技巧

高內(nèi)聚和低耦合是一個(gè)設(shè)計(jì)良好的系統(tǒng)的特征。

代碼塊本身可能被視為一個(gè)小模塊,為了盡可能實(shí)現(xiàn)高內(nèi)聚,需要使變量盡可能接近使用它們代碼塊位置。

例如,如果一個(gè)變量?jī)H存在以形成塊作用域內(nèi),不要將此變量公開(kāi)給外部塊作用域,因?yàn)橥獠繅K不應(yīng)該關(guān)心此變量。

不必要地延長(zhǎng)變量生命周期的一個(gè)典型例子是函數(shù)中for循環(huán)的使用:

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'; }

indexitemlength變量在函數(shù)體的開(kāi)頭聲明,但是,它們僅在最后使用,那么這種方式有什么問(wèn)題呢?

從頂部的聲明到for語(yǔ)句中變量 index 和 item 都是未初始化的,值為 undefined。它們?cè)谡麄€(gè)函數(shù)作用域內(nèi)具有不合理較長(zhǎng)的生命周期。

一種更好的方法是將這些變量盡可能地移動(dòng)到使用它們的位置:

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'; }

indexitem變量?jī)H存在于for語(yǔ)句的作用域內(nèi),for 之外沒(méi)有任何意義。length變量也被聲明為接近其使用它的位置。

為什么修改后的版本優(yōu)于初始版本? 主要有幾點(diǎn):

  • 變量未暴露undefined狀態(tài),因此沒(méi)有訪問(wèn)undefined的風(fēng)險(xiǎn)

  • 將變量盡可能地移動(dòng)到它們的使用位置會(huì)增加代碼的可讀性

  • 高內(nèi)聚的代碼塊在必要時(shí)更容易重構(gòu)并提取到單獨(dú)的函數(shù)中

2.2 訪問(wèn)不存在的屬性

訪問(wèn)不存在的對(duì)象屬性時(shí),JS 返回undefined。

咱們用一個(gè)例子來(lái)說(shuō)明這一點(diǎn):

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

favoriteMovie是一個(gè)具有單個(gè)屬性 title 的對(duì)象。 使用屬性訪問(wèn)器favoriteMovie.actors訪問(wèn)不存在的屬性actors將被計(jì)算為undefined

本身訪問(wèn)不存在的屬性不會(huì)引發(fā)錯(cuò)誤, 但嘗試從不存在的屬性值中獲取數(shù)據(jù)時(shí)就會(huì)出現(xiàn)問(wèn)題。 常見(jiàn)的的錯(cuò)誤是 TypeError: Cannot read property <prop> of undefined

稍微修改前面的代碼片段來(lái)說(shuō)明TypeError throw

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

favoriteMovie沒(méi)有屬性actors,所以favoriteMovie.actors的值 undefined。因此,使用表達(dá)式favoriteMovie.actors[0]訪問(wèn)undefined值的第一項(xiàng)會(huì)引發(fā)TypeError

JS 允許訪問(wèn)不存在的屬性,這種允許訪問(wèn)的特性容易引起混淆:可能設(shè)置了屬性,也可能沒(méi)有設(shè)置屬性,繞過(guò)這個(gè)問(wèn)題的理想方法是限制對(duì)象始終定義它所持有的屬性。

不幸的是,咱們常常無(wú)法控制對(duì)象。在不同的場(chǎng)景中,這些對(duì)象可能具有不同的屬性集,因此,必須手動(dòng)處理所有這些場(chǎng)景:

接著我們實(shí)現(xiàn)一個(gè)函數(shù)append(array, toAppend),它的主要功能在數(shù)組的開(kāi)頭和/或末尾添加新的元素。 toAppend參數(shù)接受具有屬性的對(duì)象:

  • first:元素插入數(shù)組的開(kāi)頭

  • last:元素在數(shù)組末尾插入。

函數(shù)返回一個(gè)新的數(shù)組實(shí)例,而不改變?cè)紨?shù)組(即它是一個(gè)純函數(shù))。

append()的第一個(gè)版本看起來(lái)比較簡(jiǎn)單,如下所示:

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, 3, 4, 5] append(['Hello'], { last: 'World' });     // => ['Hello', 'World'] append([8, 16], { first: 4 });            // => [4, 8, 16]

由于toAppend對(duì)象可以省略first或last屬性,因此必須驗(yàn)證toAppend中是否存在這些屬性。如果屬性不存在,則屬性訪問(wèn)器值為undefined。

檢查firstlast屬性是否是undefined,在條件為 if(toappendix .first){}if(toappendix .last){}中進(jìn)行驗(yàn)證:

這種方法有一個(gè)缺點(diǎn), undefinedfalse,null,0NaN''是虛值。

append() 的當(dāng)前實(shí)現(xiàn)中,該函數(shù)不允許插入虛值元素:

append([10], { first: 0, last: false }); // => [10]

0false是虛值的。 因?yàn)?if(toAppend.first){}if(toAppend.last){}實(shí)際上與falsy進(jìn)行比較,所以這些元素不會(huì)插入到數(shù)組中,該函數(shù)返回初始數(shù)組[10]而不會(huì)進(jìn)行任何修改。

以下技巧解釋了如何正確檢查屬性的存在。

技巧3: 檢查屬性是否存在

JS 提供了許多方法來(lái)確定對(duì)象是否具有特定屬性:

  • obj.prop!== undefined:直接與undefined進(jìn)行比較

  • typeof obj.prop!=='undefined':驗(yàn)證屬性值類型

  • obj.hasOwnProperty('prop'):驗(yàn)證對(duì)象是否具有自己的屬性

  • 'prop' in obj:驗(yàn)證對(duì)象是否具有自己的屬性或繼承屬性

我的建議是使用 in 操作符,它的語(yǔ)法短小精悍。in操作符的存在表明一個(gè)明確的意圖,即檢查對(duì)象是否具有特定的屬性,而不訪問(wèn)實(shí)際的屬性值。

JavaScript中7個(gè)處理undefined的小技巧

obj.hasOwnProperty('prop')也是一個(gè)很好的解決方案,它比 in 操作符稍長(zhǎng),僅在對(duì)象自己的屬性中進(jìn)行驗(yàn)證。

涉及與undefined進(jìn)行比較剩下的兩種方式可能有效,但在我看來(lái),obj.prop!== undefinedtypeof obj.prop!=='undefined'看起來(lái)冗長(zhǎng)而怪異,并暴露出直接處理undefined的可疑路徑。。

讓咱們使用in操作符改進(jìn)append(array, toAppend) 函數(shù):

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, 3, 4], { first: 1, last: 5 }); // => [1, 2, 3, 4, 5] append([10], { first: 0, last: false });  // => [0, 10, false]

'first' in toAppend (和'last' in toAppend)在對(duì)應(yīng)屬性存在時(shí)為true,否則為false。in操作符的使用解決了插入虛值元素0false的問(wèn)題?,F(xiàn)在,在[10]的開(kāi)頭和結(jié)尾添加這些元素將產(chǎn)生預(yù)期的結(jié)果[0,10,false]。

技巧4:解構(gòu)訪問(wèn)對(duì)象屬性

在訪問(wèn)對(duì)象屬性時(shí),如果屬性不存在,有時(shí)需要指示默認(rèn)值??梢允褂?code>in和三元運(yùn)算符來(lái)實(shí)現(xiàn)這一點(diǎn)。

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

當(dāng)要檢查的屬性數(shù)量增加時(shí),三元運(yùn)算符語(yǔ)法的使用變得令人生畏。對(duì)于每個(gè)屬性,都必須創(chuàng)建新的代碼行來(lái)處理默認(rèn)值,這就增加了一堵難看的墻,里面都是外觀相似的三元運(yùn)算符。

為了使用更優(yōu)雅的方法,可以使用 ES6 對(duì)象的解構(gòu)。

對(duì)象解構(gòu)允許將對(duì)象屬性值直接提取到變量中,并在屬性不存在時(shí)設(shè)置默認(rèn)值,避免直接處理undefined的方便語(yǔ)法。

實(shí)際上,屬性提取現(xiàn)在看起來(lái)簡(jiǎn)短而有意義:

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

要查看實(shí)際操作中的內(nèi)容,讓我們定義一個(gè)將字符串包裝在引號(hào)中的有用函數(shù)。quote(subject, config)接受第一個(gè)參數(shù)作為要包裝的字符串。 第二個(gè)參數(shù)config是一個(gè)具有以下屬性的對(duì)象:

  • char:包裝的字符,例如 '(單引號(hào))或(雙引號(hào)),默認(rèn)為

  • skipIfQuoted:如果字符串已被引用則跳過(guò)引用的布爾值,默認(rèn)為true。

使用對(duì)象析構(gòu)的優(yōu)點(diǎn),讓咱們實(shí)現(xiàn)quote()

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 = '", skipifquote = true} = config解構(gòu)賦值在一行中從config對(duì)象中提取charskipifquote屬性。如果config對(duì)象中有一些屬性不可用,那么解構(gòu)賦值將設(shè)置默認(rèn)值:char'"',skipifquotefalse。

該功能仍有改進(jìn)的空間。讓我們將解構(gòu)賦值直接移動(dòng)到參數(shù)部分。并為config參數(shù)設(shè)置一個(gè)默認(rèn)值(空對(duì)象{}),以便在默認(rèn)設(shè)置足夠時(shí)跳過(guò)第二個(gè)參數(shù)。

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"'

注意,解構(gòu)賦值替換了函數(shù) config 參數(shù)。我喜歡這樣:quote()縮短了一行。

={}在解構(gòu)賦值的右側(cè),確保在完全沒(méi)有指定第二個(gè)參數(shù)的情況下使用空對(duì)象。

對(duì)象解構(gòu)是一個(gè)強(qiáng)大的功能,可以有效地處理從對(duì)象中提取屬性。 我喜歡在被訪問(wèn)屬性不存在時(shí)指定要返回的默認(rèn)值的可能性。因?yàn)檫@樣可以避免undefined以及與處理它相關(guān)的問(wèn)題。

技巧5: 用默認(rèn)屬性填充對(duì)象

如果不需要像解構(gòu)賦值那樣為每個(gè)屬性創(chuàng)建變量,那么丟失某些屬性的對(duì)象可以用默認(rèn)值填充。

ES6 Object.assign(target,source1,source2,...)將所有可枚舉的自有屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象中,該函數(shù)返回目標(biāo)對(duì)象。

例如,需要訪問(wèn)unsafeOptions對(duì)象的屬性,該對(duì)象并不總是包含其完整的屬性集。

為了避免從unsafeOptions訪問(wèn)不存在的屬性,讓我們做一些調(diào)整:

定義包含默認(rèn)屬性值的defaults對(duì)象

調(diào)用Object.assign({},defaults,unsafeOptions)來(lái)構(gòu)建新的對(duì)象options。 新對(duì)象從unsafeOptions接收所有屬性,但缺少的屬性從defaults對(duì)象獲取。

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

unsafeOptions僅包含fontSize屬性。 defaults對(duì)象定義屬性fontSizecolor的默認(rèn)值。

Object.assign() 將第一個(gè)參數(shù)作為目標(biāo)對(duì)象{}。 目標(biāo)對(duì)象從unsafeOptions源對(duì)象接收fontSize屬性的值。 并且人defaults對(duì)象的獲取color屬性值,因?yàn)?code>unsafeOptions不包含color屬性。

枚舉源對(duì)象的順序很重要:后面的源對(duì)象屬性會(huì)覆蓋前面的源對(duì)象屬性。

現(xiàn)在可以安全地訪問(wèn)options對(duì)象的任何屬性,包括options.color在最初的unsafeOptions中是不可用的。

還有一種簡(jiǎn)單的方法就是使用ES6中展開(kāi)運(yùn)算符:

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

對(duì)象初始值設(shè)定項(xiàng)從defaultsunsafeOptions源對(duì)象擴(kuò)展屬性。 指定源對(duì)象的順序很重要,后面的源對(duì)象屬性會(huì)覆蓋前面的源對(duì)象。

使用默認(rèn)屬性值填充不完整的對(duì)象是使代碼安全且持久的有效策略。無(wú)論哪種情況,對(duì)象總是包含完整的屬性集:并且無(wú)法生成undefined的屬性。

2.3 函數(shù)參數(shù)

函數(shù)參數(shù)隱式默認(rèn)為undefined

通常,用特定數(shù)量的參數(shù)定義的函數(shù)應(yīng)該用相同數(shù)量的參數(shù)調(diào)用。在這種情況下,參數(shù)得到期望的值

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

調(diào)用multiply(5,3)使參數(shù)ab接收相應(yīng)的53值,返回結(jié)果:5 * 3 = 15

在調(diào)用時(shí)省略參數(shù)會(huì)發(fā)生什么?

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

函數(shù)multiply(a, b){}由兩個(gè)參數(shù)ab定義。調(diào)用multiply(5)用一個(gè)參數(shù)執(zhí)行:結(jié)果一個(gè)參數(shù)是5,但是b參數(shù)是undefined。

技巧6: 使用默認(rèn)參數(shù)值

有時(shí)函數(shù)不需要調(diào)用的完整參數(shù)集,可以簡(jiǎn)單地為沒(méi)有值的參數(shù)設(shè)置默認(rèn)值。

回顧前面的例子,讓我們做一個(gè)改進(jìn),如果b參數(shù)未定義,則為其分配默認(rèn)值2

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

雖然所提供的分配默認(rèn)值的方法有效,但不建議直接與undefined值進(jìn)行比較。它很冗長(zhǎng),看起來(lái)像一個(gè)hack .

這里可以使用 ES6 的默認(rèn)值:

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

2.4 函數(shù)返回值

隱式地,沒(méi)有return語(yǔ)句,JS 函數(shù)返回undefined。

在JS中,沒(méi)有任何return語(yǔ)句的函數(shù)隱式返回undefined

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

square() 函數(shù)沒(méi)有返回計(jì)算結(jié)果,函數(shù)調(diào)用時(shí)的結(jié)果undefined。

當(dāng)return語(yǔ)句后面沒(méi)有表達(dá)式時(shí),默認(rèn)返回 undefined。

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

return; 語(yǔ)句被執(zhí)行,但它不返回任何表達(dá)式,調(diào)用結(jié)果也是undefined。

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

技巧7: 不要相信自動(dòng)插入分號(hào)

JS 中的以下語(yǔ)句列表必須以分號(hào)(;)結(jié)尾:

  • 空語(yǔ)句

  • letconst,var,importexport聲明

  • 表達(dá)語(yǔ)句

  • debugger 語(yǔ)句

  • continue 語(yǔ)句,break 語(yǔ)句

  • throw 語(yǔ)句

  • return 語(yǔ)句

如果使用上述聲明之一,請(qǐng)盡量務(wù)必在結(jié)尾處指明分號(hào):

function getNum() {   let num = 1;    return num; } getNum(); // => 1

let 聲明和 return 語(yǔ)句結(jié)束時(shí),強(qiáng)制性寫(xiě)分號(hào)。

當(dāng)你不想寫(xiě)這些分號(hào)時(shí)會(huì)發(fā)生什么? 例如,咱們想要減小源文件的大小。

在這種情況下,ECMAScript 提供自動(dòng)分號(hào)插入(ASI)機(jī)制,為你插入缺少的分號(hào)。

ASI 的幫助下,可以從上一個(gè)示例中刪除分號(hào)

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

上面的代碼是有效的JS代碼,缺少的分號(hào)ASI會(huì)自動(dòng)為我們插入。

乍一看,它看起來(lái)很 nice。 ASI 機(jī)制允許你少寫(xiě)不必要的分號(hào),可以使JS代碼更小,更易于閱讀。

ASI 創(chuàng)建了一個(gè)小而煩人的陷阱。 當(dāng)換行符位于returnreturn n expression之間時(shí),ASI 會(huì)在換行符之前自動(dòng)插入分號(hào)(return; n expression)。

函數(shù)內(nèi)部return; ? 即該函數(shù)返回undefined。 如果你不詳細(xì)了解ASI的機(jī)制,則意外返回的undefined會(huì)產(chǎn)生意想不到的問(wèn)題。

來(lái) getPrimeNumbers()調(diào)用返回的值:

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

return語(yǔ)句和數(shù)組之間存在一個(gè)換行,JS 在return后自動(dòng)插入分號(hào),解釋代碼如下:

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

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

這個(gè)問(wèn)題通過(guò)刪除return和數(shù)組文字之間的換行來(lái)解決:

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

我的建議是研究自動(dòng)分號(hào)插入的確切方式,以避免這種情況。

當(dāng)然,永遠(yuǎn)不要在return和返回的表達(dá)式之間放置換行符。

2.5 void 操作符

void <expression>計(jì)算表達(dá)式無(wú)論計(jì)算結(jié)果如何都返回undefined 。

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

void操作符的一個(gè)用例是將表達(dá)式求值限制為undefined,這依賴于求值的一些副作用。

3、 未定義的數(shù)組

訪問(wèn)越界索引的數(shù)組元素時(shí),會(huì)得到undefined

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

colors數(shù)組有3個(gè)元素,因此有效索引為0,12

因?yàn)樗饕?code>5和-1沒(méi)有數(shù)組元素,所以訪問(wèn)colors[5]colors[-1]值為undefined。

JS 中,可能會(huì)遇到所謂的稀疏數(shù)組。這些數(shù)組是有間隙的數(shù)組,也就是說(shuō),在某些索引中,沒(méi)有定義元素。

當(dāng)在稀疏數(shù)組中訪問(wèn)間隙(也稱為空槽)時(shí),也會(huì)得到一個(gè)undefined

下面的示例生成稀疏數(shù)組并嘗試訪問(wèn)它們的空槽

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

使用數(shù)組時(shí),為了避免獲取undefined,請(qǐng)確保使用有效的數(shù)組索引并避免創(chuàng)建稀疏數(shù)組。

4、 undefined和null之間的區(qū)別

一個(gè)合理的問(wèn)題出現(xiàn)了:undefinednull之間的主要區(qū)別是什么?這兩個(gè)特殊值都表示為空狀態(tài)。

主要區(qū)別在于undefined表示尚未初始化的變量的值,null表示故意不存在對(duì)象。

讓咱們通過(guò)一些例子來(lái)探討它們之間的區(qū)別。

number 定義了但沒(méi)有賦值。

let number; number; // => undefined

number 變量未定義,這清楚地表明未初始化的變量。

當(dāng)訪問(wèn)不存在的對(duì)象屬性時(shí),也會(huì)發(fā)生相同的未初始化概念

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

因?yàn)?code>obj中不存在lastName屬性,所以JS正確地將obj.lastName計(jì)算為undefined。

在其他情況下,你知道變量期望保存一個(gè)對(duì)象或一個(gè)函數(shù)來(lái)返回一個(gè)對(duì)象。但是由于某些原因,你不能實(shí)例化該對(duì)象。在這種情況下,null是丟失對(duì)象的有意義的指示器。

例如,clone()是一個(gè)克隆普通JS對(duì)象的函數(shù),函數(shù)將返回一個(gè)對(duì)象

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

但是,可以使用非對(duì)象參數(shù)調(diào)用clone(): 15null(或者通常是一個(gè)原始值,nullundefined)。在這種情況下,函數(shù)不能創(chuàng)建克隆,因此返回null—— 一個(gè)缺失對(duì)象的指示符。

typeof操作符區(qū)分了這兩個(gè)值

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

嚴(yán)格相等運(yùn)算符===可以正確區(qū)分undefinednull

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

總結(jié)

undefined的存在是JS的允許性質(zhì)的結(jié)果,它允許使用:

  • 未初始化的變量

  • 不存在的對(duì)象屬性或方法

  • 訪問(wèn)越界索引的數(shù)組元素

  • 不返回任何結(jié)果的函數(shù)的調(diào)用結(jié)果

大多數(shù)情況下直接與undefined進(jìn)行比較是一種不好的做法。一個(gè)有效的策略是減少代碼中undefined關(guān)鍵字的出現(xiàn):

  • 減少未初始化變量的使用

  • 使變量生命周期變短并接近其使用的位置

  • 盡可能為變量分配初始值

  • 多敷衍 const 和 let

  • 使用默認(rèn)值來(lái)表示無(wú)關(guān)緊要的函數(shù)參數(shù)

  • 驗(yàn)證屬性是否存在或使用默認(rèn)屬性填充不安全對(duì)象

  • 避免使用稀疏數(shù)組

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
精品久久久无码人妻中文字幕豆芽| 97久久国产亚洲精品超碰热| 被老头一个晚上做了6次| 国产精品久久一区二区三区蜜桃| 精品久久综合1区2区3区激情| 男生听到女生喘气是什么心理现象| 日本三线和韩国三线品牌对比| 无码综合天天久久综合网色吧影院 | 精品人妻一区二区三区浪潮在线 | 亚洲精品国产成人精品| 337P日本欧洲亚洲大胆69影| 高潮喷视频在线无码| 极品人妻被黑人中出种子| 男朋友把舌头都伸进我的嘴巴里了| 色欲香天天天综合网站小说| 亚洲A级成人无码网站| 亚洲欧洲精品成人久久曰| 99国产精品无码| 国产成人无码一区二区在线播放| 久久99精品久久久久久野外| 亲近相奷对白中文字幕片| 无遮高潮国产免费观看| 尤物AV无码国产在线看| 99久久久国产精品消防器材| 国产成人牲交在线观看视频| 久久精品国产清高在天天线| 亲孑伦视频一区二区三区一| 性欧美18ⅩXOO极品FREE| 中文区中文字幕免费看| 高清国产天干天干天干| 久久AⅤ天堂AV无码AV| 人妻人人做人碰人人添青青| 亚洲AV成人一区二区三区网站 | 无码精品人妻一区二区三区AV| 夜夜躁狠狠躁2021| 抽搐一进一出再深一点| 国语对白刺激在线视频国产网红| 男生J桶进女人P又色又爽又黄 | 蜜桃一区二区hd视频网站| 少妇饥渴偷公乱A级无码| 亚洲熟妇AV一区二区三区宅男| 巴西FREE性VIDEO极品| 国色天香精品卡一卡二卡三二百| 女人被狂C到高潮视频网站| 无码精品人妻一区二区三区免费看| 影音先锋女人AV鲁色资源网久久| 多毛BGMBGMBGM胖在线| 久久WWW免费人成人片| 日本人妻丰满熟妇久久久久久| 亚洲成AV人片不卡无码| JAPANESE中国丰满少妇| 国产在线精品二区| 欧美疯狂性受XXXXX喷水| 小东西好几天没弄了还能吃吗| 最新版天堂资源官网在线| 国产精品白丝JK白祙喷水视频| 老熟女太熟了95AV| 天堂资源在线官网| 尤物TV国产精品看片在线| 国产A级三级三级三级| 久久夜色精品国产噜噜亚洲SV| 上面一边亲下一边面膜使用方法 | 找老女人泻火对白自拍| 国产成人18黄网站免费观看| 久久夜色精品国产噜噜AV| 试看A级看一毛片二十分钟| 一本一久本久A久久精品综合| 丰满乳乱亲伦小说| 久久久噜噜噜久久久精品| 少妇被躁爽到高潮无码| 一区二区三区国产精华护肤品| 囯产精品一区二区三区线| 久久夜色精品国产欧美乱| 天堂影院在线观看高清在线 | 国精一二二产品无人区免费应用| 欧美日韩在大午夜爽爽影院| 亚洲AV综合A国产AV中文| 拔萝卜电视剧高清免费| 精品人妻系列无码一区二区三区| 日韩欧美成人免费观看| 野花影视视频在线观看免费| 国产超碰人人模人人爽人人喊| 满18岁夜里禁用100款APP| 无码专区一ⅤA亚洲V天堂| 99久久精品国产一区二区蜜芽| 国内精品国产成人国产三级| 人妻少妇精品久久| 亚洲人成电影网站色WWW| 嗯~啊哈好深好骚啊哼| 胯下硕大征服冰山女神| 无码免费一区二区三区免费播放| 亚洲日本一线产区和二线产区区别| 成人作爱Av一级无码| 久久久久亚洲AV无码专区喷水| 四虎成人精品在永久免费| 伊人天堂Av无码Av日韩Av| 国产精品久久久久久一区二区三区 | 极品少妇流白浆草莓视频| 日韩精品成熟妇人Av一区二区| 亚洲综合色区在线观看| 国产高潮呻吟无码精品AV| 女人浓毛巨茎ⅩXXOOO| 亚洲丁香婷婷久久一区二区| 成人性生交大片免费看| 巨爆乳寡妇中文在线观看| 唔嗯啊欧美一级作爱网站| SUNTEK中老年妈妈| 精品国产亚洲第一区二区三区| 色婷婷AV一区二区三区浪潮慧瑟| 在线观看视频一区二区三区| 国产日产欧洲无码视频| 人妻无码久久一区二区三区免费| 亚洲中文字幕无码一区无广告| 国产激情З∠视频一区二区| 免费影视观看网站入口| 亚洲AV中文无码4区| 粗大挺进亲女H顾晓晓| 毛茸茸的撤尿正面BBW| 亚洲AV成人无码一区二区在线观看 | 欧美熟妇呻吟猛交XX牲| 亚洲日韩欧美一区二区三区| 国产成人无码国产亚洲| 欧美人与性动交α欧美精品| 亚洲色大成网站WWW尤物| 国产黄A三级三级三级| 青青草国产成人A∨| 夜夜躁婷婷AV蜜桃妖精视频| 国产农村妇女精品一二区| 人与禽zozzo性伦| 曰本丰满熟妇XXXX性| 国产亚洲精品精品精品| 日韩精品亚洲人成在线观看| 中文字幕不卡乱偷在线观看| 黑人与亚洲女人XXXXXXXⅩ| 少妇久久久久久被弄高潮| 999精产国品一二三产区区| 精品日产一卡2卡三卡4卡自拍 | 午夜内射高潮视频| 被陌生人在地铁揉到高潮| 乱码人妻Av一区二区三区| 亚洲AV永久无码精品古装片 | 欧美XXXX做受性欧美88| 亚洲人成伊人成综合网久久久| 国产精品第20页| 人妻少妇一区二区| 伊人久久大香线蕉综合AV| 国产午夜无码福利在线看网站| 日韩无码av一区二区| 51FUN吃瓜网-热心群众| 久久99精品久久久久婷婷| 无码专区 人妻系列 在线| 成av人片一区二区三区久久| 免费毛片45分钟| 亚洲精品无码不卡AV| 国产精品久久久久AAAA| 日本大学学校AAAAA| 最新国产免费AV片在线观看| 久久97久久精品免费观看黑人| 无遮挡又爽又刺激的视频| 丁香五月开心婷婷激情综合| 欧美精产国品一二三产品工艺| 一本久久综合亚洲鲁鲁五月天| 国偷自产一区二视频观看| 熟妇无码乱子成人精品| ZOOM人与ZOOMWIDS| 蜜桃av中文字幕| 亚洲色大18成人网站WWW| 国产无遮挡免费真人视频在线观看 | 女教师娇喘潮喷抽搐在线视频| 亚洲熟妇丰满色XXXXX欧美| 国产午夜高清高清在线观看 | 97久久国产露脸精品国产| 久久久久久久久久久精品尤物| 亚洲AV无码国产永久播放蜜芽| 国产成人精品人人做人人爽| 日本japanese人妻护士| 7777色情XXXX欧美| 久久天天躁夜夜躁狠狠85| 亚洲国产成人精品无码区在线播放 | 一本到12不卡视频在线DVD| 狠狠色狠狠色综合| 玩弄放荡人妻一区二区三| 成人综合婷婷国产精品久久蜜臀 | 国产AV无码专区亚洲AⅤ蜜芽| 人妻无码视频一区二区三区| 69美女ⅩXXXXXXX19| 久久午夜羞羞影院免费观看| 亚洲精品高清国产一线久久| 国产日产久久高清欧美一区| 四虎永久在线精品视频| 不屈的儿媳妇电视剧汉语版| 欧美精品九九99久久在免费线| 用嘴巴吃鸡的好处| 精品亚洲国产成人| 亚洲AV无码一区二区三区网站| 国产精品国产AV片国产| 色综合色综合久久综合频道88| 办公室被吃奶好爽在线观看| 欧美高大丰满FREESEX| 中文字幕丰满伦子无码|