成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript檢測(cè)原始值、引用值、屬性

劉德剛 / 2413人閱讀

摘要:檢測(cè)函數(shù)從技術(shù)上講,中的函數(shù)是引用類型,同樣存在構(gòu)造函數(shù),每個(gè)函數(shù)都是其實(shí)例,比如不好的寫法然而,這個(gè)方法亦不能跨幀使用,因?yàn)槊總€(gè)幀都有各自的構(gòu)造函數(shù),好在運(yùn)算符也是可以用于函數(shù)的,返回。

上周寫過(guò)一篇讀書筆記《編寫可維護(hù)的JavaScript》之編程實(shí)踐,其中 第8章 避免『空比較』是博主在工作中遇坑較多的雷區(qū),所以特此把該章節(jié)重新整理分享,希望大家不再坑隊(duì)友(>﹏<)。

在 JavaScript 中,我們常常會(huì)看到這樣的代碼:變量與null的比較(這種用法很有問(wèn)題),用來(lái)判斷變量是否被賦予了一個(gè)合理的值。比如:

var Controller = {
    process: function(items) {
        if (items !== null) { // 不好的寫法
            items.sort();
            items.forEach(function(item) {
                // 執(zhí)行一些邏輯
            });
        }
    }
}

在這段代碼中,process()方法顯然希望items是一個(gè)數(shù)組,因?yàn)槲覀兛吹?b>items擁有sort()forEach()。這段代碼的意圖非常明顯:如果參數(shù)items不是一個(gè)組數(shù),則停止接下來(lái)的操作。這種寫法的問(wèn)題在于,和null的比較并不能真正避免錯(cuò)誤的發(fā)生。items的值可以是1,也可以是是字符串,甚至可以是任意對(duì)象。這些值都和null不相等,進(jìn)而會(huì)導(dǎo)致process()方法一旦執(zhí)行到sort()時(shí)就會(huì)出錯(cuò)。

僅僅和null比較并不能提供足夠的信息來(lái)判斷后續(xù)代碼的執(zhí)行是否真的安全。好在 JavaScript 為我們提供了很多種方法來(lái)檢測(cè)變量的真實(shí)值。

檢測(cè)原始值

在 JavaScript 中有5種原始類型(也稱為簡(jiǎn)單數(shù)據(jù)類型): String、Number、BooleanUndefinedNull。如果你希望一個(gè)值是StringNumber、BooleanUndefined,最佳選擇是使用typeof運(yùn)算符,它會(huì)返回一個(gè)表示類型的字符串。

對(duì)于字符串,typeof返回"string"。

對(duì)于數(shù)字,typeof返回"number"。

對(duì)于布爾值,typeof返回"boolean"。

對(duì)于undefined,typeof返回"undefined"。

typeof的基本語(yǔ)法是:typeof variable,你還可以這樣用:typeof(variable),盡管這是合法的 JavaScript 語(yǔ)法,這種用法讓typeof看起來(lái)像一個(gè)函數(shù)而非運(yùn)算符。鑒于此,我們更推薦無(wú)括號(hào)的寫法。

使用typeof來(lái)檢測(cè)這4種原始類型是非常安全的做法。來(lái)看下面這些例子。

// 檢測(cè)"String"
if (typeof name === "string") {
    anotherName = name.substring(3);
}

// 檢測(cè)"Number"
if (typeof count === "number") {
    updateCount(count);
}

// 檢測(cè)"Boolean"
if (typeof found === "boolean" && found) {
    message("Found!");
}

// 檢測(cè)"Undefined"
if (typeof MyApp === "undefined") {
    MyApp = {
        // 其他代碼
    };
}

typeof運(yùn)算符的獨(dú)特之處在于,將其用于一個(gè)未聲明的變量也不會(huì)報(bào)錯(cuò)。未定義的變量和值為undefined的變量通過(guò)typeof都將返回"undefined"。

最后一個(gè)原始類型null,通過(guò)typeof將返回"object",這看上去很怪異,被認(rèn)為是標(biāo)準(zhǔn)規(guī)范的嚴(yán)重 bug,因此在編程時(shí)要 杜絕使用typeof來(lái)檢測(cè)null的類型

console.log(typeof null);   // "object"

簡(jiǎn)單地和null進(jìn)行比較通常不會(huì)包含足夠的信息以判斷值的類型是否合法,所以null一般不應(yīng)用于檢測(cè)語(yǔ)句。

但有一個(gè)例外,如果所期望的值真的是null,則可以直接和null進(jìn)行比較。例如:

// 如果你需要檢測(cè) null,則使用這種方法
var element = document.getElementById("my-div");
if (element !== null) {
    element.className = "found";
}

如果 DOM 元素不存在,則通過(guò)document.getElementById()得到的值為null。這個(gè)方法要么返回一個(gè)節(jié)點(diǎn),要么返回null。由于這時(shí)null是可預(yù)見(jiàn)的一種輸出,則可以用恒等運(yùn)算符===或非恒等運(yùn)算符!==來(lái)檢測(cè)返回結(jié)果。

typeof運(yùn)算符的返回值除了上述提到的string、number、boolean、undefinedobject之外,還有function。從技術(shù)的角度來(lái)講,函數(shù)在 JavaScript 中也是對(duì)象,不是一種數(shù)據(jù)類型。然而,函數(shù)也確實(shí)有一些特殊的屬性,因此通過(guò)typeof運(yùn)算符來(lái)區(qū)分函數(shù)和其他對(duì)象是有必要的。這一特性將在后面 檢測(cè)函數(shù) 中用到。

檢測(cè)引用值

在 JavaScript 中除了原始值之外的都是引用值(也稱為對(duì)象),常用的引用類型有:Object、ArrayDateRegExp,這些引用類型都是 JavaScript 的內(nèi)置對(duì)象。typeof運(yùn)算符在判斷這些引用類型時(shí)全都返回"object"。

console.log(typeof {});             // "object"
console.log(typeof []);             // "object"
console.log(typeof new Date());     // "object"
console.log(typeof new RegExp());   // "object"

檢測(cè)某個(gè)引用值類型的最好方法是使用instanceof運(yùn)算符,instanceof的基本語(yǔ)法是:

value instanceof constructor

// 檢測(cè)日期
if (value instanceof Date) {
    console.log(value.getFullYear);
}

// 檢測(cè) Error
if (value instanceof Error) {
    throw value;
}

// 檢測(cè)正則表達(dá)式
if (value instanceof RegExp) {
    if (value.test(anotherValue)) {
        console.log("Matches");
    }
}

instanceof的一個(gè)有意思的特性是它不僅檢測(cè)構(gòu)造這個(gè)對(duì)象的構(gòu)造器,還檢測(cè)原型鏈。原型鏈包含了很多信息,包括定義對(duì)象所采用的繼承模式。比如,默認(rèn)情況下,每個(gè)對(duì)象都繼承自Object,因此每個(gè)對(duì)象的value instanceof Object都會(huì)返回ture。比如:

var now = new Date();
console.log(now instanceof Object); // ture
console.log(now instanceof Date);   // ture

instanceof運(yùn)算符也可以檢測(cè)自定義的類型,比如:

function Person(name){
    this.name = name;
}
var me = new Person("Nicholas");
console.log(me instanceof Object);  // ture
console.log(me instanceof Person);  // ture

這段示例代碼中創(chuàng)建了Person類型。變量mePerson的實(shí)例,因此me instanceof Persontrue。上文也提到,所有的對(duì)象都被認(rèn)為是Object的實(shí)例,因此me instanceof Object也是ture。

在 JavaScript 中檢測(cè) 內(nèi)置類型自定義類型 時(shí),最好的做法就是使用instanceof運(yùn)算符,這也是唯一的方法。

但有一個(gè)嚴(yán)重的限制,假設(shè)兩個(gè)瀏覽器幀(frame)里都有構(gòu)造函數(shù)Person,幀A中的Person實(shí)例frameAPersonInstance傳入到幀B中,則會(huì)有如下結(jié)果:

console.log(frameAPersonInstance instanceof frameAPerson)    // ture
console.log(frameAPersonInstance instanceof frameBPerson)    // false

盡管兩個(gè)Person的定義是完全一樣的,但在不同幀(frame)里,他們被認(rèn)為是不同類型。有兩個(gè)非常重要的內(nèi)置類型也有這個(gè)問(wèn)題:ArrayFunction,所以檢測(cè)它們一般不使用instanceof

檢測(cè)函數(shù)

從技術(shù)上講,JavaScript 中的函數(shù)是引用類型,同樣存在Function構(gòu)造函數(shù),每個(gè)函數(shù)都是其實(shí)例,比如:

function myFunc() {}

// 不好的寫法
console.log(myFunc instanceof Function); // true

然而,這個(gè)方法亦不能跨幀(frame)使用,因?yàn)槊總€(gè)幀都有各自的Function構(gòu)造函數(shù),好在typeof運(yùn)算符也是可以用于函數(shù)的,返回"function"。

function myFunc() {}

// 好的寫法
console.log(typeof myFunc === "function"); // true

檢測(cè)函數(shù)最好的方法是使用typeof,因?yàn)樗梢钥鐜╢rame)使用。

typeof來(lái)檢測(cè)函數(shù)有一個(gè)限制。在 IE 8 和更早版本的 IE 瀏覽器中,使用typeof來(lái)檢測(cè) DOM 節(jié)點(diǎn)中的函數(shù)都返回"object"而不是"function"。比如:

// IE8 及更早版本的IE
console.log(typeof document.createElement);         // "object"
console.log(typeof document.getElementById);        // "object"
console.log(typeof document.getElementByTagName);   // "object"

之所以出現(xiàn)這種怪異的現(xiàn)象是因?yàn)闉g覽器對(duì) DOM 的實(shí)現(xiàn)有差異。簡(jiǎn)言之,這些早版本的 IE 并沒(méi)有將 DOM 實(shí)現(xiàn)為內(nèi)置的 JavaScript 方法,導(dǎo)致內(nèi)置typeof運(yùn)算符將這些函數(shù)識(shí)別為對(duì)象。因?yàn)?DOM 是有明確定義的,了解到對(duì)象成員如果存在則意味著它是一個(gè)方法,開發(fā)者往往通過(guò)in運(yùn)算符來(lái)檢測(cè) DOM 的方法,比如:

// 檢測(cè) DOM 方法
if ("querySelectorAll" in document) {
    var images = document.querySelectorAll("img");
}

這段代碼檢查querySelectorAll是否定義在document中,如果是,則使用這個(gè)方法。盡管不是最理想的方法,如果想在 IE 8 及更早瀏覽器中檢測(cè) DOM 方法是否存在,這是最安全的做法。在其他所有的情形中,typeof運(yùn)算符是檢測(cè) JavaScript 函數(shù)的最佳選擇。

檢測(cè)數(shù)組

JavaScript 中最古老的跨域問(wèn)題之一就是在幀(frame)之間來(lái)回傳遞數(shù)組。開發(fā)者很快發(fā)現(xiàn)instanceof Array在此場(chǎng)景中不能返回正確的結(jié)果。正如上文提到的,每個(gè)幀都有各自的Array構(gòu)造函數(shù),因此一個(gè)幀中的實(shí)例在另外一個(gè)幀里不會(huì)被識(shí)別。

關(guān)于如何在 JavaScript 中檢測(cè)數(shù)組類型已經(jīng)有狠多研究了,最終 Kangax 給出了一種優(yōu)雅的解決方案:

function isArray(value) {
    return Object.prototype.toString.call(value) === "[object Array]";
}

Kangax 發(fā)現(xiàn)調(diào)用某個(gè)值的內(nèi)置toString()方法在所有瀏覽器中都會(huì)返回標(biāo)準(zhǔn)的字符串結(jié)果。對(duì)于數(shù)組來(lái)說(shuō),返回的字符串為"[object Array]",也不用考慮數(shù)組實(shí)例實(shí)在哪個(gè)幀(frame)中被構(gòu)造出來(lái)的。這種方法在識(shí)別內(nèi)置對(duì)象時(shí)往往十分有用,但對(duì)于自定義對(duì)象請(qǐng)不要用這種方法。

ECMAScript5 將Array.isArray()正式引入 JavaScript。唯一的目的就是準(zhǔn)確地檢測(cè)一個(gè)值是否為數(shù)組。同 Kangax 的函數(shù)一樣,Array.isArray()也可以檢測(cè)跨幀(frame)傳遞的值,因此很多 JavaScript 類庫(kù)目前都類似地實(shí)現(xiàn)了這個(gè)方法。

function isArray(value) {
    if (typeof Array.isArray === "function") {
        return Array.isArray(value);
    } else {
        return Object.prototype.toString.call(value) === "[object Array]";
    }
}

IE 9+、FireFox 4+、Safari 5+、Opera 10.5+、Chrome 都實(shí)現(xiàn)了Array.isArray()方法。

檢測(cè)屬性

另外一種用到null(以及undefined)的場(chǎng)景是當(dāng)檢測(cè)一個(gè)屬性是否在對(duì)象中存在時(shí),比如:

// 不好的寫法:檢測(cè)假值
if (object[propertyName]) {
    // 一些代碼
}

// 不好的寫法:和null相比較
if (object[propertyName] != null) {
    // 一些代碼
}

// 不好的寫法:和undefined相比較
if (object[propertyName] != undefined) {
    // 一些代碼
}

上面這段代碼里的每個(gè)判斷,實(shí)際上是通過(guò)給定的名字來(lái)檢查屬性的值,而并非判斷給定的名字所指的屬性是否存在。在第一個(gè)判斷中,當(dāng)屬性值為假值時(shí)結(jié)果會(huì)出錯(cuò),比如:0、""(空字符串)、false、nullundefined,畢竟這些都是屬性的合法值。

判斷屬性是否存在的最好的方法是使用in運(yùn)算符。in運(yùn)算符僅僅會(huì)簡(jiǎn)單地判斷屬性是否存在,而不去讀屬性的值,如果實(shí)例對(duì)象的屬性存在、或者繼承自對(duì)象的原型,in運(yùn)算符都會(huì)返回true。比如:

var object = {
    count: 0,
    related: null
};

// 好的寫法
if ("count" in object) {
    // 這里的代碼會(huì)執(zhí)行
}

// 不好的寫法:檢測(cè)假值
if (object["count"]) {
    // 這里的代碼不會(huì)執(zhí)行
}

// 好的寫法
if ("related" in object) {
    // 這里的代碼會(huì)執(zhí)行
}

// 不好的寫法,檢測(cè)是否為
if (object["related"] != null) {
    // 這里的代碼不會(huì)執(zhí)行
}

如果你只想檢查實(shí)例對(duì)象的某個(gè)屬性是否存在,則使用hasOwnProperty()方法。所有繼承自Object的 JavaScript 對(duì)象都有這個(gè)方法,如果實(shí)例中存在這個(gè)屬性則返回true(如果這個(gè)屬性只存在于原型里,則返回false)。需要注意的是,在 IE 8 以及更早版本的 IE 中,DOM 對(duì)象并非繼承自 Object,因此也不包含這個(gè)方法。也就是說(shuō),你在調(diào)用 DOM 對(duì)象的hasOwnProperty()方法之前應(yīng)當(dāng)先檢測(cè)其是否存在。

// 對(duì)于所有非 DOM 對(duì)象來(lái)說(shuō),這是好的寫法
if (object.hasOwnProperty("related")) {
    // 執(zhí)行這里的代碼會(huì)
}

// 如果你不確定是否為 DOM 對(duì)象,則這樣來(lái)寫
if ("hasOwnProperty" in object && object.hasOwnProperty("related")) {
    // 執(zhí)行這里的代碼會(huì)
}

因?yàn)榇嬖?IE 8 以及更早版本的 IE 的情形,在判斷實(shí)例對(duì)象的屬性是否存在時(shí),我更傾向于使用in運(yùn)算符,只有在需要判斷實(shí)例屬性時(shí)才會(huì)用到hasOwnProperty()。

不管你什么時(shí)候需要檢測(cè)屬性的存在性,請(qǐng)使用in運(yùn)算符或者hasOwnProperty()。這樣做可以避免很多 bug。

擴(kuò)展閱讀

《編寫可維護(hù)的JavaScript》

《JavaScript權(quán)威指南(第6版)》

《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》

歡迎來(lái)到 石佳劼的博客,如有疑問(wèn),請(qǐng)?jiān)凇冈摹乖u(píng)論區(qū) 留言,我會(huì)盡量為您解答。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/79703.html

相關(guān)文章

  • JavaScript 面向?qū)ο箝_發(fā)知識(shí)總結(jié)基礎(chǔ)篇

    摘要:字面形式允許你在不需要使用操作符和構(gòu)造函數(shù)顯式創(chuàng)建對(duì)象的情況下生成引用值。操作符以一個(gè)對(duì)象和一個(gè)構(gòu)造函數(shù)作為參數(shù)鑒別數(shù)組有前一小結(jié)可以知道鑒別數(shù)組類型可以使用。屬性是函數(shù)獨(dú)有的,表明該對(duì)象可以被執(zhí)行。這種函數(shù)被稱為匿名函數(shù)。 引子: 1.JavaScript 中的變量類型和類型檢測(cè) 1.1原始類型 1.2引用類型 1.3內(nèi)建類型的實(shí)例化 1.4函數(shù)的字面形式 1.5正則表達(dá)式的字...

    Kross 評(píng)論0 收藏0
  • 【基礎(chǔ)系列】javascript數(shù)據(jù)類型(原始類型)

    摘要:返回布爾值,表示參數(shù)字符串是否在原字符串的頭部。布爾值中布爾值有兩個(gè)和和都表示值的空缺,但事從背后更深遠(yuǎn)的角度考慮,他們的還是有差別的。首先我們來(lái)看一下類型轉(zhuǎn)化表任意的值都可以轉(zhuǎn)換為布爾值,只有會(huì)被轉(zhuǎn)換為,其他所有值都會(huì)被轉(zhuǎn)換成。 開辟了一個(gè)關(guān)于javascript的基礎(chǔ)系列,更加深入、細(xì)致的了解這門語(yǔ)言。今天分享的是js的數(shù)據(jù)類型。 javascript的數(shù)據(jù)類型可以分為兩類:原始類...

    aikin 評(píng)論0 收藏0
  • JavaScript面向?qū)ο缶?一)

    摘要:使函數(shù)不同于其他對(duì)象的決定性特性是函數(shù)存在一個(gè)被稱為的內(nèi)部屬性。其中,是一個(gè)布爾值,指明改對(duì)象本身是否可以被修改值為。注意凍結(jié)對(duì)象和封印對(duì)象均要在嚴(yán)格模式下使用。 數(shù)據(jù)類型 在JavaScript中,數(shù)據(jù)類型分為兩類: 原始類型:保存一些簡(jiǎn)單數(shù)據(jù),如true,5等。JavaScript共有5中原始類型: boolean:布爾,值為true或false number:數(shù)字,值...

    hiYoHoo 評(píng)論0 收藏0
  • [譯]Understanding javascript's 'undefined

    摘要:一個(gè)表示編譯器檢測(cè)到一個(gè)無(wú)效的引用值。在實(shí)際情況中,往往是在獲取一個(gè)未被賦值的引用時(shí)被拋出。任何一個(gè)函數(shù)上下文都有一個(gè)被稱為活動(dòng)對(duì)象的變量對(duì)象。沒(méi)有找到的話,就會(huì)認(rèn)為引用名沒(méi)有基礎(chǔ)值并拋出的錯(cuò)誤。下沒(méi)有下的屬性僅存在于被啟動(dòng)的情況下。 和其他語(yǔ)言相比,javascript中的對(duì)于undefined的理解還是有點(diǎn)讓人困惑的。特別是試著理解ReferenceErrors錯(cuò)誤(x is no...

    galaxy_robot 評(píng)論0 收藏0
  • <<編寫可維護(hù)的javascript>> 筆記8(避免'空比較&#

    摘要:中常常會(huì)看到這種代碼變量與的比較這種用法很有問(wèn)題用來(lái)判斷變量是否被賦予了一個(gè)合理的值比如不好的寫法執(zhí)行一些邏輯這段代碼中方法顯然是希望是一個(gè)數(shù)組因?yàn)槲覀兛吹降膿碛泻瓦@段代碼的意圖非常明顯如果參數(shù)不是一個(gè)數(shù)組則停止接下來(lái)的操作這種寫法的問(wèn)題在 js中, 常常會(huì)看到這種代碼: 變量與null的比較(這種用法很有問(wèn)題), 用來(lái)判斷變量是否被賦予了一個(gè)合理的值. 比如: const Contr...

    young.li 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<