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

資訊專欄INFORMATION COLUMN

[你不知道的 JavaScript 類型和語法] 第一章:類型

Astrian / 2468人閱讀

摘要:語言中規(guī)定的類型為以及。這兩個(gè)值有不同的類型。內(nèi)建類型定義了七種內(nèi)建類型中新增提示以上類型,除的被稱為基本類型。新增列出的六種類型的值都會返回一個(gè)對應(yīng)類型名稱的字符串。是中新增的數(shù)據(jù)類型,我們會在第三章詳細(xì)介紹。

譯者的前言

一直都想好好研究這個(gè)在 GitHub 上很有名氣的系列,而翻譯恰是最好的閱讀途徑之一。可以讓我閱讀的時(shí)候,不那么不求甚解。

圖靈社區(qū)出版了該系列兩部分的中文版——《作用域和閉包》以及《this和對象原型》,我就打算從《類型和語法》這本開始做起。

同時(shí),我對本書的翻譯進(jìn)度會在 GitHub 上同步,希望能有更多的同行參與進(jìn)來,將更多的干貨貢獻(xiàn)社區(qū)。

翻譯 GitHub 倉庫地址:https://github.com/StarStudio/You-Dont-Know-JS

原著:https://github.com/getify/You-Dont-Know-JS

PS:最近對于翻譯英文原版系列很有興趣,如果有好的干貨英文文章(且大家信得過我的水平),可以放在評論區(qū),有時(shí)間我一定會翻譯!

第一章:類型

大多數(shù)開發(fā)人員認(rèn)為,動態(tài)語言(如 JavaScript)并沒有類型。讓我們來看看 ES5.1 的 規(guī)范 對于這部分內(nèi)容是怎么說的:

本規(guī)范中所有算法所操作的值都有一個(gè)類型與之對應(yīng)。這些值的類型均在本規(guī)范中對應(yīng)。當(dāng)然,這些類型也可能是 ECMAScript 語言中規(guī)定的類型的子類型。

在 ECMAScript 語言中,每個(gè) ECMAScript 類型所對應(yīng)的值都被 ECMAScript 程序開發(fā)人員直接操作。ECMAScript 語言中規(guī)定的類型為 Undefined, Null, Boolean, String, Number 以及Object。

如果你是強(qiáng)類型語言(靜態(tài)語言)的粉絲,你也許會對這樣使用“類型”感到很反感。在那些語言里,“類型”所擁有的含義可比在 JS 里的多得多。

有人說 JS 不應(yīng)該聲稱它有“類型,應(yīng)該把這種東西稱為“標(biāo)簽”,或是“子類型”。

好吧。我們將使用這一粗略的定義(類似于規(guī)范中所描述的):一個(gè)類型是一個(gè)固有的,內(nèi)建的特征集,無論是編譯引擎還是開發(fā)人員,都可以用它來確定一個(gè)值的行為,并把這個(gè)值和其他值加以區(qū)分。

簡單來說,如果在編譯引擎和開發(fā)人員眼里,值 42(數(shù)字)和值 "42"(字符串)處理的方法不同,那么我們就說他們有不同的類型—— numberstring。當(dāng)你處理 42 時(shí),你將使用一些處理數(shù)字的方法,比如數(shù)學(xué)運(yùn)算。而當(dāng)你處理 "42" 時(shí),你則會使用一些字符串處理方法,比如輸出到頁面,等等。這兩個(gè)值有不同的類型。

雖然這并不是什么嚴(yán)謹(jǐn)?shù)亩x,但對于我們接下來的討論,已經(jīng)綽綽有余了。而且這樣的定義,和JS如何形容自己是一致的。

類型——或是別的什么

不考慮學(xué)術(shù)上的爭論,我們來想想為什么 JavaScript 會需要類型

對于每種類型及其基本行為都有所了解,有助于更高效的將值進(jìn)行類型轉(zhuǎn)換(詳見第四章,類型轉(zhuǎn)換)。幾乎所有的JS程序,都存在著這樣那樣的類型轉(zhuǎn)換,所以了解這些,對你來說很重要。

如果你有一個(gè)值為 42number,但想對它進(jìn)行 string 類型的操作,如移除 1 位置的字符 "2",你最好先將這個(gè)值的類型從 number 轉(zhuǎn)換為 string。

這看似很簡單。

但是進(jìn)行這樣的類型轉(zhuǎn)換,有很多方式。有些方式很明確,很簡單就能說出來龍去脈,并且也值得信賴.但如果你不夠細(xì)心,類型轉(zhuǎn)換可能以一種匪夷所思的方式展現(xiàn)在你面前。

類型轉(zhuǎn)換可能是 JavaScript 最大的疑惑之一了。這點(diǎn)經(jīng)常被視為這一語言的缺陷,是應(yīng)該避免使用的。

由于有了對 JavaScript 類型的全面了解,我們希望能夠說明為何類型轉(zhuǎn)換的壞名聲言過其實(shí),甚至是不恰當(dāng)?shù)摹覀儠淖兡愕膫鹘y(tǒng)觀點(diǎn),讓你看到類型轉(zhuǎn)換的強(qiáng)大力量和實(shí)用性。不過首先,我們先來了解一下值和類型。

內(nèi)建類型

JavaScript 定義了七種內(nèi)建類型:

null

undefined

boolean

number

string

object

symbol —— ES6 中新增

提示:以上類型,除 object 的被稱為基本類型。

typeof 運(yùn)算符會檢測所給值得類型,并返回以下其中字符串類型的值——然而奇怪的是,返回的結(jié)果和我們剛剛列出的的內(nèi)建類型并不一一對應(yīng)。

typeof undefined     === "undefined"; // true
typeof true          === "boolean";   // true
typeof 42            === "number";    // true
typeof "42"          === "string";    // true
typeof { life: 42 }  === "object";    // true

// ES6新增!
typeof Symbol()      === "symbol";    // true

列出的六種類型的值都會返回一個(gè)對應(yīng)類型名稱的字符串。Symbol 是 ES6 中新增的數(shù)據(jù)類型,我們會在第三章詳細(xì)介紹。

你也許注意到了,我將 null 從列表中除去了。因?yàn)樗芴厥狻?dāng)使用 typeof 運(yùn)算符時(shí),它表現(xiàn)的就像 bug 一樣:

typeof null === "object"; // true

如果它返回的是 "null" 的話,那可真是件好事,可惜的是,這個(gè) bug 已經(jīng)存在了 20 年,而且由于有太多的 web 程序依賴這一 bug 運(yùn)行,修復(fù)這一 bug 的話,將會創(chuàng)造更多的 bug,并且使很多 web 應(yīng)用無法運(yùn)行,所以估計(jì)將來也不會修復(fù)。

如果你想要確定一個(gè) null 類型的值是這一類型,你需要使用復(fù)合判定:

var a = null;

(!a && typeof a === "object"); // true

null 是基本類型中唯一值表現(xiàn)的像 false 一樣的類型(詳見第四章),但如果運(yùn)行 typeof 進(jìn)行檢查,返回的還是 "object"。

那么,typeof 返回的第七種字符串類型的值是什么?

typeof function a(){ /* .. */ } === "function"; // true

單拍腦袋想的話,很容易理解 function(函數(shù))會是 JS 中頂級的內(nèi)建類型,尤其是它針對 typeof 運(yùn)算符的表現(xiàn)。然而,如果你閱讀相關(guān)的標(biāo)準(zhǔn),會發(fā)現(xiàn)它實(shí)際上是對象類型(object)的子類型。更確切的說,函數(shù)是一種“可以被調(diào)用的對象”——一類擁有名為 [[Call]] 的內(nèi)建屬性且可以被調(diào)用的對象。

函數(shù)實(shí)際上是對象這點(diǎn)其實(shí)很有用。最重要的一點(diǎn)就是,它可以有屬性。例如:

function a(b,c) {
    /* .. */
}

該函數(shù)具有一個(gè) length 屬性,值為函數(shù)形式參數(shù)的個(gè)數(shù)。

a.length; // 2

本例中,函數(shù)聲明中包括兩個(gè)形參(bc),所以“函數(shù)的長度”是 2。

那么數(shù)組呢?他們也是 JS 內(nèi)置的類型,會不會有什么特殊的表現(xiàn)?

typeof [1,2,3] === "object"; // true

然而并沒有,只是普通的對象罷了。一般將它們也視為對象的“子類型”(詳見第三章),與普通對象不同的是,它們可以通過數(shù)字來序列化(就像普通對象那樣可以通過字符串類型的 key(鍵)來序列化一樣),并且操作有可以自動更新的 length 屬性。

值和類型

在 JavaScript 中,變量不具有類型——值有類型。變量可以在任何時(shí)刻保存任何值。

換句話說,JS 并不是強(qiáng)類型的語言,編譯引擎不會讓一個(gè)變量始終保存和這個(gè)變量最開始所保存的值擁有相同的類型。變量可以保存一個(gè) string 類型的值,并在接下來的賦值操作中保存一個(gè)number類型,以此類推。

一個(gè)42number 類型的,而且這個(gè)類型是不能改變的。另一個(gè)值,如 "42"string 類型,可以通過對 number 類型的 42 進(jìn)行類型轉(zhuǎn)換(詳見第四章)來得到。

如果你用 typeof 運(yùn)算符去操作一個(gè)變量,看上去就像是在求“變量是什么類型?”,然而 JS 中的變量并不具有類型。所以,其實(shí)是在求“變量中保存的值是什么類型?”。

var a = 42;
typeof a; // "number"

a = true;
typeof a; // "boolean"

typeof 運(yùn)算符返回的必然是字符串類型:

typeof typeof 42; // "string"

其中typeof 42會返回"number",然后typeof "number"就會返回"string"。

undefined vs "undeclared"(未定義和未聲明)

當(dāng)變量沒有被賦值的時(shí)候,其值為 undefined。調(diào)用 typeof 運(yùn)算符對它進(jìn)行操作會返回 "undefined"

var a;

typeof a; // "undefined"

var b = 42;
var c;

// 然后另
b = c;

typeof b; // "undefined"
typeof c; // "undefined"

對于許多開發(fā)者都認(rèn)為“未定義(undefined)”相當(dāng)于是“未聲明”的代名詞,然而在 JS 中,這兩個(gè)概念截然不同。

一個(gè)“未定義(undefined)”的變量是已經(jīng)在當(dāng)前作用域中聲明了的,只不過是目前它并沒有保存其他的值而已。而“未聲明(undeclared)”則是指在當(dāng)前作用域中沒有聲明的變量。

考慮如下的示例:

var a;

a; // undefined
b; // ReferenceError: b is not defined(錯誤的中文大意是:引用錯誤:b 尚未定義)

瀏覽器對于這一錯誤的描述可以說相當(dāng)讓人困惑?!癰 尚未定義”很容易讓人理解成“b 是未定義”。然后,“未定義”和“尚未定義”間的差別實(shí)在是太大了。如果瀏覽器要是能報(bào)個(gè)像“未找到變量 b”或是“b 尚未聲明”之類的錯誤,就不會這么讓人迷糊了。

同樣的,typeof 運(yùn)算符的特殊行為加重了這一困惑,請看例子:

var a;

typeof a; // "undefined"

typeof b; // "undefined"

對于“未聲明”或著說“尚未定義”的變量,typeof 會返回 "undefined"。你會發(fā)現(xiàn),雖然 b 是一個(gè)沒有聲明的變量,但是當(dāng)我們執(zhí)行 typeof b 的時(shí)候卻沒有報(bào)錯。會出現(xiàn)這種情況,源于 typeof 運(yùn)算符特殊的安全機(jī)制。

和前面的例子一樣,如果對于沒有聲明的變量,typeof 會返回一個(gè)“未聲明”之類的東西,而不是將其和“undefined”混為一談的話,就不會有這么多麻煩了。

typeof 對處理未聲明的處理

然而,在瀏覽器端這種,多個(gè)腳本文件均可以在全局命名空間下加載變量的 JavaScript 環(huán)境中,這種安全機(jī)制反而很有用。

提示:許多開發(fā)者堅(jiān)信,在全局命名空間下不應(yīng)該有任何變量,所有的東西都應(yīng)該在模塊或者是私有/分離的命名空間中。理論上,這很棒,而且確實(shí)是我們追求的一個(gè)目標(biāo),然而在實(shí)踐中,這幾乎是不可能的。不過 ES6 中加入了對模塊的支持,這使得我們能夠更接近這一目標(biāo)。

例如,在你的程序中,你通過一個(gè)全局變量 DEBUG 實(shí)現(xiàn)了一個(gè)調(diào)試模式。你希望在開始進(jìn)行 debug,如在控制臺輸出一條調(diào)試信息之前,檢查這個(gè)變量是否已經(jīng)聲明。你可以將全局的 var DEBUG = true 聲明寫在一個(gè)名為"debug.js"的文件夾下,當(dāng)你在進(jìn)行開發(fā)/測試下才在瀏覽器中引入,而不是在生產(chǎn)環(huán)境。

而你需要注意的,就是如何去在你的其他代碼中檢查這個(gè)全局的 DEBUG 變量,畢竟你可不希望報(bào)一個(gè) ReferenceError。在這種場景下,typeof 運(yùn)算符就成了我們的好幫手。

// 注意,這種方法會報(bào)錯!
if (DEBUG) {
    console.log( "Debugging is starting" );
}

// 更為安全的檢查方式
if (typeof DEBUG !== "undefined") {
    console.log( "Debugging is starting" );
}

這類檢查不僅對于用戶定義的變量很有用,當(dāng)你在見此一個(gè)內(nèi)建的 API 的時(shí)候,這種不會拋出錯誤的檢查也非常棒:

if (typeof atob === "undefined") {
    atob = function() { /*..*/ };
}

提示:當(dāng)你在對一個(gè)目前不存在的特性寫“polyfill(膩?zhàn)幽_本)”的時(shí)候,你需要避免用 var 來聲明變量 atob。如果你在 if 語句里面使用 var atob 來聲明,即使 if 語句的條件不滿足,變量的聲明也會被提升到作用域的最頂級(詳見本系列中的《作用域和閉包》)。在部分瀏覽器中,對一些特殊的全局的內(nèi)建對象類型(常稱為“宿主對象”,如瀏覽器中的 DOM 對象),這種重復(fù)的聲明會報(bào)錯。所以最好避免使用 var 來阻止變量提升。

另一種不使用 typeof 安全機(jī)制,進(jìn)行檢查的方法,就是利用所有的全局變量都是(global)全局對象(在瀏覽器中就是 window 對象)這一點(diǎn)。所以,上面的檢查還有如下等價(jià)的寫法(同樣很安全):

if (window.DEBUG) {
    // ..
}

if (!window.atob) {
    // ..
}

和引用一個(gè)未聲明的變量不同,當(dāng)你嘗試獲取一個(gè)對象(即便是 window 對象)不存在的屬性的時(shí)候,并不會拋出什么 ReferenceError。

而另一方面,一些開發(fā)者極力避免使用 window 對象來引用全局變量,尤其是當(dāng)你的代碼運(yùn)行在多種 JS 環(huán)境(不光是瀏覽器,比如服務(wù)端的 node.js)時(shí),全局(global)對象可不一定叫 window。

即便當(dāng)你不使用全局變量的時(shí)候,typeof 的安全機(jī)制也有它的用武之地,雖然這種情況很少見,也有一些開發(fā)人員認(rèn)為這種設(shè)計(jì)并不值得。比如你準(zhǔn)備寫一個(gè)可供他人復(fù)制粘貼的通用函數(shù),想要知道程序中是否定義了某一特定的變量(將會影響你函數(shù)的執(zhí)行),你可以這樣:

function doSomethingCool() {
    var helper =
        (typeof FeatureXYZ !== "undefined") ?
        FeatureXYZ :
        function() { /*.. 默認(rèn)值 ..*/ };

    var val = helper();
    // ..
}

doSomethingCool() 會檢查是否存在一個(gè)名為 FeatureXYZ 的變量,有的話就使用,沒有的話,就使用默認(rèn)值?,F(xiàn)在,如果有人在他的程序/模塊中使用了這一公共函數(shù),檢查它們是否定義了 FeatureXYZ 就顯得尤為重要:

// IIFE (詳見本系列《作用域和閉包》一書中的立即執(zhí)行函數(shù)表達(dá)式)
(function(){
    function FeatureXYZ() { /*.. my XYZ feature ..*/ }

    // include `doSomethingCool(..)`
    function doSomethingCool() {
        var helper =
            (typeof FeatureXYZ !== "undefined") ?
            FeatureXYZ :
            function() { /*.. default feature ..*/ };

        var val = helper();
        // ..
    }

    doSomethingCool();
})();

在這里,FeatureXYZ 并不是一個(gè)全局變量,但我們?nèi)匀皇褂?typeof 運(yùn)算符的安全機(jī)制來檢查。注意到,在這種情況下,我們可沒有全局對象用于這一檢查(像使用 window.___ 那樣),所以 typeof 真的很有幫助。

有些開發(fā)者可能會喜歡一種叫做“依賴注入”的設(shè)計(jì)模式,讓 doSomethingCool() 不去檢查 FeatureXYZ 是否在它外部/附近被定義,而是通過顯示的判斷來確定,如:

function doSomethingCool(FeatureXYZ) {
    var helper = FeatureXYZ ||
        function() { /*.. 默認(rèn)值 ..*/ };

    var val = helper();
    // ..
}

要實(shí)現(xiàn)這一功能,其實(shí)有很多解決方案。沒有一種模式是“對的”或“錯的”——要對各種方法進(jìn)行權(quán)衡。不過總的來說,typeof 的安全機(jī)制確實(shí)給了我們更多的選擇。

總結(jié)

JavaScript 擁有七種內(nèi)建類型:null,undefined,booleannumber,stringobject,symbol??梢酝ㄟ^使用 typeof 運(yùn)算符來對它們進(jìn)行區(qū)分。

變量不具有類型,但值有。這些類型定義了值的行為。

許多開發(fā)者會將“未定義(undefined)”和“未聲明”混為一談,但是在 JavaScript 它們完全不同。undefined是一個(gè)可供已經(jīng)聲明的變量保存的值?!拔绰暶鳌币馕吨粋€(gè)未經(jīng)聲明的變量。

不幸的是,JavaScript 中很多地方都將兩者混為一談,比如錯誤信息("ReferenceError: a is not defined"),以及用 typeof 操作,兩者都返回 "undefined"。

不過,typeof 這種安全機(jī)制(阻止報(bào)錯)在某些場景中,如需要檢查一個(gè)變量是否存在的時(shí)候還是很有用的。

原書 《You Don"t Know JS: Types & Grammar》
本章原文 Chapter 1: Types

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

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

相關(guān)文章

  • 重讀你不知道JS (上) 第一節(jié)一章

    摘要:的抽象語法樹中可能會有一個(gè)叫作的頂級節(jié)點(diǎn),接下來是一個(gè)叫作它的值是的子節(jié)點(diǎn),以及一個(gè)叫作的子節(jié)點(diǎn)。值得注意的是,是非常重要的異常類型。嚴(yán)格模式下,未聲明的和倆者行為相同,都會是。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復(fù)雜微妙技術(shù)的語言,即使是經(jīng)驗(yàn)豐富的 JavaScript 開發(fā)者,如果...

    lk20150415 評論0 收藏0
  • 十分鐘快速了解《你不知道 JavaScript》(上卷)

    摘要:最近剛剛看完了你不知道的上卷,對有了更進(jìn)一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對象原型。附錄詞法這一章并沒有說明機(jī)制,只是介紹了中的箭頭函數(shù)引入的行為詞法。第章混合對象類類理論類的機(jī)制類的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對 JavaScript 有了更進(jìn)一步的了解。 《你不知道的 JavaScript》上卷由兩部...

    趙春朋 評論0 收藏0
  • 精讀《你不知道javascript(中卷)》

    摘要:強(qiáng)制類型轉(zhuǎn)換本章介紹了的數(shù)據(jù)類型之間的轉(zhuǎn)換即強(qiáng)制類型轉(zhuǎn)換包括顯式和隱式。強(qiáng)制類型轉(zhuǎn)換常常為人詬病但實(shí)際上很多時(shí)候它們是非常有用的。隱式強(qiáng)制類型轉(zhuǎn)換則沒有那么明顯是其他操作的副作用。在處理強(qiáng)制類型轉(zhuǎn)換的時(shí)候要十分小心尤其是隱式強(qiáng)制類型轉(zhuǎn)換。 前言 《你不知道的 javascript》是一個(gè)前端學(xué)習(xí)必讀的系列,讓不求甚解的JavaScript開發(fā)者迎難而上,深入語言內(nèi)部,弄清楚JavaSc...

    李世贊 評論0 收藏0
  • 你不知道JavaScript(ES6與之未來)

    摘要:然而,臨近規(guī)范發(fā)布時(shí),有建議提及未來的版本號切換為編年制,比如用同來指代在年末前被定稿的所有版本??偟脕碚f就是版本號不再那么重要了,開始變得更像一個(gè)萬古長青的活標(biāo)準(zhǔn)。 你不知道的JS(下卷)ES6與之未來 第一章:ES的今與明 在你想深入這本書之前,你應(yīng)該對(在讀此書時(shí))JavaScript的最近標(biāo)準(zhǔn)掌握熟練,也就是ES5(專業(yè)來說是ES 5.1)。在此,我們決定全方面地談?wù)撽P(guān)于將近的...

    Julylovin 評論0 收藏0
  • 你不知道JavaScript》 (中) 閱讀摘要

    摘要:這時(shí)候控制臺看到的是對象的快照,然而點(diǎn)開看詳情的話是這段代碼在運(yùn)行的時(shí)候,瀏覽器可能會認(rèn)為需要把控制臺延遲到后臺,這種情況下,等到瀏覽器控制臺輸出對象內(nèi)容時(shí),可能已經(jīng)運(yùn)行,因此會在點(diǎn)開的時(shí)候顯示,這是的異步化造成的。 本書屬于基礎(chǔ)類書籍,會有比較多的基礎(chǔ)知識,所以這里僅記錄平常不怎么容易注意到的知識點(diǎn),不會全記,供大家和自己翻閱; 上中下三本的讀書筆記: 《你不知道的JavaScri...

    stackvoid 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<