前言:
對于程序員,學(xué)習(xí)是無止境的,知識淘換非???能夠快速穩(wěn)固掌握一門新技術(shù),是一個程序員應(yīng)該具備的素質(zhì).這里將分享本人一點點不成熟的心得.
了解一門語言,了解它的概念非常重要,但是一些優(yōu)秀的設(shè)計思想需要細(xì)心和大量實踐才能慢慢參悟,在這之前需要做的是能夠運用它來開發(fā),那么了解一些基礎(chǔ)特性非常有必要,通常這些特性是需要經(jīng)驗積累,從各種坑中累計出來,但是還有一種看似很笨卻很有效的學(xué)習(xí)方法.那就是將別人的經(jīng)驗記錄下來,有事沒事都拿出來看看,集合開發(fā)中的經(jīng)驗,這會非常有效.
調(diào)試工具 firebug
需要升級的知識點 《ECMAScript 6 入門》
詞法結(jié)構(gòu)
- 編程語言的詞法結(jié)構(gòu)是一套基礎(chǔ)性規(guī)則,用來描述如何使用這門語言的編寫程序。
- 字符集:
- JavaScript程序是用Unicode字符集編寫的。Unicode是ASCII和Latin-1的超集,并支持地球上幾乎所有在用的語言
- 區(qū)分大小寫
- 空格、換行符和格式控制符
- JavaScript會忽略程序中標(biāo)識之間的空格
- 注釋
- 第一種注釋,在行尾“//”之后的文本都會被JavaScript當(dāng)作注釋忽略掉的
- 第二種注釋,"/"和"/"之間的本文都會被當(dāng)作注釋
- 直接量
- 就是程序中直接使用的數(shù)據(jù)值“12”//數(shù)字true//布爾值等等
- 標(biāo)識符和保留字
- 標(biāo)識符就是一個名字。在JS中,標(biāo)識符用來對變量和函數(shù)名進(jìn)行命名,或用作JS代碼中某些循環(huán)語句中的跳轉(zhuǎn)位置的標(biāo)記。
- 標(biāo)識符必須以字母、下劃線、美元符開始
- 保留字就是JS把一些標(biāo)識符拿出來用作自己的關(guān)鍵字,因此,就不能再程序中把這些關(guān)鍵字用作標(biāo)識符了
- 可選的分號
- 缺少分隔符,一條語句結(jié)束就成了下一條語句的開始
- 在JS中,如果語句各自獨占一行,通常可以省略語句之間的分號(“}”也可以省略),JS會在換行處自動填補分號,但并不是所有換行出都會自動填補,只有在可以解析的情況下才會填補
類型、值和變量
- 在編程語言中,能夠表示并操作的值的類型稱做數(shù)據(jù)類型,編程語言最基本的特性就是能夠支持多種數(shù)據(jù)類型。
- 當(dāng)程序需要將值保存起來以備將來使用時,便將其賦值給一個變量
- 變量是一個值的符號名稱,可以通過名稱來獲得對值的引用。變量的工作機制是編程語言的另一個基本特性
- JS的數(shù)據(jù)類型分為兩類
- 原始數(shù)據(jù)(primitive type)類型,包括數(shù)字、字符串和布爾值
- 對象(object type)類型,JS中除了數(shù)字、字符串、布爾值、Null、Undefined之外的就是對象了
- 對象(object)是屬性(property)的集合,每個屬性都由“名/值對”
- JS定義了一種特殊的對象——數(shù)組(array)
- JS定義了一種特殊的對象——函數(shù)
- 數(shù)字
- JS不區(qū)分整數(shù)值和浮點數(shù)值,JS中所有數(shù)字均用浮點數(shù)值表示
- 當(dāng)一個數(shù)字直接出現(xiàn)在程序中,我們稱之為數(shù)字直接量
- JS支持多種格式的數(shù)字直接量
- 十進(jìn)制
- 十六進(jìn)制
- 數(shù)組下標(biāo)的32位整數(shù)
- 浮點型直接量
- JS中的算術(shù)運算
- JS中的算術(shù)運算在溢出、下溢或被零整除時不會報錯。當(dāng)數(shù)字運算結(jié)果超過了JS所能表示的數(shù)字上限,結(jié)果為一個特殊的無窮大值,JS中以Infinity表示
- 下溢是當(dāng)運算結(jié)果無限接近于零并比JS能表達(dá)的最小值還小的時候,JS將返回0
- 從技術(shù)上講,只有JS對象才能擁有方法。然而數(shù)字、字符串和布爾值也可以擁有自己的方法(3.6節(jié)進(jìn)行講解)
- 原始類型/對象類型
- 可變類型/不可變類型
- 可變類型:值是可以修改的,數(shù)組與對象就是可變類型
- 不可變類型:數(shù)字、字符串、布爾值、NULL和Undefined——比如,修改一個數(shù)值的內(nèi)容本身就說不通
- JS可以自由地進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換。比如,程序期望使用字符串的地方使用了數(shù)字,JS會自動將數(shù)字轉(zhuǎn)換為字符串,使用布爾值的地方使用非布爾值,也會進(jìn)行自動轉(zhuǎn)換
- JS中靈活的類型轉(zhuǎn)換規(guī)則對“判斷相等”的定義有影響。等號運算符“==”
- JS變量是無類型的,變量可被賦值任何類型,同樣一個變量也可重新賦予不同類型的值
- 詞法作用域
- 日期和時間
- 字符串
- 字符串是一組由16位值組成的不可變的有序序列,每個字符串通常來自于Unicode字符集
- JS定義的各式字符串操作方法均作用于16位值
- JS中字符串是不可變類型,JS中的字符串是固定不變的,類似replace()的方法都返回新的字符串,原始字符串本身并沒發(fā)生改變
- 字符串直接量
- 轉(zhuǎn)義字符
- JS字符串中反斜線(\)有著特殊的用途,反斜線符號后加一個字符,就不再表示它們字面含義了,比如,\n就是一個轉(zhuǎn)義字符,它表示換行符
- \'轉(zhuǎn)義符,表示單引號
- 字符串的使用
- JS的內(nèi)置功能之一就是字符串連接。字符串使用加(+)號連接,表示兩數(shù)相連
- 匹配模式(正則表達(dá)式)
- 布爾值
- 布爾值指代真或假、開或關(guān)、是或否。這個類型只有兩個值,保留字true和false
- 程序中的比較語句的結(jié)果通常都是布爾值
- 布爾值通常用于JS中的控制結(jié)構(gòu)中
- 任意JS的值都可以轉(zhuǎn)換為布爾值。(undefined、null、0、-0、NaN、“”//空字符串)這些值都會被轉(zhuǎn)換成false。所有其他的值,包括所有對象(數(shù)組)都會轉(zhuǎn)換成true??梢赞D(zhuǎn)換為false的值有時稱做“假值”,反之稱為“真值”
- 布爾值包含toString()方法,這個不重要的API可以將布爾值轉(zhuǎn)換為字符串
- “&&”運算符執(zhí)行了邏輯與(AND)操作。當(dāng)且僅當(dāng)兩個操作數(shù)都是真值時才返回true
- “||”運算符是布爾或(OR)操作
- “!”一元操作符執(zhí)行了布爾非(NOT)操作
- null和undefined
- null是JS語言的關(guān)鍵字,表示一個特殊值,用來描述“空值”。對null執(zhí)行typeof預(yù)算,結(jié)果返回字符串“object”,也就是說,可以將null認(rèn)為是一個特殊的對象值,含義是“非對象”。通常認(rèn)為null是它自有類型的唯一一個成員,它可以表示數(shù)字、字符串和對象是“無值”的。
- undefined不是JS語言的關(guān)鍵字,它與null一樣表示空缺。用未定義的值表示更深層次的“空值”。它是變量的一種取值,表明變量沒有初始化。typeof運算符得到undefined的類型,則返回“undefined”,表明這個值是這個類型的唯一成員
- null與undefined是不同的,但是它們都是表示“值的空缺”,兩者往往可以互換。判斷相等運算符“==”認(rèn)為兩者是相等的(喲啊使用嚴(yán)格相等運算符“===”來區(qū)分它們)。它們都不包括任何屬性和方法。使用”.“和”[]“來存取這兩個值的成員或方法都會產(chǎn)生一個類型錯誤
- 或許可以認(rèn)為undefined是系統(tǒng)級的,出乎意料的或類似錯誤的值的空缺,而null是表示程序集的、正常的或在意料之中的值的空缺。如果對他們進(jìn)行操作,賦值給變量或者屬性,或作為參數(shù)傳入函數(shù),最佳選擇是使用null
- 全局對象
- 當(dāng)JS解釋器啟動時或者在任何Web瀏覽器加載新頁面的時候,它將創(chuàng)建一個新的全局對象,并給它一組定義的初始屬性
- 全局屬性,比如undefined、Infinity和NaN
- 全局函數(shù),比如isNaN()、parseInt()
- 構(gòu)造函數(shù),比如Date()、RegExp()、String()、Object()和Array()
- 全局對象,比如Math和JSON
- 全局對象的初始屬性并不是保留字,但它們應(yīng)該當(dāng)作保留字來對待
- 客戶端JS來講,Windows對象定義了一些額外的全局屬性
- 在代碼的最頂級——不再任何函數(shù)內(nèi)的JS代碼——可以使用JS關(guān)鍵字this來引用全局對象
- 在客戶端JS中,在其表示的瀏覽器窗口中的所有JS代碼中,Window對象充當(dāng)了全局對象。
- 包裝對象
- JS對象是一種復(fù)合值,它是屬性或已命名值的集合。通過”.”符號來引用屬性值。當(dāng)屬性值是一個函數(shù)的時候,稱其為方法。通過o.m()來調(diào)用對象o中的方法
- 字符串也同樣具有屬性和方法,字符串不是對象,但是有屬性。只要引用了字符串的屬性,JS就會將字符串s值通過調(diào)用new String(s)的方式轉(zhuǎn)換成對象,這個對象繼承了字符串的方法,并被用來處理屬性的引用。一旦屬性引用結(jié)束,這個新創(chuàng)建的對象就會銷毀。
- 同字符串一樣,數(shù)字和布爾值也具有各自的方法:通過Number()和Boolean()構(gòu)造函數(shù)創(chuàng)建一個臨時對象。null和undefined沒有包裝對象,訪問它們的屬性會造成一個類型錯誤
- “==”等于運算符將原始值和其包裝對象視為相等,當(dāng)“===”全等運算符將它們視為不相等,使用typeof運算符可以看到原始值和其包裝對象的不同
- 不可變的原始值和可變的對象引用
- JS中的原始值(undefined、null、布爾值、數(shù)字和字符串)與對象(包括數(shù)組和函數(shù))有著本質(zhì)的區(qū)別。
- 原始值是不可更改的,任何方法都無法更改一個原始值
- 對數(shù)字和布爾值來說改變數(shù)字的值本身就說不通,對字符串來說,不那么明顯,看起來字符串組成像是對各字符的數(shù)組,我們期望通過制定索引下標(biāo)來修改字符串中的字符。實際上JS是禁止這樣做的,字符串所有方法看上去返回了一個修改后的字符串,實際上返回的是一個新的字符串值
- 原始值的比較是值的比較,只有在它們的值相等時它們才會相等
- 如果比較兩個單獨的字符串,當(dāng)且僅當(dāng)它們的長度相等且每個索引的字符都相等時,JS才認(rèn)為他們相等
- 對象和原始值不同,它們是可變的——它們的值也是可修改的
- 對象的比較并非值的比較,即使兩個對象包含同樣的屬性及相同的值,它們也是不相等的,各個索引元素完全相等的兩個數(shù)組也不相等
- 通常稱對象為引用類型,以此來和JS基本類型區(qū)分開
- 對象值都是引用,對象的比較是引用的比較
- 當(dāng)且僅當(dāng)它們引用同一個基對象時,它們才相等
- 將數(shù)組或?qū)ο筚x值給一個變量,僅僅是賦值的引用,對象本身并沒有復(fù)制一次
- 類型轉(zhuǎn)換
- JS取值非常靈活,從布爾值可以看出,當(dāng)JS期望使用一個布爾值的時候,可以提供任意類型值,JS將根據(jù)需要自行轉(zhuǎn)換類型
- 顯示類型轉(zhuǎn)換
- JS可以自動做許多類型轉(zhuǎn)換,但為了代碼變得清晰易讀而做的顯示轉(zhuǎn)換
- 顯示類轉(zhuǎn)換最簡單的方法使用Boolean()、Number()、String()或Object()函數(shù)
- 對象轉(zhuǎn)換為原始值
- 所有對象繼承了兩個轉(zhuǎn)換方法。
- toString()
- 第一個是toString(),它的作用是返回一個反映這個對象的字符串
- 很多類定義了更多特定版本的toString()
- 數(shù)組類的toString()方法,將每個數(shù)組元素轉(zhuǎn)換為一個字符串,并在元素之間添加都好后合并成結(jié)果字符串
- 函數(shù)類的toString()方法,返回這個函數(shù)的實現(xiàn)定義的表示方式,通常是將用戶定義的函數(shù)轉(zhuǎn)換為JS源代碼字符串
- 日期類的toString()方法,返回一個可讀的日期和時間字符串
- RegExp類的toString()方法,將RegExp對象轉(zhuǎn)換為表示正則表達(dá)式直接量的字符串
- valueOf()
- 這個方法任務(wù)并未詳細(xì)定義,如果存在任意原始值,它就默認(rèn)將對象轉(zhuǎn)換為表示它的原始值
- 對象是復(fù)合值,而且大多數(shù)對象無法真正表示為一個原始值,因此簡單的valueOf()方法簡單的返回對象本身,而不是返回一個原始值
- 重復(fù)聲明與遺漏聲明
- 使用var語句重復(fù)聲明變量是合法且無害的。如果重復(fù)聲明帶有初始化器,那么這就跟一條簡單的賦值語句沒什么兩樣
- 如果試圖讀取一個沒有聲明的變量值JS會報錯
- 給一個沒有聲明的變量賦值也會報錯
- 變量作用域
- 變量的作用域是程序源代碼中定義這個變量的區(qū)域
- 全局變量擁有全局作用域
- 函數(shù)體內(nèi)聲明的變量作用域是局部性的,它們只在函數(shù)體內(nèi)有定義
- 函數(shù)作用域和聲明提前
- JS沒有塊級作用域,JS取而代之的使用了函數(shù)作用域
- JS的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終可見,意味著變量在聲明之前已經(jīng)可用,JS的這個特性被非正式的成為聲明提前,即JS函數(shù)里聲明的所有變量(但不涉及賦值)都被“提前”至函數(shù)體的頂部
- 作為屬性的變量
- 當(dāng)聲明一個JS全局變量時,實際上是定義了全局對象的一個屬性
- 當(dāng)使用var聲明一個變量時,創(chuàng)建的這個屬性是不可配置的,也就是說這個變量無法通過delete運算符刪除
- JS全局變量是全局對象的屬性,這是ECMASscript規(guī)范中強制規(guī)定的,對于局部變量則沒有如此規(guī)定
- ECMAScript 5 規(guī)范稱“聲明上下文對象”,JS可以允許使用this關(guān)鍵字來引用全局對象,卻沒有方法可以引用局部變量中存放的對象。這種存放局部變量的對象的特有性質(zhì),是一種對我們不可見的內(nèi)部實現(xiàn)。
- 作用域鏈(未完全理解)
- JS是基于詞法作用域的語言:通過閱讀包含變量定義在內(nèi)的數(shù)行源碼就能知道變量的作用域。
- 全局變量在程序中始終都是有定義的
- 局部變量在聲明它的函數(shù)體內(nèi)以及其所嵌套的函數(shù)內(nèi)始終是有定義的
- /*
- 如果將一個局部變量看做是自定義實現(xiàn)的對象的屬性的話,那么可以換個角度來解讀變量作用域。
- 每一段JS代碼(全局代碼或函數(shù))都有一個與之關(guān)聯(lián)的作用域鏈。
- 這個作用域鏈?zhǔn)且粋€對象列表或者鏈表,這組對象定義了這段代碼“作用域中”的變量。
- 當(dāng)JS需要查找變量x的值的時候(這個過程稱做變量解析),它會從鏈接中的第一個對象開始查找,如果這個對象有名為x的屬性,則會直接使用這個屬性的值,如果第一個對象中不存在名為x的屬性,JS會繼續(xù)查找鏈接的下一個對象。
- 如果第二個對象依然沒有名為x的屬性,則會繼續(xù)查找下一個對象,以此類推
- 如果作用域鏈就上沒有任何一個對象含有屬性x,那么就認(rèn)為這段代碼的作用域鏈接上不存在x,并最終拋出一個引用錯誤異常
- */
- /*
- 在JS的最頂層代碼中(也就是不包含在任何函數(shù)定義的代碼),作用域鏈由一個全局對象組成
- 在不包含嵌套的函數(shù)體內(nèi),作用域鏈上有兩個對象,第一個是定義函數(shù)參數(shù)和局部變量的對象,第二個是全局對象
- 在一個嵌套的函數(shù)體內(nèi),作用域鏈上至少有三個對象
- 理解對象鏈的創(chuàng)建規(guī)則是非常重要的
- 當(dāng)定義一個函數(shù)時,它實際上保存一個作用域鏈。
- 當(dāng)調(diào)用這個函數(shù)時,它創(chuàng)建一個新的對象來存儲它的局部變量,并將這個對象添加至保存的那個作用域鏈上,同時創(chuàng)建一個新的更長的表示函數(shù)調(diào)用作用域的“鏈”
- 對于嵌套函數(shù)來講,每次調(diào)用外部函數(shù)時,內(nèi)部函數(shù)又會重新定義一遍。因為每次調(diào)用外部函數(shù)的時候,作用域鏈都是不同的
- 內(nèi)部函數(shù)在每次定義的時候都有微妙的差別,在每次調(diào)用外部函數(shù)的時候,每部函數(shù)的代碼都是相同的,而且關(guān)聯(lián)這段代碼的作用域也不相同
表達(dá)式和運算符
- 表達(dá)式JS中的一個短語,JS解釋器會將其計算出一個結(jié)果
- 常量、變量名都是一種簡單的表達(dá)式
- 復(fù)雜表達(dá)式是由簡單表達(dá)式組成的
- 簡單表達(dá)式組合成復(fù)雜表達(dá)式最常用的方法就是使用運算符。根據(jù)運算符規(guī)則返回一個值
- 原始表達(dá)式
- 最簡單的表達(dá)式是“原始表達(dá)式”
- 原始表達(dá)式是表達(dá)式的最小單位,它們不再包含其他表達(dá)式
- JS原始表達(dá)式包含常量、關(guān)鍵字、變量
- 對象和數(shù)組的初始化表達(dá)式
- 函數(shù)定義表達(dá)式
- 屬性訪問表達(dá)式
- 調(diào)用表達(dá)式
- 對象創(chuàng)建表達(dá)式
- 省略部分。。。。。。
語句
- 表達(dá)式在JS中是短語,那么語句就是JS整句或命令
- 語句塊的結(jié)尾不需要分號。塊中的原始語句必須以分號結(jié)束,但語句塊不需要
- 語句塊中的縮進(jìn),這不是必須的,但能增強代碼的可閱讀性
- JS中沒有塊級作用域,在語句塊中聲明的變量并不是語句私有的
對象
- 對象是JS的基本數(shù)據(jù)類型
- 對象是一種復(fù)合值
- 對象也可看做是屬性的無序集合,每個屬性都是一個名/值對
- 屬性名是字符串,因此我們可以把對象看成是對字符串到值的映射
- 這種基本數(shù)據(jù)類型還有很多叫法,有些我們已然非常熟悉,比如散列、散列表、字典、關(guān)聯(lián)數(shù)組
- 然而對象不僅僅是字符串到值的映射,除了可以保持自有的屬性,JS對象還可以從一個稱為原型的對象繼承屬性
- 對象的方法通常是繼承的屬性,這種“原型式繼承”是JS的核心特征
- JS對象是動態(tài)的可以增刪屬性
- 除了字符串、數(shù)字、true、false、unll、undefined之外,JS中的值都是對象
- 對象最常見的用法是創(chuàng)建、設(shè)置、查找、刪除、檢測、枚舉它的屬性
- 屬性包括名字和值
- 屬性名可以是包含空字符串在內(nèi)的任意字符串
- 對象中不能存在兩個同名的屬性
- 值可以是任意JS值,或者(在ECMASscript5中)可以是一個getter或setter函數(shù)
- 除了名字和值之外,每個屬性還有一些與之相關(guān)的值,稱為“屬性特性”
- 屬性特性
- 可寫,表明是否餓可以設(shè)置該屬性的值
- 可枚舉,表明是否可以通過for/in循環(huán)返回該屬性
- 可配置,表明是否可以刪除或修改該屬性
- 對象特性
- 對象的原型,指向另為一個對象,本對象的屬性繼承自它的原型對象
- 對象的類,是一個標(biāo)識對象類型的字符串
- 對象的擴展標(biāo)記,指明了(在ECMAScript 5中)是否可以向該對象添加新屬性
- 三類JS對象的兩類屬性作區(qū)分
- 內(nèi)置對象,是由ECMAScript規(guī)范定義的對象或類。例如數(shù)組、函數(shù)、日期、增則表達(dá)式
- 宿主對象,是由JS解釋器所嵌入的宿主環(huán)境(比如Web瀏覽器)定義的
- 自定義對象,是由運行中的JS代碼創(chuàng)建的對象
- 自有屬性,是直接在對象中定義的屬性
- 繼承屬性,是在對象的原型對象中定義的屬性
- 創(chuàng)建對象
- 對象直接量
- 關(guān)鍵字new創(chuàng)建
- Object.create()函數(shù)創(chuàng)建
- 對象直接量
- 創(chuàng)建對象直接量最簡單的方式就是在JS代碼中使用對象直接量
- 對象直接量是由若干名/值對組成的映射表
- 屬性名可以是JS標(biāo)識符也可以是字符串直接量(包括空字符串)
- 對象之間量是一個表達(dá)式,這個表達(dá)式的每次運算都創(chuàng)建并初始化一個新的對象
- 每次計算對象之間量的時候,也都會計算它的每個屬性值
- 重復(fù)調(diào)用的函數(shù)中的循環(huán)體內(nèi)使用了對象直接量,它將創(chuàng)建很多新對象,并且每次創(chuàng)建的對象的屬性值也有可能不同
- 通過new創(chuàng)建對象
- new運算符創(chuàng)建并初始化一個新對象
- 關(guān)鍵字new后跟隨一個函數(shù)調(diào)用,這里的函數(shù)稱做構(gòu)造函數(shù)
- JS語言核心中的原始類型都包含內(nèi)置構(gòu)造函數(shù)
- 原型
- 每一個JS對象(null除外)都和另一個對象相關(guān)聯(lián),就是原型,每一個對象都從原型繼承屬性
- 所有對象直接量創(chuàng)建的對象都具有同一個原型對象,并可以通過JS代碼Object.prototype獲得對原型對象的引用
- 通過new和構(gòu)造函數(shù)調(diào)用創(chuàng)建的對象的原型就是狗找函數(shù)的prototype屬性的值
- 沒有原型的對象為數(shù)不多,Object.prototype就是其中之一
- Object.create()
- Object.create()是一個靜態(tài)函數(shù),而不是提供給某個對象調(diào)用的方法
- 可以傳入?yún)?shù)null創(chuàng)建一個沒有原型的新對象,這種方式創(chuàng)建的對象不會繼承任何東西,甚至不包括基礎(chǔ)方法,比如toString(),也就是說它將不能和“+”運算符一起正常工作
- 屬性的查詢和設(shè)置
- 作為關(guān)聯(lián)數(shù)組的對象
- 第一種語法使用點運算符和一個標(biāo)識符運算符,這和C和Java中訪問一個結(jié)構(gòu)體或?qū)ο蟮撵o態(tài)字段非常類似
- 第二種語法使用方括號和一個字符串,看起來更像數(shù)組,這個素組元素是通過字符串索引而不是數(shù)字索引,這種數(shù)組就是關(guān)聯(lián)數(shù)組,也稱散列、映射、字典
- 繼承(未完全理解)
- JS對象具有“自有屬性”,也有一些屬性從原型對象繼承而來
- 假設(shè)o對象的屬性x賦值,如果o中已經(jīng)有屬性x(這個屬性不是繼承來的),那么這個賦值操作只會改變這個已有屬性x的值
- 如果o中不存在屬性x,那么賦值操作給o添加一個新屬性x
- 如果之前o繼承自有屬性x,那么這個繼承的屬性就被新創(chuàng)建的同名屬性覆蓋了
- 屬性賦值操作首先檢查原型鏈,以此判斷是否允許賦值操作
- 如果o繼承自一個只讀屬性x,那么賦值操作是不允許的,如果允許賦值操作,它也總是在原始對象上創(chuàng)建屬性或?qū)σ延械膶傩再x值,而不會去修改原型鏈
- 在JS中,只有在查詢屬性時才會體會到繼承的存在,而設(shè)置屬性則和繼承無關(guān),這是JS的一個重要特性,該特性讓程序員可以有選擇地覆蓋繼承的屬性
- 屬性賦值要么失敗,要么創(chuàng)建一個屬性,要么在原始對象中設(shè)置屬性,但有一個例外,如果o繼承自屬性x,而這個屬性是一個具有setter方法的accessor屬性,那么這時將調(diào)用setter方法而不是給o創(chuàng)建一個屬性x
- 需要注意的是,setter方法是由對象o調(diào)用的,而不是定義這個屬性的原型對象調(diào)用的。因此如果setter方法定義任意屬性,這個操作只是針對o本身,并不會修改原型鏈
- 屬性訪問錯誤
- 屬性訪問并不總是返回或設(shè)置一個值
- 查詢一個不存在的屬性并不會報錯,查找對象自有屬性或繼承的屬性中均為找到屬性,屬性訪問表達(dá)式返回undefined
- 如果對象不存在,那么試圖查詢這個不存在對象的屬性就會報錯,因為找到對象返回的是undefined而unll與undefind都沒有屬性
- 給unll和undefined設(shè)置屬性也會報類型錯誤
- 對象自有屬性是只讀的,不能給只讀屬性重新賦值(defineProperty()方法中有一個例外,可以對可配置的只讀屬性重新賦值)
- 對象繼承自有屬性,且它是只讀的,不同通過同名自有屬性覆蓋只讀的繼承屬性
- 免去其它不可賦值情況下,對象的可擴展性是false,那么不能定義新屬性
- 刪除屬性
- delete運算符可以刪除對象的屬性
- delete運算符只是斷開屬性和宿主對象的聯(lián)系,而不會去操作屬性中的屬性
- delete運算符只能刪除自有屬性,不能刪除繼承屬性(要刪除繼承屬性必須從定義這個屬性的原型對象上刪除它,而且這會影響到所有繼承自這個原型的對象)
- 當(dāng)刪除一個嵌套對象,由于刪除的屬性引用依然存在,可能因為這種不嚴(yán)謹(jǐn)?shù)拇a而造成內(nèi)存泄漏。所有在銷毀對象的時候,要遍歷屬性中的屬性,依次刪除
- 當(dāng)delete表達(dá)式刪除成或沒有副作用(比如刪除不存在的屬性)時,它返回true,如果delete后不是一個屬性訪問表達(dá)式(比如 delete 1),同樣返回true
- delete不能刪除那些可配置性為false的屬性(盡管可以刪除不可擴展對象的可配置屬性)。
- 檢測屬性
- in——in與那算符左側(cè)是屬性名(字符串),右側(cè)是對象。如果對象自有屬性或繼承屬性中包含這個屬性則返回true
- hasOwnProperty()——方法用來檢測給定的名字是否是對象的自有屬性。對于繼承屬性它將返回false
- propertyIsEnumerable()——是hasOwnProperty()增強版,只有檢測到是自有屬性且這個屬性的可枚舉性為true時它才返回true。通常由JS代碼創(chuàng)建的屬性都是可枚舉的,除非使用特定方法改變屬性的可枚舉性
- !==——比較值
- 有一種場景必須使用in運算符,當(dāng)對象值為undefined時
- 枚舉屬性
- 許多實用工具庫給Object.prototype添加了新的方法或?qū)傩?,這些屬性方法可以被所有對象繼承并使用
- for/in循環(huán)可以在循環(huán)體中遍歷對象中所有可枚舉的屬性(包括自有屬性和繼承的屬性),把屬性名稱賦值給循環(huán)變量。
- 對象繼承的內(nèi)置方法不可枚舉的,但在代碼中給對象添加的屬性都是可枚舉的(除非轉(zhuǎn)為成不可枚舉)
- ECMAScript 5中定義了兩個用以枚舉屬性名稱的函數(shù)Object.keys()、Object.getOwnPropertyNames()
- 屬性getter和setter
- * 屬性的特性
- 除了包含名字和值之外,屬性還包含一些標(biāo)識它們可寫、可枚舉、可配置的特性
- 可以認(rèn)為一個屬性包含一個名字和4個特性。數(shù)據(jù)屬性的4個特性分別是它的值、可寫性、可枚舉性、可配置性
- 存取屬性不具有值特性和可寫性,它們的可寫性是由setter方法存在于否決定的。因此存取器屬性的4個特性是讀取、寫入、可枚舉、可配置
- 為了實現(xiàn)屬性特性的查詢和設(shè)置操作,ECMAScript 5中定義了一個名為“屬性描述符”的對象,這個對象代表那4個特性
- 描述對象的屬性和它們所描述的屬性特性是同名的。因此,數(shù)據(jù)屬性的描述符對象的屬性有value、writable、enumerable、configurable
- 存取器屬性的描述符對象則用get、set屬性代替value和writable,其中writable、enumerable和configurable都是布爾值
- 通過調(diào)用Object.getOwnPropertyDescriptor()可以獲得某個對象特定屬性的屬性描述符
- getOwnPropertyDescriptor()只能得到自有屬性的描述符,想要得到繼承屬性的特性需要遍歷原型鏈
- 通過definePeoperty()設(shè)置屬性的特性,屬性秒速符對象不必包含所有4個特性。這個方法要么修改已有屬性要么新建自有屬性,但不能修改繼承屬性
- 如果要同時修改或創(chuàng)建多個屬性,則需要使用Object.defineProperties()
- 如果對象是不可擴展的,則可以編輯已有的自有屬性,但不能給它添加新屬性
- 如果屬性是不可配置的,則不能修改它的可配置性和可枚舉性
- 如果存取器屬性是不可配置的,則不能修改其getter和setter方法,也不能將它轉(zhuǎn)換為數(shù)據(jù)屬性
- 如果數(shù)據(jù)屬性是不可配置的,則不能將它轉(zhuǎn)換為存取器屬性
- 如果數(shù)據(jù)屬性是不可配置的,則不能將它的可寫性從false修改為true,但可以從true修改為false
- 如果數(shù)據(jù)屬性是不可配置且不可寫的,則不能修改它的值。然而可配置但不可寫屬性的值是可以修改的(實際上是先將它標(biāo)記為可寫的,然后修改它的值,最后轉(zhuǎn)換為不可寫的)
- 對象的三個屬性
- 每一個對象都有與之相關(guān)的原型、類、可擴展性
- 原型屬性
- 對象的原型屬性是用來繼承屬性的
- 原型屬性是在實例對象創(chuàng)建之初就設(shè)置好的
- 通過對象之間量創(chuàng)建的對象使用Object.prototype作為它們的原型
- 通過new構(gòu)造函數(shù)創(chuàng)建的對象使用構(gòu)造函數(shù)的prototype屬性作為它們的原型
- 通過object.create()創(chuàng)建的對象使用第一個參數(shù)(也可以是null)作為它們的原型
- 在ECMScript 5中,將對象作為參數(shù)傳入Object.getPrototypeOf()可以查詢它的原型
- 通過new表達(dá)式創(chuàng)建的對象,通常繼承一個constructor屬性,這個屬性指代創(chuàng)建這個對象的構(gòu)造函數(shù)
- 通過直接量與object.creat創(chuàng)建的對象包含一個名為constructor的屬性,這個屬性指代Object構(gòu)造函,因此,constructor.prototype才是對象直接量的真正原型,但對于object.create()創(chuàng)建的對象則往往不是這樣
- 使用isPrototypeOf()方法,檢測一個對象是否是另一個對象的原型
- isPrototypeOf()函數(shù)實現(xiàn)的功能與instanceof運算符非常類似
- _proto_,可設(shè)置對象的原型,但是應(yīng)用不廣泛,不推薦使用
- 類屬性
- 對象的類屬性是一個字符串,用以表示對象的類型信息ECMAS 3與5都未提供設(shè)置個屬性的方法,并只有一種間接方法可以查詢它。默認(rèn)的toString()方法
- 很多對象繼承的toString()方法被重寫了,為了能調(diào)用正確版本的toString,必須間接的調(diào)用Function.call()方法
- 通過內(nèi)置構(gòu)造函數(shù)創(chuàng)建的對象包含“類屬性”,它與構(gòu)造函數(shù)名稱相匹配
- 通過對象直接量和Object.create創(chuàng)建的對象的類屬性是‘object’,自定義構(gòu)造函數(shù)創(chuàng)建的對象也是一樣,因此對于自定義函數(shù)來說,沒辦法通過類屬性類區(qū)分對象的類
- 可擴展性
- 對象的可擴展性用以表示是否可以給對象添加新屬性,所有內(nèi)置對象和自定義對象都是顯式可擴展的
- ECMAScript 5 定義了用來查詢和設(shè)置對象可擴展性的函數(shù)。Object.esExtensible()判斷是否可擴展
- 將對象轉(zhuǎn)換為不可擴展的,需要調(diào)用Object.preventExtensions(),一旦將對象轉(zhuǎn)換為不可擴展的,就無法再將其轉(zhuǎn)換回可擴展,并且只影響對象本身的可擴展性
- 給一個不可擴展的原型對象添加屬性,這個不可擴展對象同樣會繼承這些新屬性
- Object.seal()和Object.preventExtensions()類似,除了能夠?qū)ο笤O(shè)置為不可擴展的,還可以將對象的所有自有屬性都設(shè)置為不可配置的。也就是說不能給這個對象添加新屬性,而且它已有的屬性也不能刪除或配置,不過它已有的可寫屬性依然可以設(shè)置。
- 對于已經(jīng)封閉的對象是不能解封的。可以使用Object.isSealed()來檢查對象是否封閉
- Object.freeze()將更嚴(yán)格的鎖定對象——“凍結(jié)”。除了將對象設(shè)置不可擴展和不可配置外,還可以將它已有數(shù)據(jù)屬性設(shè)置為只讀(如果對象的存取器屬性具有setter方法,存取器屬性將不受影響,仍可以通過屬性賦值調(diào)用它們)。使用Object.isFrozen()來檢測對象是否凍結(jié)
- preventExtensions()seal()freeze()都返回傳入的對象,也就是說,可以通過函數(shù)嵌套的方式調(diào)用它們
- 序列化對象
- 序列化對象是指將對象的狀態(tài)轉(zhuǎn)換為字符串,也可將字符串還原為對象
- ECMAScript 5 提供了內(nèi)置函數(shù)JSON.stringify()和JSON.parse()用來序列化和還原JS對象
- JSON語法是JS語法的子集,并不能表示JS所有對象
- 子集
- 大多數(shù)代碼都會定義它們的子集,用以更安全的方式執(zhí)行第三方代碼
- 子集的設(shè)計目的是在容器或“沙箱”中更安全的運行不可信的第三方JavaScript代碼
- 所有能破壞這個沙箱并影響全局執(zhí)行環(huán)境的語言特性和API在這個安全子集中都是禁止的
- 為了讓代碼靜態(tài)的通過JavaScript安全檢查,必須移除一些JavaScript特性
- 禁止使用this,因為在(非嚴(yán)格模式中)this訪問全局變量
- 嚴(yán)格模式
- 嚴(yán)格模式是將更好的的錯誤檢查引入代碼中的方法
- 嚴(yán)格模式時,無法使用隱式聲明的變量、將賦值給只讀屬性或?qū)傩蕴砑拥讲豢蓴U展的對象等
- 消除JS代碼中一些不合理、不嚴(yán)謹(jǐn)之處,減少代碼怪異行為
- 程序或函數(shù)開頭使用use strict 來聲明嚴(yán)格模式
- with、帶.或[]表達(dá)式、function、windows和對Document的引用
- 支持對象、數(shù)組、字符串、無窮大數(shù)字、true、false和null,并可以序列化和反序列化
- NaN/Infinity和-Infinity序列化的結(jié)果是null
- RegExp、Error對象和undefined值不能序列化和還原
- JSON.stringify()只能序列化對象可枚舉的自有屬性
- 對于不能序列化的屬性來說,在序列化后的輸出字符串中會將這個屬性省略掉
- stringify()parse都可以接受第二個可選參數(shù),通過傳入需要序列化或還原的屬性列表來定制自定義的序列化或還原操作
- 對象方法
- toString方法
- toString方法沒有參數(shù),返回一個表示調(diào)用這個方法的對象值的字符串
- 很多類都帶有自自定義的toString方法
- toLocaleString方法
- 除了基本的tostring方法外,對象都包含toLocaleString方法,這個方法返回一個表示這個對象的本地字符串
- Date、Number類對toLocaleString方法做了定制
- valueOf
- valueOf與toString非常類似,當(dāng)JS需要將對象轉(zhuǎn)換為某種原始值而非字符串的時候才會調(diào)用它,尤其轉(zhuǎn)換為數(shù)字的時候
- 在需要使用原始值的地方使用了對象,JS就會自動調(diào)用這個方法
× 數(shù)組
- 數(shù)組是值的有序集合
- 每個值叫做一個元素,每個元素在數(shù)組中有一個位置,以數(shù)字表示,稱為索引
- 數(shù)組可以是任何類型,并且同一個數(shù)組中的不同元素也可能有不同的類型
- 數(shù)組的元素甚至也可能是對象或其他數(shù)組,這允許創(chuàng)建復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
- JS數(shù)組的索引是基于零的32位數(shù)值
- JS數(shù)組是動態(tài)的,根據(jù)需要他們會增長或縮減,并且在創(chuàng)建數(shù)組時無需聲明一個固定大小或者在數(shù)組大小變化時無需重新分配空間
- JS數(shù)組可能是稀疏的,數(shù)組元素的索引不一定要連續(xù)的,它們之間可以有空缺
- 每個JS數(shù)組都有一個length屬性。針對非稀疏數(shù)組該元素就是數(shù)組元素的個數(shù)
- 針對稀疏數(shù)組,length比所有元素的索引要大
- JS數(shù)組是JS對象的特殊形式
- 通常,數(shù)組的實現(xiàn)是經(jīng)過優(yōu)化的,用數(shù)字索引來訪問數(shù)組元素一般來說比訪問常規(guī)對象屬性要快很多
- 數(shù)組繼承自Array.prototype中的屬性,它定義了一套豐富的數(shù)組操作方法
- 數(shù)組直接量中的值不一定是常量,可以是任意表達(dá)式
- 它可以包含對象直接量或其他數(shù)組直接量
- 如果省略數(shù)組直接量中的某個值,省略的元素將被賦予undefined值
- 數(shù)組直接量的語法允許有可選的結(jié)尾的逗號
- 調(diào)用構(gòu)造函數(shù) Array()是創(chuàng)建數(shù)組的另一種方法,這種形式可以預(yù)分配一個數(shù)組空間,但數(shù)組中沒有存儲值,甚至數(shù)組的索引屬性還未定義
- 數(shù)組的特別之處在于,當(dāng)使用小于2的32次方的非負(fù)整數(shù)作為屬性名時數(shù)組會自動維護(hù)其length屬性值
- 所有數(shù)組都是對象,可以為其創(chuàng)建任意名字的屬性。但如果使用的屬性是數(shù)組的索引,數(shù)組的特殊行為就是將根據(jù)需要更新它們的length屬性值
- 可以使用負(fù)數(shù)或非整數(shù)來索引數(shù)組。在這種情況下,數(shù)值轉(zhuǎn)換為字符串,字符串作屬性名來用。既然名字不是非負(fù)整數(shù),它就只能當(dāng)作常規(guī)的對象屬性,而非數(shù)組的索引
- 使用了是非負(fù)整數(shù)的字符串,它就當(dāng)作數(shù)組索引,而非對象屬性
- 數(shù)組索引僅僅是對象屬性名的一種特殊類型,這意味著JS數(shù)組沒有“越界”錯誤的概念
- 當(dāng)試圖查詢?nèi)魏螌ο笾胁淮嬖诘膶傩詴r,不會報錯,只會得到undefined值。類似對象,對于對象同樣存在這種情況
- 既然數(shù)組是對象,那么它們可以從原型中繼承元素。在ECMASscript 5中,數(shù)組可以定義元素的getter和setter方法
- 如果一個元素確實繼承了元素或使用了元素的getter和setter方法,訪問這種數(shù)組的元素的時間會與常規(guī)對象屬性的查找時間相近
- 訪問數(shù)組
- 數(shù)組是對象的特殊形式。使用方括號訪問數(shù)組元素就像用方括號訪問對象的屬性一樣
- JS將指定的數(shù)字索引轉(zhuǎn)換成字符串——索引值1變成“1”——然后將其作為屬性名來使用
- 對于常規(guī)JS對象也可以使用方括號來操作
- 創(chuàng)建數(shù)組
- 直接量創(chuàng)建
- new Array()構(gòu)造函數(shù)創(chuàng)建
- × 數(shù)組元素的添加和刪除
- push()方法在數(shù)組末尾增加一個或多個元素
- unshift()方法在數(shù)組的首部插入一個元素,并且將其他元素依次移到跟高的索引處
- delete 直接刪除數(shù)組某個元素,并不影響數(shù)組長度
- 數(shù)組有pop方法(它和push()一起使用),后者一次使減少長度1并返回被刪除元素的值
- shift方法(它和unshift一起使用),從數(shù)組頭部刪除一個元素。和delete不同的是shift方法將所有元素下移到比當(dāng)前索引低1的地方
- 稀疏數(shù)組
- 稀疏數(shù)組就是包含從0開始的不連續(xù)索引的數(shù)組
- 通常數(shù)組中的length屬性值代表數(shù)組中元素的個數(shù)。如果數(shù)組是稀疏的,length屬性值大于元素的個數(shù)
- 可以用delete操作符來生產(chǎn)稀疏數(shù)組
- 足夠稀疏的數(shù)組通常在實現(xiàn)上比稠密的數(shù)組更慢、內(nèi)存利用率更高,在這一的數(shù)組中查找元素的時間與常規(guī)對象屬性的查找時間一樣長
- 通過數(shù)組刪除 Array.shift() 或 Array.pop() splice() 不會產(chǎn)生稀疏數(shù)組
- 數(shù)組長度
- 每個數(shù)組有一個length屬性,就是這個屬性使其區(qū)別于常規(guī)的JS對象
- 在數(shù)組中肯定找不到一個元素的索引值大于或等于它的長度。為了維持此規(guī)則不變化,數(shù)組有兩個特殊的行為
- 1:當(dāng)為數(shù)組元素賦值,他的索引i大于或等于現(xiàn)有數(shù)組長度時,length屬性的值將設(shè)置i+1
- 2:設(shè)置length屬性為一個小于當(dāng)前長度的非負(fù)整數(shù)n時,當(dāng)前數(shù)組中那些索引值大于或等于n的元素將從中刪除
- 如果讓一個數(shù)組元素不能配置,就不能刪除它。如果不能刪除它,length屬性不嫩設(shè)置為小于不可配置元素的索引值
- 數(shù)組的遍歷
- for
- 這是遍歷數(shù)組最常用的方法
- 在嵌套循環(huán)或其他性能非常重要的上下文中,可以看到這種基本的數(shù)組遍歷需要優(yōu)化,數(shù)組的長度應(yīng)該只查詢一次而非每次循環(huán)都要查詢
- for/in
- 自動處理稀疏數(shù)組
- 循環(huán)每次將一個可枚舉的屬性名(包括數(shù)組索引)賦值給循環(huán)變量。不存在的所有將不會被遍歷
- ECMAScript規(guī)范允許for/in循環(huán)以不同的孫旭遍歷對象的屬性。通常數(shù)組元素的遍歷實現(xiàn)是升序的,但不能保證一定是這樣。特別地,如果數(shù)組同時擁有對象屬性和數(shù)組元素,返回的屬性名很可能是按照創(chuàng)建的順序而非數(shù)值的大小順序。如果算法依賴于遍歷順序,那么不推薦這種遍歷方法
- forEach
- ECMAScript 5定義了一些遍歷數(shù)組元素的新方法,按照索引的順序按個傳遞給定義的一個函數(shù)。這些方法中最常用的就是forEach
- 多維數(shù)組
- JS不支持真正的多維數(shù)組,但可以用數(shù)組的數(shù)組來近似。
- × 數(shù)組方法
- join
- Array.join()方法將數(shù)組中所有元素都轉(zhuǎn)化為字符串并連接在一起,返回最后生成的字符串
- 可以指定一個可選的字符串在生產(chǎn)的字符串中來分割數(shù)組的各個元素。如果不指定分割符,默認(rèn)使用逗號
- join是string.split方法的逆向操作,后者是將字符串分割成若干塊來創(chuàng)建一個數(shù)組
- reverse
- 將數(shù)組中的元素顛倒順序,返回逆序的數(shù)組
- 它不通過重新排列的元素創(chuàng)建新的數(shù)組,而是在原先的數(shù)組中重新排序它們
- sort
- Array.sort()方法將數(shù)組中的元素排序并返回排序后的數(shù)組。當(dāng)不帶參數(shù)調(diào)用sort()時,數(shù)組元素以字母表順序排序
- 如果數(shù)組包含undefined元素,它們會被排到數(shù)組的尾部
- concat
- Array.concat()創(chuàng)建并返回一個新數(shù)組
- slice
- Array.slice()返回指定數(shù)組的一個片段或子數(shù)組
- splice
- Array.splice()方法是在數(shù)組中插入或刪除元素的通用方法
- push和pop
- unshift和shift
- 行為非常類似于push和pop,不一樣的是前者在數(shù)組的頭部而非尾部進(jìn)行元素的插入和刪除操作
- toString和toLocalString
- 數(shù)組和其他JS對象一樣擁有toString方法
- forEach
- 從頭至尾遍歷數(shù)組,為每個元素調(diào)用指定的函數(shù)
- map
- filter
- every和some
- reduce和reduceRight
- indexOf和astIndexOf
- 數(shù)組類型
- 類數(shù)組對象
- 作為數(shù)組的字符串
函數(shù)
- 函數(shù)是這樣一段JS代碼,它只定義一次,但可能被執(zhí)行或調(diào)用任意次
- JS函數(shù)是參數(shù)化的,函數(shù)的定義包括一個稱為形參的標(biāo)識符列表,這些參數(shù)在函數(shù)體內(nèi)像局部變量一樣工作
- 函數(shù)調(diào)用會為形參提供實參的值
- 函數(shù)使用它們實參的值來計算返回值,成為該函數(shù)調(diào)用表達(dá)式的值
- 除了實參之外,每次調(diào)用還會擁有另一個值——本次調(diào)用的上下文——這就是this關(guān)鍵字的值
- 函數(shù)掛載在一個對象上,作為對象的一個屬性,就稱它為對象的方法。當(dāng)通過這個對象來調(diào)用函數(shù)時,該對象就是此次調(diào)用的上下文,也就是該函數(shù)的this的值
- 用于初始化一個新創(chuàng)建的對象的函數(shù)稱為構(gòu)造函數(shù)
- 在JS里,函數(shù)即對象,程序可以隨意操控它們,比如可以把函數(shù)賦值給變量,或者作為參數(shù)傳遞給其他函數(shù)。因為函數(shù)就是對象,所有可以給它們設(shè)置屬性,甚至調(diào)用它們的方法
- JS的函數(shù)可以嵌套在其他函數(shù)中定義,這樣它們就可以訪問它們被定義是所處的作用域中的任何變量。這意味著JS函數(shù)構(gòu)成了一個閉包。它給JS帶來了非常強勁的編程能力
- 形參和實參的區(qū)別,形參相當(dāng)于函數(shù)中定義的變量,實參是在運行時的函數(shù)調(diào)用時傳入的參數(shù)
- 函數(shù)定義
- 函數(shù)使用function關(guān)鍵字來定義,它可以用在函數(shù)定義表達(dá)式或者函數(shù)聲明語句里。在兩種形式中,函數(shù)定義都從function關(guān)鍵字開始,其后跟隨這些組成部分
- 嵌套函數(shù)
- 有趣之處在于它們的變量作用域規(guī)則:它們可以訪問嵌套它們(或多重嵌套)的函數(shù)的參數(shù)和變量
- 函數(shù)調(diào)用
- 作為函數(shù)
- 作為方法
- 作為構(gòu)造函數(shù)
- 通過它們的call()和apply()方法間接調(diào)用
- 方法調(diào)用
- 一個方法無非就是保存在一個對象的屬性里的函數(shù)。這里的函數(shù)表達(dá)式本身就是一個屬性訪問表達(dá)式,這意味著該函數(shù)被當(dāng)作一個方法,而不是普通函數(shù)
- 方法調(diào)用與函數(shù)調(diào)用有一個重要的區(qū)別,即,調(diào)用上下文。屬性訪問表達(dá)式由兩部分組成,一個對象和屬性名稱。
- 方法和this關(guān)鍵字是面向?qū)ο缶幊谭独暮诵?/li>
- 任何函數(shù)只要作為方法調(diào)用實際上都會傳入一個隱式的實參——這個實參是一個對象,方法調(diào)用的母體就是這個對象,方法調(diào)用的語法已經(jīng)清晰表明了函數(shù)將基于一個對象進(jìn)行操作
- this是一個關(guān)鍵字,不是變量,也不是屬性名。JS的語法不允許給this賦值
- 和變量不同,this關(guān)鍵字沒有作用域的限制,嵌套函數(shù)不會從調(diào)用它的函數(shù)中繼承this
- 如果嵌套函數(shù)作為方法調(diào)用,其this的值指向調(diào)用它的對象。如果嵌套函數(shù)作為函數(shù)調(diào)用,其this值不是全局對象(非嚴(yán)格模式下)就是undefined(嚴(yán)格模式下)
- 方法鏈
- 當(dāng)方法返回值是一個對象,這個對象還可以再調(diào)用它的方法
- 構(gòu)造函數(shù)調(diào)用
- 如果函數(shù)或者方法調(diào)用之前帶有關(guān)鍵字new,它就構(gòu)造函數(shù)調(diào)用。
- 構(gòu)造函數(shù)調(diào)用和普通函數(shù)調(diào)用以及方法調(diào)用在實參處理、調(diào)用上下文和返回值方面都有不同
- 如果構(gòu)造函數(shù)調(diào)用在圓括號內(nèi)包含一組實參列表,先計算這些實參表達(dá)式,然后傳入函數(shù)內(nèi),這和函數(shù)調(diào)用和方法調(diào)用是一致的。如果構(gòu)造函數(shù)沒有形參調(diào)用都可以省略圓括號
- 構(gòu)造函數(shù)調(diào)用創(chuàng)建一個新的空對象,這個對象繼承自構(gòu)造函數(shù)的prototype屬性。構(gòu)造函數(shù)試圖初始化這個新創(chuàng)建的對象,并將這個對象用作其調(diào)用的上下文,因此構(gòu)造函數(shù)可以使用this關(guān)鍵字來引用這個新創(chuàng)建的對象
- 構(gòu)造函數(shù)通常不使用關(guān)鍵字return,它們通常初始化新對象,當(dāng)構(gòu)造函數(shù)的函數(shù)體執(zhí)行完畢時,它會顯示返回
- 如果構(gòu)造函數(shù)使用return語句但沒有指定返回值,或者返回一個原始值,那么這時將忽略返回值,同時使用這個新對象作為調(diào)用結(jié)果
- 間接調(diào)用
- JS中的函數(shù)也是對象,和其他JS對象沒什么兩樣,函數(shù)對象也可以包含方法。其中兩個方法call和apply()可以用來間接調(diào)用函數(shù)。兩個方法都允許顯示指定調(diào)用所需的this值,也就是說任何函數(shù)可以作為任何對象的方法來調(diào)用,哪怕這個函數(shù)不是那個對象的方法。兩個方法都可以指定調(diào)用的實參
- 函數(shù)的實參和形參
- JS中的函數(shù)定義并 未指定函數(shù)形參的類型,函數(shù)調(diào)用也未對傳入的實參值做任何類型檢查。
- JS函數(shù)調(diào)用甚至不檢查傳入形參的個數(shù)
- 可選形參
- /*optional*/來強調(diào)形參是可選的
- 可變長的實參列表:實參對象
- 當(dāng)調(diào)用函數(shù)的時候傳入的實參個數(shù)超過函數(shù)定義是的形參個數(shù)時,沒有辦法直接獲得未命名值的引用
- 在函數(shù)體內(nèi),標(biāo)識符arguments是指向?qū)崊ο蟮囊茫瑢崊ο笫且粋€類數(shù)組對象
- arguments并不是真正的數(shù)組,他是一個實參對象。每個實參對象都包含以數(shù)字為索引的一組元素以及l(fā)ength屬性,但并不是真正的數(shù)組??梢岳斫鉃榕銮删哂袛?shù)字為索引的屬性
- callee和caller屬性
- 非標(biāo)準(zhǔn)的,但是大多瀏覽器都有實現(xiàn),通過caller屬性可以訪問調(diào)用棧
- 將對象屬性用作實參
- 當(dāng)一個函數(shù)包含超過三個形參時,對程序員來說,要記住嗲用函數(shù)中實參的正確順序非常頭疼。通過傳入對象可以簡化這一步
- 作為函數(shù)的值
- 函數(shù)可以定義,也可調(diào)用,這時函數(shù)最重要的特性
- 函數(shù)定義和調(diào)用是JS的詞法特性
- JS中函數(shù)不僅是一種語法,也是值,可以將函數(shù)賦值給變量,存儲在對象的屬性或數(shù)組的元素中,作為參數(shù)傳入另外一個函數(shù)等
- 自定義函數(shù)屬性
- JS中的函數(shù)并不是原始值,而是一種特殊的對象,也就是說函數(shù)可以擁有屬性
- 作為命名空間的函數(shù)
- 函數(shù)作用域的概念:在函數(shù)中聲明的變量在函數(shù)體內(nèi)都是可見的(包括在嵌套函數(shù)中),在函數(shù)的外部是不可見的
- JS中無法聲明只在一個代碼塊內(nèi)部可見的變量,基于這個原因,我們常常是用函數(shù)用作臨時命名空間,在這個命名空間內(nèi)定義的變量都不會污染到全局命名空間
- × 閉包
- JS采用詞法作用域,函數(shù)的執(zhí)行依賴于變量作用域,這個作用域是在函數(shù)定義時決定的,而不是函數(shù)調(diào)用時決定的
- JS函數(shù)對象內(nèi)部不僅包含函數(shù)的代碼邏輯,還必須引用當(dāng)前的作用域鏈
- 函數(shù)對象通過作用域鏈互關(guān)聯(lián)起來,函數(shù)體內(nèi)部的變量都可以保存在函數(shù)作用域內(nèi),這種特性在計算機科學(xué)文獻(xiàn)中稱為“閉包”
- 從技術(shù)角度將,所有JS函數(shù)都是閉包:它們都是對象,它們都關(guān)聯(lián)到作用域鏈
- 定義大多數(shù)函數(shù)時的作用域鏈在調(diào)用函數(shù)時依然有效,但這并不影響閉包
- 待更新........
- 函數(shù)屬性、方法和構(gòu)造函數(shù)
- length屬性
- arguments.length表示傳入函數(shù)的實參的個數(shù)。而函數(shù)本身的length屬性是只讀的,它代表函數(shù)定義時形參的數(shù)量
- prototype屬性
- 每一個函數(shù)都包含一個prototype屬性,這個屬性指向一個對象的引用,這個對象稱作“原型對象”
- call方法和apply方法
- bind方法
- toString方法
- function構(gòu)造函數(shù)
- 可調(diào)用的對象
- 函數(shù)式編程
- JS并非函數(shù)式編程語言
- JS中可以向操作對象一樣操控函數(shù),也就是說可以在JS中應(yīng)用函數(shù)式編程技術(shù)
- 使用函數(shù)處理數(shù)組
- 高階函數(shù)就是操作函數(shù)的函數(shù),它接收一個或多個函數(shù)作為參數(shù),并返回一個新函數(shù)
- 高階函數(shù)
- 不完全函數(shù)
- 記憶
類和模塊
- 在JS中可以定義對象的類,讓每個對象都共享某些屬性
- 在JS中類的實現(xiàn)是基于其原型繼承機制的
- 兩個實例都從同一個原型對象繼承了屬性,我們說他們是同一個類的實例
- 如果兩個對象繼承自同一個原型,往往意味著(擔(dān)不是絕對)它們是由同一個構(gòu)造函數(shù)創(chuàng)建并初始化
- JS中類的一個重要特性是“動態(tài)可繼承”
- 類和原型
- 在JS中,類的所有實例對象都從同一個原型對象上繼承屬性,因此,原型對象是類的核心
- 類和構(gòu)造函數(shù)
- 構(gòu)造函數(shù)是用來初始化新創(chuàng)建的對象的
- 調(diào)用構(gòu)造函數(shù)的一個重要特征是,構(gòu)造函數(shù)的prototype屬性被用做新對象的原型。這意味著同一個構(gòu)造函數(shù)創(chuàng)建的所有對象都繼承自一個相同的對象,因此他們都是同一個類的成員
- 構(gòu)造函數(shù)和類的標(biāo)識
- 原型對象是類的唯一標(biāo)識,當(dāng)且僅當(dāng)兩個對象繼承自同一個原型對象時,它們才是屬于同一個類的實例。而初始化的構(gòu)造函數(shù)則不能作為類的標(biāo)識,兩個構(gòu)造函數(shù)的prototype屬性可能指向同一個原型對象。那么這兩個構(gòu)造函數(shù)有創(chuàng)建的實例屬于同一個類
- 構(gòu)造函數(shù)是類的“外在表現(xiàn)”。構(gòu)造函數(shù)名字通常用做類名
- instanceof的語法強化了“構(gòu)造函數(shù)是類的公有標(biāo)識”概念
- constructor屬性
- 任何JS函數(shù)都可以用作構(gòu)造函數(shù),并且調(diào)用構(gòu)造函數(shù)是需要用到一個prototye屬性的
- 每個JS函數(shù)(ECMAScript5中的Function.bind()方法返回的函數(shù)除外)都自動擁有一個prototype屬性。這個屬性的值是一個對象,這個對象包含唯一一個不可枚舉屬性constructor。constructor屬性值是一個函數(shù)對象
- JS中Java式的類繼承
- 構(gòu)造函數(shù)對象
- 構(gòu)造函數(shù)(對象)為JS類定義名字。任何添加到這個構(gòu)造函數(shù)對象中的屬性都是類字段和類方法(如果屬性值是函數(shù)的話就是類方法)
- 原型對象
- 原型對象的屬性被類的所有實例所繼承,如果原型對象的屬性值是函數(shù)的話,這個函數(shù)就作為類的實例的方法來調(diào)用
- 實例對象
- 類的每個實例都是一個獨立的對象,直接給這個實例定義屬性是不會為所有實例對象所共享的。定義在實例上的非函數(shù)屬性,實際上是實例的字段
- JS中定義類的步驟
- 第一步,定義一個構(gòu)造函數(shù),并設(shè)置初始化新對象的實例屬性
- 第二步,給構(gòu)造函數(shù)的prototype對象定義實例的方法
- 第三步,給構(gòu)造函數(shù)定義類字段和類屬性
- 類的擴充
- JS中基于原型的繼承機制是動態(tài)的,對象從其原型繼承屬性,如果創(chuàng)建對象之后原型的屬性發(fā)生變化,也會影響到繼承這個原型的所有實例對象
- 類和類型
- JS定義了少量的數(shù)據(jù)類型:null、undefined、布爾值、數(shù)字、字符串、函數(shù)和對象
- instanceof運算符
- 左操作符是待檢測其類對象,右操作數(shù)是定義類的構(gòu)造函數(shù)。返回布爾值,這里檢測繼承可以不是直接繼承
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。