小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JavaScript高級程序設(shè)計(jì)讀書筆記

 新進(jìn)小設(shè)計(jì) 2021-11-14

JavaScript簡介

JavaScript簡史

JavaScript 誕生于 1995 年。


JavaScript實(shí)現(xiàn)

一個(gè)完整的 JavaScript 實(shí)現(xiàn)由下列三個(gè)不同的部分組成:

  1. 核心(ECMAScript);
  2. 文檔對象模型(DOM);
  3. 瀏覽器對象模型(BOM);

ECMAScript

ECMA-262 標(biāo)準(zhǔn)沒有參照 web 瀏覽器,它規(guī)定了這門語言的下列組成部分:語法、類型、語句、關(guān)鍵字、保留字、操作符、對象。


文檔對象模型(DOM)

文檔對象模型(DOM,Document Object Model)是針對 XML 但經(jīng)過擴(kuò)展用于 HTML 的應(yīng)用程序編程接口(API)。


瀏覽器對象模型(BOM)

瀏覽器對象模型(BOM,Browser Object Model)從根本上將,BOM 只處理瀏覽器窗口和框架,但人們習(xí)慣上也把所有針對瀏覽器的 JavaScript 擴(kuò)展算作 BOM 的一部分,下面就是一些這樣的擴(kuò)展:

  • 彈出新瀏覽器窗口的功能;
  • 移動、縮放和關(guān)閉瀏覽器窗口的功能;
  • 提供瀏覽器詳細(xì)信息的 navigator 對象;
  • 提供瀏覽器所加載頁面的詳細(xì)信息的 location 對象;
  • 提供用戶顯示器分辨率詳細(xì)信息的 screen 對象;
  • 對 cookies 的支持;
  • 像 XMLHttpRequest 和 IE 的 ActiveXObject 這樣的自定義對象;

小結(jié)

JavaScript 是一種專門與網(wǎng)頁交互而設(shè)計(jì)的腳本語言,由下列三個(gè)部分組成:

  1. ECMAScript,由 ECMA-262 定義,提供核心語言功能;
  2. 文檔對象模型(DOM),提供訪問和操作網(wǎng)頁內(nèi)容的方法和接口;
  3. 瀏覽器對象模型(BOM),提供與瀏覽器交互的方法和接口;

在HTML中使用JavaScript

script元素

向 HTML 頁面中插入 JavaScript 的主要方法就是使用 <script> 元素。

使用 <script> 元素的方式有兩種:直接在頁面中嵌入 JavaScript 代碼和包含外部 JavaScript 文件。

注意:使用 <script> 引入外部 JavaScript 文件時(shí),不要在標(biāo)簽內(nèi)添加額外的 JS 代碼,如果添加了將會被忽略。


標(biāo)簽的位置

按照傳統(tǒng)的做法,所有 <script> 元素都應(yīng)該放在頁面中 <head> 元素中,這種做法的目的就是把所有外部文件(CSS文件和JavaScript文件)的引用都放在相同的地方。

可是這種做法有一種缺點(diǎn)就是,必須要等到全部 JS 代碼都被下載、解析和執(zhí)行完成以后,才能開始出現(xiàn)頁面的內(nèi)容(瀏覽器在遇到 <body> 標(biāo)簽時(shí)才開始出現(xiàn)內(nèi)容)。對于需要很多 JS 代碼的頁面來說,這會導(dǎo)致頁面出現(xiàn)明顯的延遲,而在延遲期間頁面是一片空白。所以,為了避免這個(gè)問題,我們應(yīng)該把 JS 引用放在 <body> 結(jié)束標(biāo)簽前面,即:

<body> 
    <!--  html代碼  -->   
    <script type="text/javascript" src="index.js"></script>
</body>

延遲腳本

<script> 標(biāo)簽的 defer 屬性用途是表明腳本在執(zhí)行時(shí)不會影響頁面的構(gòu)造。也就是說,腳本會被延遲到整個(gè)頁面都解析完畢后再運(yùn)行。因此,在 <script> 元素中設(shè)置 defer 屬性,相當(dāng)于告訴瀏覽器立即下載,但延遲執(zhí)行。

假設(shè)把 <script> 元素放在 <head> 元素之中,并加上 defer 屬性,但其中包含的腳本將延遲到瀏覽器遇到 </html> 標(biāo)簽后再執(zhí)行。HTML5 規(guī)范要求腳本按照它們出現(xiàn)的先后順序執(zhí)行,因此第一個(gè)延遲腳本會先于第二個(gè)延遲腳本執(zhí)行,而這兩個(gè)腳本會先于 DOMContentLoaded 事件執(zhí)行。但在現(xiàn)實(shí)中,延遲腳本不一定會按順序執(zhí)行,也不一定會在 DOMContentLoaded 事件觸發(fā)前執(zhí)行,因此最好只包含一個(gè)延遲腳本。

defer 屬性只適用于外部腳本文件。


異步腳本

HTML5 為 <script> 元素定義了 async 屬性。與 defer 屬性類似,都用于改變處理腳本的行為,也只適用于外部腳本文件,并告訴瀏覽器立即下載文件。但不同的是,標(biāo)記為 async 的腳本并不保證按照指定它們的先后順序執(zhí)行。

例如,在 <head> 元素中放兩個(gè) <script> 元素。第二個(gè)腳本文件可能會在第一個(gè)腳本文件前執(zhí)行。指定 async 屬性的目的是不讓頁面等待兩個(gè)腳本下載和執(zhí)行,從而異步加載頁面其他內(nèi)容。因此,建議異步腳本不要在加載期間修改 DOM。

異步腳本一定會在頁面的 load 事件前執(zhí)行,但可能會在 DOMContentLoaded 事件觸發(fā)前或后執(zhí)行。


嵌入代碼與外部文件

使用外部文件的優(yōu)點(diǎn):

  1. 可維護(hù)性;
  2. 可緩存;
  3. 適應(yīng)未來;

文檔模式

兩種文檔模式:混雜模式(quirks mode)、標(biāo)準(zhǔn)模式(standards mode)。


noscript元素

這個(gè)元素用以在不支持 JS 的瀏覽器中顯示替代的內(nèi)容。

包含 <noscript> 元素中的內(nèi)容只有在下面的情況才會顯示出來:

  1. 瀏覽器不支持腳本;
  2. 瀏覽器支持腳本,但腳本被禁用;

基本概念

語法

區(qū)分大小寫

ECMAScript 中的一切(變量、函數(shù)名和操作符)都區(qū)分大小寫。


標(biāo)識符

標(biāo)識符就是指變量、函數(shù)、屬性的名字,或函數(shù)的參數(shù)。

標(biāo)識符按照以下規(guī)則組合:

  • 第一個(gè)字符必須是字母、下劃線(_)或美元符號($);
  • 其他字符可以是字母、下劃線、美元符號或數(shù)字;

不能把關(guān)鍵字、保留字、true、false、null 用作標(biāo)識符。


注釋

// 單行注釋

/*
這是多行注釋
這是多行注釋
*/

嚴(yán)格模式

嚴(yán)格模式是為 JS 定義了一種不同的解析與執(zhí)行模型。在嚴(yán)格模式下,一些不確定的行為將得到處理,對某些不安全的操作會拋出錯(cuò)誤。

要在整個(gè)腳本中啟用嚴(yán)格模式,可以在頂部添加下列代碼:

"use strict";

它是一個(gè)編譯指示(pragma),用來告訴支持 JS 引擎切換到嚴(yán)格模式。

可以指定函數(shù)在嚴(yán)格模式下執(zhí)行:

function doSomething(){
    "use strict";
    //函數(shù)體
}

語句

ECMAScript 中語句以一個(gè)分號結(jié)尾。如果省略分號,則由解析器確定語句的結(jié)尾。

雖然語句結(jié)尾的分號并不是必須的,但最好還是不要省略。因?yàn)榧由戏痔柨梢员苊夂芏噱e(cuò)誤,也會在某些情況下增進(jìn)代碼性能。


關(guān)鍵字和保留字

關(guān)鍵字可用于表示控制語句的開始或結(jié)束,或用于執(zhí)行特定操作等。關(guān)鍵字不能用作標(biāo)識符。

ECMA-262 還描述了一組不能用作標(biāo)識符的保留字


變量

ECMAScript 的變量是松散類型的,就是可以用來保存任何類型的數(shù)據(jù)。

定義變量時(shí)要使用 var 操作符(var是一個(gè)關(guān)鍵字),后跟變量名(即標(biāo)識符)。

如果省略 var 操作符可以定義全局變量,但這也不是我們所推薦的。因?yàn)樵诰植孔饔糜蛑卸x的全局變量很難維護(hù),而且如果有意地忽略了 var 操作符,也會由于相應(yīng)變量不會馬上就有定義而導(dǎo)致不必要的混亂。給未經(jīng)聲明的變量賦值在嚴(yán)格模式下會拋出 ReferenceError 錯(cuò)誤。


數(shù)據(jù)類型

簡單數(shù)據(jù)類型(基本數(shù)據(jù)類型):undefined、null、boolean、number、string、symbol(ES 6新引入的數(shù)據(jù)類型)。

復(fù)雜數(shù)據(jù)類型:object。

typeof操作符

typeof 用來檢測給定變量的數(shù)據(jù)類型,只適用于基本數(shù)據(jù)類型的類型判斷。

對一個(gè)值使用 typeof 操作符可能返回下列某個(gè)字符串:

  • “undefined” - 如果這個(gè)值未定義;
  • “boolean” - 如果這個(gè)值是布爾值;
  • “string” - 如果這個(gè)值是字符串;
  • “number” - 如果這個(gè)值是數(shù)值;
  • “object” - 如果這個(gè)值是對象或 null;
  • “function” - 如果這個(gè)值是函數(shù);

undefined類型

undefined 類型只有一個(gè)值,即特殊的 undefined。在使用 var 聲明變量但未對其加以初始化時(shí),這個(gè)變量的值就是 undefined。

對未初始化的變量執(zhí)行 typeof 操作符會返回 undefined 值,而對未聲明的變量執(zhí)行 typeof 操作符同樣也會返回 undefined 值。


null類型

null 類型也只有一個(gè)值,這個(gè)特殊的值是 null。

使用 typeof 操作符檢測 null 值時(shí)會返回 “object” :

var car = null
alert(typeof car);    // "object"

boolean類型

boolean 類型只有兩個(gè)值:true、false。

注意:boolean 類型的值是區(qū)分大小寫的,True、False(以及其他的混合大小寫形式)都不是 boolean 的值,只是標(biāo)識符。

要將一個(gè)值轉(zhuǎn)換為其對應(yīng)的 boolean 值,可以調(diào)用轉(zhuǎn)型函數(shù) Boolean()。


number類型

八進(jìn)制字面值的第一位必須是零(0),然后是八進(jìn)制數(shù)字序列(0~7)。如果字面值中的數(shù)值超出了范圍,那前導(dǎo)零將被忽略,后面的數(shù)值將被當(dāng)作十進(jìn)制數(shù)解析。

十六進(jìn)制字面值的前兩位必須是0x,后面跟任何十六進(jìn)制數(shù)字(09及AF),其他A~F可以大寫,也可以小寫。

在進(jìn)行算術(shù)計(jì)算時(shí),所有以八進(jìn)制、十六進(jìn)制表示的數(shù)值最后將被轉(zhuǎn)換成十進(jìn)制數(shù)值。


浮點(diǎn)數(shù)值

浮點(diǎn)數(shù)值就是該數(shù)值中必須包含一個(gè)小數(shù)點(diǎn),并且小數(shù)點(diǎn)后面必須至少有一位數(shù)字。


數(shù)值范圍

ECMAScript 能夠表示的最小數(shù)值存在 Number.MIN_VALUE 中,在大多數(shù)瀏覽器中,這個(gè)值是 5e-324。

ECMAScript 能夠表示的最大數(shù)值存在 Number.MAX_VALUE 中,在大多數(shù)瀏覽器中,這個(gè)值是 1.7976931348623157e+308。

如果計(jì)算結(jié)果超出了 JavaScript 數(shù)值范圍時(shí),那么這個(gè)數(shù)值將被自動轉(zhuǎn)換成 Infinity 值。如果這個(gè)數(shù)值為負(fù)數(shù),將被轉(zhuǎn)換成 -Infinity(負(fù)無窮),如果這個(gè)數(shù)值為正數(shù),將被轉(zhuǎn)換成 Infinity(正無窮)。


NaN

即非數(shù)值是一個(gè)特殊的數(shù)值,這個(gè)數(shù)值用于表示一個(gè)本來要返回?cái)?shù)值的操作數(shù)未返回?cái)?shù)值的情況(這樣就不會拋出錯(cuò)誤)。

有兩個(gè)特點(diǎn)。首先,任何涉及 NaN 的操作都會返回 NaN,這個(gè)特點(diǎn)在多步計(jì)算中有可能導(dǎo)致問題。其次,NaN 與任何值都不相等,包括 NaN 本身。

alert(NaN == NaN);    // false

針對這兩個(gè)特點(diǎn),ECMAScript 定義了 isNaN() 函數(shù)。這個(gè)函數(shù)接受一個(gè)參數(shù),該參數(shù)可以是任何類型,而函數(shù)會幫我們確定這個(gè)參數(shù)是否“不是數(shù)值”。某些不是數(shù)值的值會直接轉(zhuǎn)換為數(shù)值。

alert(isNaN(NaN));    // true
alert(isNaN(10));       // false(10是數(shù)值)
alert(isNaN("10"));    // false(可以被轉(zhuǎn)換成數(shù)值10)
alert(isNaN("blue"));    // true(不能轉(zhuǎn)換為數(shù)值)
alert(isNaN(true));    // false(可以被轉(zhuǎn)換成數(shù)值1) 

數(shù)值轉(zhuǎn)換

有三個(gè)函數(shù)可以把非數(shù)值轉(zhuǎn)換為數(shù)值:Number()、parseInt()、parseFloat()。

Number() 函數(shù)可以用于任何數(shù)據(jù)類型,另外兩個(gè)函數(shù)則專門用于把字符串轉(zhuǎn)為數(shù)值。這三個(gè)函數(shù)對于同樣的輸入會有返回不同的結(jié)果。

Number() 函數(shù)的轉(zhuǎn)換規(guī)則:

  • 如果是 boolean 值,true、false 將分別轉(zhuǎn)為 1 和 0。
  • 如果是數(shù)字值,只是簡單的傳入和返回。
  • 如果是 null 值,返回 0。
  • 如果是 undefined,返回 NaN。
  • 如果是字符串,遵循下列規(guī)則:
    1. 如果字符串中只包含數(shù)字(包括帶正負(fù)號情況),則將其轉(zhuǎn)換為十進(jìn)制數(shù)值(前導(dǎo)的零會被忽略)。
    2. 如果字符串中包含有效的浮點(diǎn)格式,則將其轉(zhuǎn)換為對應(yīng)的浮點(diǎn)數(shù)值(前導(dǎo)的零會被忽略)。
    3. 如果字符串中包含有效的十六進(jìn)制格式,則將其轉(zhuǎn)換為相同大小的十進(jìn)制數(shù)值。
    4. 如果字符串為空(不含任何字符),則將其轉(zhuǎn)換為 0。
    5. 如果字符串中包含除上述格式以外的字符,則將其轉(zhuǎn)換為 NaN。
  • 如果是對象,則調(diào)用對象的 valueOf() 方法,然后依照前面的規(guī)則轉(zhuǎn)換返回的值。如果轉(zhuǎn)換結(jié)果為 NaN,則調(diào)用對象的 toString() 方法,然后再依照前面的規(guī)則轉(zhuǎn)換返回的字符串值。

string類型

string 類型用于表示由零或多個(gè) 16 位 Unicode 字符組成的字符序列,即字符串。

字符字面量

String 數(shù)據(jù)類型包含一些特殊的字符字面量,也叫轉(zhuǎn)義序列。

\n 換行
\t 制表
\b 退格
\r 回車
\f 進(jìn)紙
\\ 斜杠
' 單引號(')
" 雙引號(")


字符串的特點(diǎn)

ECMAScript 的字符串是不可變的,也就是說,字符串一旦創(chuàng)建,它們的值就不能改變。如果要改變某個(gè)變量保存的字符串,首先要摧毀原來的字符串,然后再用另一個(gè)包含新值得字符串填充該變量。


轉(zhuǎn)換為字符串

把一個(gè)值轉(zhuǎn)換為一個(gè)字符串有兩種方式。第一種是使用幾乎每個(gè)值都有得 toString() 方法。

在不知道要轉(zhuǎn)換的值是不是 null 或 undefined 的情況時(shí),還可以使用轉(zhuǎn)型函數(shù) String(),這個(gè)函數(shù)能夠?qū)⑷魏晤愋偷闹缔D(zhuǎn)換為字符串。

String()函數(shù)遵循下列轉(zhuǎn)換規(guī)則:

  • 如果值由 toString() 方法,則調(diào)用該方法(沒有參數(shù))并返回相應(yīng)的結(jié)果。
  • 如果值是 null,則返回 "null"。
  • 如果值是 undefined,則返回 "undefined"。

Object類型

ECMAScript 中的對象其實(shí)就是一組數(shù)據(jù)和功能的集合。

對象可以通過執(zhí)行 new 操作符后跟要?jiǎng)?chuàng)建的對象類型的名稱來創(chuàng)建。而創(chuàng)建 Object 類型的實(shí)例并為其添加屬性和(或)方法,就可以創(chuàng)建自定義對象。

Object 的每個(gè)實(shí)例都具有下列屬性和方法:

  • constructor:保存著用于創(chuàng)建當(dāng)前對象的函數(shù)。
  • hasOwnProperty(propertyName):用于檢查給定的屬性在當(dāng)前對象實(shí)例中是否存在。
  • isPrototypeOf(object):用于檢查傳入的對象是否是當(dāng)前對象的原型。
  • propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用 for-in 語句來枚舉。
  • toLocaleString():返回對象的字符串表示,該字符串與執(zhí)行環(huán)境的地區(qū)對應(yīng)。
  • toString():返回對象的字符串表示。
  • valueOf():返回對象的字符串、數(shù)值或布爾值表示,通常與 toString() 方法的返回值相同。

操作符

操作符包括算術(shù)操作符(如加號和減號)、位操作符、關(guān)系操作符、相等操作符

一元操作符

只能操作一個(gè)值的操作符叫一元操作符。

遞增和遞減操作符

前置型、后置型。前置型應(yīng)該位于要操作的變量之前,后置型應(yīng)該位于要操作的變量之后。

執(zhí)行前置遞增和遞減操作時(shí),變量的值都是在語句被求值以前改變的。

后置的遞增和遞減操作是在包含它們的語句被求值之后才執(zhí)行的。

在應(yīng)用于不同的值時(shí),遞增和遞減操作符遵循下列規(guī)則:

  • 在應(yīng)用于一個(gè)包含有效數(shù)字字符的字符串時(shí),先將其轉(zhuǎn)換為數(shù)字值,再執(zhí)行加減 1 的操作。字符串變量變成數(shù)值變量。
  • 在應(yīng)用于一個(gè)不包含有效數(shù)字字符的字符串時(shí),將變量的值設(shè)置為 NaN。字符串變量變成數(shù)值變量。
  • 在應(yīng)用于布爾值 false 時(shí),先將其轉(zhuǎn)換為 0 再執(zhí)行加減 1 的操作。布爾值變量變成數(shù)值變量。
  • 在應(yīng)用于布爾值 true 時(shí),先將其轉(zhuǎn)換為 1 再執(zhí)行加減 1 的操作。布爾值變量變成數(shù)值變量。
  • 在應(yīng)用于浮點(diǎn)數(shù)值時(shí),執(zhí)行加減 1 的操作。
  • 在應(yīng)用于對象時(shí),先調(diào)用對象的 value() 方法以取得一個(gè)可供操作的值。然后對該值應(yīng)用前述規(guī)則。如果結(jié)果是 NaN,則在調(diào)用 toString() 方法后再應(yīng)用前述規(guī)則。

一元加和減操作符

一元加操作符以一個(gè)加號(+)表示,放在數(shù)值前面,對數(shù)值不會產(chǎn)生任何影響。

一元減操作符主要用于表示負(fù)數(shù)。


位操作符

位操作符不直接操作 64 位的值,而是先將 64 位的值轉(zhuǎn)換成 32 位的整數(shù),然后執(zhí)行操作,最后再將結(jié)果轉(zhuǎn)換回 64 位。

對于有符號的整數(shù),32 位中的前 31 位用于表示整數(shù)的值。第 32 位表示數(shù)值的符號:0表示正數(shù),1表示負(fù)數(shù)。這個(gè)表示符號的位叫符號位

負(fù)數(shù)以二進(jìn)制碼存儲,使用的格式是二進(jìn)制補(bǔ)碼,計(jì)算一個(gè)數(shù)值的二進(jìn)制補(bǔ)碼,經(jīng)過以下步驟:

  1. 求這個(gè)數(shù)值絕對值的二進(jìn)制碼;
  2. 求二進(jìn)制反碼,即將 0 替換為 1,1 替換為 0;
  3. 得到的二進(jìn)制反碼加 1。
    根據(jù)這 3 個(gè)步驟求 -18 的二進(jìn)制碼,首先求 18 的二進(jìn)制碼:
    0000  0000  0000  0000  0000  0000  0001  0010
    然后,求其二進(jìn)制反碼:
    1111  1111  1111  1111  1111  1111  1110  1101
    最后,二進(jìn)制反碼加1:
    1111  1111  1111  1111  1111  1111  1110  1101
                                   1
    -------------------------------------------------------------------------------
    1111  1111  1111  1111  1111  1111  1110  1110
    就求得-18的二進(jìn)制表示。

如果對非數(shù)值應(yīng)用位操作符,會先使用 Number() 函數(shù)將該值轉(zhuǎn)換為一個(gè)數(shù)值,然后再應(yīng)用位操作,得到的結(jié)果是一個(gè)數(shù)值。


按位非(NOT)

按位非操作符由一個(gè)波浪線(~)表示。

執(zhí)行按位非得結(jié)果就是返回?cái)?shù)值得反碼。

按位非操作的本質(zhì):操作數(shù)的負(fù)值減 1。

按位非是在數(shù)值表示的最底層執(zhí)行操作,因此速度更快。


按位與(AND)

按位與操作符由一個(gè)和號字符(&)表示,它由兩個(gè)操作符數(shù)。

按位與操作只在兩個(gè)數(shù)值的對應(yīng)位都是 1 時(shí)才返回 1,任何一位是 0,結(jié)果都是 0。


按位或(OR)

按位或操作符由一個(gè)豎線(|)表示,也有兩個(gè)操作符。

按位或操作在有一個(gè)位是 1 的情況下就返回 1,而只有在兩個(gè)位都是 0 的情況下才返回 0。


按位異或(XOR)

按位異或操作符由一個(gè)插入符號(^)表示,也有兩個(gè)操作符。

按位異或操作在兩個(gè)數(shù)值對應(yīng)位上只有一個(gè) 1 時(shí)才返回 1,如果對應(yīng)的兩位都是 1 或 0,則返回 0。


左移

左移操作符由兩個(gè)小于號(<<)表示,這個(gè)操作符會將數(shù)值的所有位向左移動指定的位數(shù)。

在向左移位后,原數(shù)值的右側(cè)就多出了空位,就用 0 來填充空位。

左移不會影響操作數(shù)的符號位。


有符號的右移

有符號的右移操作符由兩個(gè)大于號(>>)表示,這個(gè)操作符會將數(shù)值向右移動,但保留符號位(即正負(fù)號標(biāo)記)。

在右移過程中,原數(shù)值出現(xiàn)空位,用符號位的值來填充空位。


無符號右移

無符號右移操作符由 3 個(gè)大于號(>>>)表示,這個(gè)操作符會將數(shù)值的所有 32 位都向右移動。對正數(shù)來說,無符號右移的結(jié)果與有符號右移相同。

對于負(fù)數(shù)來說,無符號右移是以 0 來填充空位。


布爾操作符

布爾操作符一共有 3 個(gè):非(NOT)、與(AND)、或(OR)。

邏輯非

邏輯非操作符由一個(gè)嘆號(!)表示。邏輯非操作符首先會將它的操作數(shù)轉(zhuǎn)換為一個(gè)布爾值,然后再對其求反。

邏輯非操作符遵循以下規(guī)則:

  • 如果操作數(shù)是一個(gè)對象,返回 false;
  • 如果操作數(shù)是一個(gè)空字符串,返回 true;
  • 如果操作數(shù)是一個(gè)非空字符串,返回 false;
  • 如果操作數(shù)是數(shù)值 0,返回 true;
  • 如果操作數(shù)是任意非 0 數(shù)值(包括Infinity),返回 false;
  • 如果操作數(shù)是 null,返回 true;
  • 如果操作數(shù)是 NaN,返回 true;
  • 如果操作數(shù)是 undefined,返回 true。

邏輯非操作符也可以用于將一個(gè)值轉(zhuǎn)換為與其對應(yīng)的布爾值,用同時(shí)使用兩個(gè)邏輯非操作符(!!)。


邏輯與

邏輯與操作符由兩個(gè)和號(&&)表示,有兩個(gè)操作數(shù)。

在有一個(gè)操作數(shù)不是布爾值的情況下,邏輯與操作不一定返回布爾值,此時(shí)遵循下列規(guī)則:

  • 如果第一個(gè)操作數(shù)是對象,則返回第二個(gè)操作數(shù);
  • 如果第二個(gè)操作數(shù)是對象,則只有在第一個(gè)操作數(shù)的求值結(jié)果為 true 的情況下才會返回該對象;
  • 如果兩個(gè)操作數(shù)都是對象,則返回第二個(gè)操作數(shù);
  • 如果第一個(gè)操作數(shù)是 null,則返回 null;
  • 如果第一個(gè)操作數(shù) NaN,則返回 NaN;
  • 如果一個(gè)操作數(shù)是 undefined,則返回 undefined。

邏輯與操作屬于短路操作,即第一個(gè)操作數(shù)能夠決定結(jié)果,那么就不會再對第二個(gè)操作數(shù)求值。


邏輯或

邏輯或操作符由兩個(gè)豎線符號(||)表示,也有兩個(gè)操作數(shù)。

遵循以下規(guī)則:

  • 如果第一個(gè)操作數(shù)是對象,則返回第一個(gè)操作數(shù);
  • 如果第一個(gè)操作數(shù)的求值結(jié)果為 false,則返回第二個(gè)操作數(shù);
  • 如果兩個(gè)操作數(shù)都是對象,則返回第一個(gè)操作數(shù);
  • 如果兩個(gè)操作數(shù)都是 null,則返回 null;
  • 如果兩個(gè)操作數(shù)都是 NaN,則返回 NaN;
  • 如果兩個(gè)操作數(shù)都是 undefined,則返回 undefined。

邏輯或操作符也是短路操作符,如果第一個(gè)操作數(shù)的求值結(jié)果為 true,就不會對第二個(gè)操作數(shù)求值。


乘性操作符

3 個(gè)乘性操作符:乘法、除法、求模。

乘法

乘法操作符由一個(gè)星號(*)表示,用于計(jì)算兩個(gè)數(shù)值的乘積。

在處理特殊值情況下,遵循下列特殊規(guī)則:

  • 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的乘法計(jì)算;
  • 如果有一個(gè)操作數(shù)是 NaN,則結(jié)果是 NaN;
  • 如果是 Infinity 與 0 相乘,則結(jié)果是 NaN;
  • 如果是 Infinity 與非 0 數(shù)值相乘,則結(jié)果是 Infinity 或 -Infinity,取決于有符號操作符的符號;
  • 如果是 Infinity 與 Infinity 相乘,則結(jié)果是 Infinity;
  • 如果有一個(gè)操作數(shù)不是數(shù)值,則在后臺調(diào)用 Number() 將其轉(zhuǎn)換為數(shù)值,然后再應(yīng)用以上規(guī)則。

除法

除法操作符由一個(gè)斜線符號(/)表示,執(zhí)行第二個(gè)操作數(shù)除第一個(gè)操作數(shù)的計(jì)算。

在處理特殊值情況下,遵循下列特殊規(guī)則:

  • 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的除法計(jì)算;
  • 如果有一個(gè)操作數(shù)是 NaN,則結(jié)果是 NaN;
  • 如果是 Infinity 被 Infinity 除,則結(jié)果是 NaN;
  • 如果是零被零除,則結(jié)果是 NaN;
  • 如果是非零的有限數(shù)被零除,則結(jié)果是 Infinity 或 -Infinity,取決于有符號操作數(shù)的符號;
  • 如果是 Infinity 被任何非零數(shù)值除,則結(jié)果是 Infinity 或 -Infinity,取決于有符號操作數(shù)的符號;
  • 如果有一個(gè)操作數(shù)不是數(shù)值,則在后臺調(diào)用 Number() 將其轉(zhuǎn)換為數(shù)值,然后再應(yīng)用以上規(guī)則。

求模

求模(余數(shù))操作符由一個(gè)百分號(%)表示。

在處理特殊值情況下,遵循下列特殊規(guī)則:

  • 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的除法計(jì)算,返回除得的余數(shù);
  • 如果被除數(shù)是無窮大值而除數(shù)是有限大的數(shù)值,則結(jié)果是 NaN;
  • 如果被除數(shù)是有限大的數(shù)值而除數(shù)是零,則結(jié)果是 NaN;
  • 如果是 Infinity 被 Infinity 除,則結(jié)果是 NaN;
  • 如果被除數(shù)是有限大的數(shù)值而除數(shù)是無窮大的數(shù)值,則結(jié)果是被除數(shù);
  • 如果被除數(shù)是零,則結(jié)果是零;
  • 如果有一個(gè)操作數(shù)不是數(shù)值,則在后臺調(diào)用 Number() 將其轉(zhuǎn)換為數(shù)值,然后再應(yīng)用以上規(guī)則。

加性操作符

加法

加法操作符(+)

如果兩個(gè)操作符都是數(shù)值,執(zhí)行常規(guī)的加法計(jì)算,然后根據(jù)下列規(guī)則返回結(jié)果:

  • 如果有一個(gè)操作數(shù)是 NaN,則結(jié)果是 NaN;
  • 如果是 Infinity 加 Infinity,則結(jié)果是 Infinity;
  • 如果是 -Infinity 加 -Infinity,則結(jié)果是 -Infinity;
  • 如果是 Infinity 加 -Infinity,則結(jié)果是 NaN;
  • 如果是 +0 加 +0,則結(jié)果是 +0;
  • 如果是 -0 加 -0,則結(jié)果是 -0;
  • 如果是 +0 加 -0,則結(jié)果是 +0。

如果有一個(gè)操作符是字符串,就要應(yīng)用如下規(guī)則:

  • 如果兩個(gè)操作數(shù)都是字符串,則將第二個(gè)操作數(shù)與第一個(gè)操作數(shù)拼接起來;
  • 如果只有一個(gè)操作數(shù)是字符串,則將另一個(gè)操作數(shù)轉(zhuǎn)換為字符串,然后再將兩個(gè)字符串拼接起來。

如果有一個(gè)操作數(shù)是對象、數(shù)值、布爾值,則調(diào)用它們的 toString() 方法取得相應(yīng)的字符串值,然后再應(yīng)用關(guān)于字符串的規(guī)則。

對于 undefined 和 null,則分別調(diào)用 String() 函數(shù)并取得字符串“undefined”和“null”。


減法

減法操作符(-)

一樣需要遵循如下特殊規(guī)則:

  • 如果兩個(gè)操作符都是數(shù)值,則執(zhí)行常規(guī)的算術(shù)減法操作并返回結(jié)果;
  • 如果有一個(gè)操作數(shù)是 NaN,則結(jié)果是 NaN;
  • 如果是 Infinity 減 Infinity,則結(jié)果是 NaN;
  • 如果是 -Infinity 減 -Infinity,則結(jié)果是 NaN;
  • 如果是 Infinity 減 -Infinity,則結(jié)果是 Infinity;
  • 如果是 -Infinity 減 Infinity,則結(jié)果是 -Infinity;
  • 如果是 +0 減 +0,則結(jié)果是 +0;
  • 如果是 -0 減 +0,則結(jié)果是 -0;
  • 如果是 -0 減 -0,則結(jié)果是 +0;
  • 如果有一個(gè)操作數(shù)是字符串、布爾值、null 或 undefined,則先在后臺調(diào)用 Number() 函數(shù)將其轉(zhuǎn)換為數(shù)值,然后再根據(jù)前面規(guī)則執(zhí)行減法計(jì)算。如果轉(zhuǎn)換結(jié)果是 NaN,則減法的結(jié)果就是 NaN;
  • 如果有一個(gè)操作數(shù)是對象,則調(diào)用對象的 valueOf() 方法以取得表示該對象的數(shù)值。如果得到的值是 NaN,則減法的結(jié)果就是 NaN。如果對象沒有 valueOf() 方法,則調(diào)用其 toString() 方法并將得到的字符轉(zhuǎn)換為數(shù)值。

關(guān)系操作符

小于(<)、大于(>)、小于等于(<=)和大于等于(>=)這幾個(gè)關(guān)系操作符用于對兩個(gè)值進(jìn)行比較,這幾個(gè)操作符都返回一個(gè)布爾值。

當(dāng)關(guān)系操作符的操作數(shù)使用了非數(shù)值時(shí),要進(jìn)行數(shù)據(jù)轉(zhuǎn)換或完成某些操作。以下就是其規(guī)則:

  • 如果兩個(gè)操作數(shù)都是數(shù)值,則執(zhí)行數(shù)值比較;
  • 如果兩個(gè)操作數(shù)都是字符串,則比較兩個(gè)字符串對應(yīng)的字符編碼值;
  • 如果一個(gè)操作數(shù)是數(shù)值,則將另一個(gè)操作數(shù)轉(zhuǎn)換為一個(gè)數(shù)值,然后執(zhí)行數(shù)值比較;
  • 如果一個(gè)操作數(shù)是對象,則調(diào)用這個(gè)對象的 valueOf() 方法,用得到的結(jié)果按照前面規(guī)則比較。如果對象沒有 valueOf() 方法,則調(diào)用 toString() 方法,并用得到的結(jié)果根據(jù)前面規(guī)則比較;
  • 如果一個(gè)操作數(shù)是布爾值,則先將其轉(zhuǎn)換為數(shù)值,然后再比較。

相等操作符

ES 提供兩組操作符:相等和不相等——先轉(zhuǎn)換再比較,全等和不全等——僅比較不轉(zhuǎn)換。

相等和不相等

相等操作符由兩個(gè)等于號(==)表示,如果兩個(gè)操作數(shù)相等,返回 true。

不相等操作符由嘆號后跟等于號(!=)表示,如果兩個(gè)操作數(shù)不相等,返回 false。

這兩個(gè)操作符都會先轉(zhuǎn)換操作數(shù)(通常稱為強(qiáng)制轉(zhuǎn)型),然后比較它們的相等性。

在轉(zhuǎn)換不同數(shù)據(jù)類型時(shí),遵循下列規(guī)則:

  • 如果有一個(gè)操作數(shù)是布爾值,則在比較相等性之前先將其轉(zhuǎn)換為數(shù)值,false 轉(zhuǎn)換為 0,true 轉(zhuǎn)換為 1;
  • 如果一個(gè)操作數(shù)是字符串,另一個(gè)操作數(shù)是數(shù)值,在比較相等性之前先將字符串轉(zhuǎn)換為數(shù)值;
  • 如果一個(gè)操作數(shù)是對象,另一個(gè)操作數(shù)不是,則調(diào)用 valueOf() 方法,用得到的基本類型值按照前面規(guī)則比較;

這兩個(gè)操作符在比較時(shí)遵循下列規(guī)則:

  • null 和 undefined 是相等的;
  • 比較相等性之前,不能將 null 和 undefined 轉(zhuǎn)換成其他任何值;
  • 如果有一個(gè)操作數(shù)是 NaN,則相等操作符返回 false,而不相等操作符返回 true。注意:即使兩個(gè)操作數(shù)都是
  • 如果兩個(gè)操作數(shù)都是對象,則比較它們是不是同一個(gè)對象。如果兩個(gè)操作數(shù)都指向同一個(gè)對象,則相等操作符返回 true;否則返回 false。

全等和不全等

全等操作符由 3 個(gè)等于號(===)表示,它只在兩個(gè)操作數(shù)未經(jīng)轉(zhuǎn)換就相等的情況下返回 true。

不全等操作符由一個(gè)嘆號后跟兩個(gè)等于號(!==)表示,它在兩個(gè)操作數(shù)未經(jīng)轉(zhuǎn)換就不相等的情況下返回 true。

注意:null == undefined 返回 true,因?yàn)樗鼈兪穷愃频闹?;?null === undefined 會返回 false。


條件操作符

條件操作符遵循與 Java 中的條件操作符相同的語法形式。


賦值操作符

簡單的賦值操作符由等于號(=)表示,其作用就是把右側(cè)的值賦給左側(cè)的變量。

如果在等于號(=)前面再添加乘性操作符、加性操作符或位操作符,就可以完成復(fù)合賦值操作。

每個(gè)主要算術(shù)操作符都有對應(yīng)的復(fù)合賦值操作符,這些操作符如下:

  • 乘/賦值(*=);
  • 除/賦值(/=);
  • 模/賦值(%=);
  • 加/賦值(+=);
  • 減/賦值(-=);
  • 左移/賦值(<<=);
  • 有符號右移/賦值(>>=);
  • 無符號右移/賦值(>>>=)。

逗號操作符

使用逗號操作符可以在一條語句中執(zhí)行多個(gè)操作。

逗號操作符多用于聲明多個(gè)變量,還可以用于賦值。用于賦值時(shí),逗號操作符總會返回表達(dá)式中的最后一項(xiàng)。


語句

語句通常使用一或多個(gè)關(guān)鍵字來完成給定任務(wù)。

if語句

語法如下:

if(condition){
    statement1
}else{
    statement2
}

其中的 condition(條件)可以是任意表達(dá)式。如果對 condition 求值的結(jié)果為 true,則執(zhí)行 statement1(語句1),否則執(zhí)行 statement2(語句2)。


do-while語句

do-while 語句是一種后測試循環(huán)語句,即只有在循環(huán)體中的代碼執(zhí)行之后,才會測試出口條件。換句話說,在對條件表達(dá)式求值之前,循環(huán)體內(nèi)的代碼至少會被執(zhí)行一次。語法如下:

do{
    statement
}while(expression);

while語句

while 語句屬于前測試循環(huán)語句,也就是說,在循環(huán)體內(nèi)的代碼被執(zhí)行之前,就會對出口條件求值。因此,循環(huán)體內(nèi)的代碼有可能永遠(yuǎn)不會被執(zhí)行。語法如下:

while(expression){
    statement
}

for語句

for 語句也是一種前測試循環(huán)語句,但它具有在執(zhí)行循環(huán)之前初始化變量和定義循環(huán)后要執(zhí)行的代碼能力。語法如下:

for(initialization;expression;post-loop-expression){
    statement
}

在 for 循環(huán)的變量初始化表達(dá)式中,也可以不使用 var 關(guān)鍵字,該變量的初始化可以在外部執(zhí)行。

for 語句中的初始化表達(dá)式、控制表達(dá)式和循環(huán)后表達(dá)式都是可選的,如果將三個(gè)表達(dá)式全部省略,就會創(chuàng)建一個(gè)無限循環(huán)。


for-in語句

for-in 語句是一種精準(zhǔn)的迭代語句,可以用來枚舉對象的屬性。語法如下:

for(property in expression){
    statement
}

如果表示要迭代的對象的變量值為 null 或 undefined,for-in 語句會拋出錯(cuò)誤。ES5 更正了這一行為,對這種情況不再拋出錯(cuò)誤,而只是不執(zhí)行循環(huán)體。為了保證最大限度的兼容性,建議在使用 for-in 循環(huán)之前,先檢測該對象的值不是 null 或 undefined。


label語句

使用 label 語句可以在代碼中添加標(biāo)簽,以便將來使用。語法如下:

label: statement

示例:

start:for(var i = 0; i < count; i++){
    alert(i);
}

break和continue語句

break 和 continue 語句用于在循環(huán)中精確地控制代碼的執(zhí)行。

break 語句會立即退出循環(huán),強(qiáng)制繼續(xù)執(zhí)行循環(huán)后面的語句。continue 語句雖然也是立即退出循環(huán),但退出循環(huán)后會從循環(huán)的頂部繼續(xù)執(zhí)行。


with語句

with 語句的作用是將代碼的作用域設(shè)置到一個(gè)特定的對象中。語法如下:

with(expression)   statement;

定義 with 語句的目的主要是為了簡化多次編寫同一個(gè)對象的工作,實(shí)例:

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;

以上代碼可以使用 with 語句改寫成如下:

with(location){
    var qs = search.substring(1);
    var hostName = hostname;
    var url = href;
}

注意:在嚴(yán)格模式下不允許使用 with 語句,否則將視為語法錯(cuò)誤。

由于大量使用 with 語句會導(dǎo)致性能下降,同時(shí)也會給調(diào)試代碼造成困難,因此在開發(fā)大型應(yīng)用程序時(shí),不建議使用 with 語句。


switch語句

switch 語句與 if 語句的關(guān)系最為密切。語法如下:

switch(expression){
    case value:statement
        break;
    case value:statement
        break;
    case value:statement
        break;
    default:statement
}

含義為:如果表達(dá)式等于這個(gè)值(value),則執(zhí)行后面的語句。而 break 關(guān)鍵字會導(dǎo)致代碼執(zhí)行流跳出 switch 語句。如果省略 break,就會導(dǎo)致執(zhí)行完當(dāng)前 case 后,繼續(xù)執(zhí)行下一個(gè) case。最后的 default 關(guān)鍵字則用于在表達(dá)式不匹配前面任何一種情形時(shí),執(zhí)行機(jī)動代碼(也相當(dāng)于 else 語句)。

switch 語句在比較值時(shí)使用的是全等操作符,因此不會發(fā)生類型轉(zhuǎn)換。


函數(shù)

通過函數(shù)可以封裝任意多條語句,而且可以在任何地方、任何時(shí)候調(diào)用執(zhí)行。

ES 中的函數(shù)使用 function 關(guān)鍵字來聲明,后跟一組參數(shù)以及函數(shù)體。語法如下:

function functionName(arg0,arg1,...,argN){
    statements
}

ES 中的函數(shù)在定義時(shí)不必指定是否返回值。實(shí)際上,任何函數(shù)在任何時(shí)候都可以通過 return 語句后跟要返回的值來實(shí)現(xiàn)返回值。示例如下:

function sum(num1,num2){
    return num1 + num2;
}

這個(gè) sum() 函數(shù)的作用是把兩個(gè)值加起來返回一個(gè)結(jié)果。

調(diào)用這個(gè)函數(shù)的代碼如下:

var result = sum(5,10);

這個(gè)函數(shù)會在執(zhí)行完 return 語句之后停止并立即退出,因此位于 return 之后的任何代碼將不會被執(zhí)行。

另外,return 語句也可以不帶有任何返回值。函數(shù)在停止執(zhí)行后將返回 undefined 值,這種用法一般用在需要提前停止函數(shù)執(zhí)行而又不需要返回值的情況下使用。

嚴(yán)格模式對函數(shù)有一些限制,如下:

  • 不能把函數(shù)命名為 eval 或 arguments;
  • 不能把參數(shù)命名為 eval 或 arguments;
  • 不能出現(xiàn)兩個(gè)命名參數(shù)同名的情況。
    如發(fā)生以上情況,將導(dǎo)致語法錯(cuò)誤,無法執(zhí)行。

理解參數(shù)

在函數(shù)體內(nèi)可以通過 arguments 對象來訪問這個(gè)參數(shù)數(shù)組,從而獲取傳遞給函數(shù)的每一個(gè)參數(shù)。

ES 函數(shù)一個(gè)重要特定:命名的參數(shù)只提供便利,但不是必需的。

沒有傳遞值的命名參數(shù)將自動被賦予 undefined 值。

ES 中的所有參數(shù)傳遞的都是值,不可能通過引用傳遞參數(shù)。


沒有重載

ES 函數(shù)不能像傳統(tǒng)意義上那樣實(shí)現(xiàn)重載。ES 函數(shù)沒有簽名,因?yàn)槠鋮?shù)是由包含零或多個(gè)值的數(shù)組來表示的。而沒有函數(shù)簽名,真正的重載是不可能做到的。

如果在 ES 中定義了兩個(gè)名字相同的函數(shù),則該名字只屬于后定義的函數(shù)。


小結(jié)

下面簡要總結(jié) ES 中的基本要素

  • ES 中的基本數(shù)據(jù)類型包括 Undefined、Null、Boolean、Numbe 和 String。
  • ES 沒有為整數(shù)和浮點(diǎn)數(shù)值分別定義不同的數(shù)據(jù)類型,Number 類型可以用于表示所有數(shù)值。
  • ES 中有一種復(fù)雜的數(shù)據(jù)類型:Object 類型,該類型是所有對象的基礎(chǔ)類型。
  • 嚴(yán)格模式為這門語言中容易出錯(cuò)的地方施加了限制。
  • ES 提供了很多基本操作符:算術(shù)操作符、布爾操作符、關(guān)系操作符、相等操作符及賦值操作符等等。
  • ES 中有很多流控制語句,如:if 語句、for 語句和 switch 語句等等。
  • 無須指定函數(shù)的返回值,因?yàn)?ES 函數(shù)都可以在任何時(shí)候返回任何值。
  • 未指定返回值的函數(shù)返回的是一個(gè)特殊的 undefined 值。
  • ES 中沒有函數(shù)簽名的概念,因?yàn)槠浜瘮?shù)參數(shù)是以一個(gè)包含零或多個(gè)值的數(shù)組的形式傳遞的。
  • 可以向 ES 函數(shù)傳遞任意數(shù)量的參數(shù),并可以通過 arguments 對象來訪問這些參數(shù)。
  • 由于不存在函數(shù)簽名,ES 函數(shù)不能重載。

變量、作用域和內(nèi)存問題

基本類型和引用類型的值

ES變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值

基本類型值指的是簡單的數(shù)據(jù)段,而引用類型值指那些可能由多個(gè)值構(gòu)成的對象。

引用類型的值是保存在內(nèi)存中的對象。JavaScript不允許直接訪問內(nèi)存中的位置,也就是說不能直接操作對象的內(nèi)存空間。在操作對象時(shí),實(shí)際上是在操  作對象的引用而不是實(shí)際的對象。因此,引用類型的值是按引用訪問的。


動態(tài)的屬性

定義基本類型值和引用類型值的方式是類似的:創(chuàng)建一個(gè)變量并為該變量賦值。

我們不能給基本類型的值添加屬性,只能給引用類型值動態(tài)地添加屬性。


復(fù)制變量值

除了保存的方式不同之外,在從一個(gè)變量向另一個(gè)變量復(fù)制基本類型值和引用類型值時(shí),也存在不同。如果從一個(gè)變量向另一個(gè)變量復(fù)制基本類型的值,會在變量對象上創(chuàng)建一個(gè)新值,然后把該值復(fù)制到為新變量分配的位置上,例如:

var num1 = 5;
var num2 = num1;

以上代碼中,num1中保存的值為5.當(dāng)使用num1的值來初始化num2時(shí),num2中也保存了值5.但num2中的5與num1的5是完全獨(dú)立的,該值只是num1中5的一個(gè)副本。此后,這兩個(gè)變量可以參與任何操作而不會相互影響。

當(dāng)從一個(gè)變量向另一個(gè)變量復(fù)制引用類型的值時(shí),同樣也會將存儲在變量對象中的值復(fù)制一份到為新變量分配的空間中。不同的是,這個(gè)值的副本實(shí)際上是一個(gè)指針,而這個(gè)指針指向存儲在堆中的一個(gè)對象。復(fù)制操作結(jié)束后,兩個(gè)變量實(shí)際上將引用同一個(gè)對象。因此,改變其中一個(gè)變量,就會音響另一個(gè)變量,例如:

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "zww"
alert(obj2.name);    //"zww"

以上代碼中,變量obj1保存了一個(gè)對象的新實(shí)例。然后這個(gè)值被復(fù)制到了obj2中。obj1和obj2都指向同一個(gè)對象。這樣,當(dāng)為obj1添加name屬性后,可以通過obj2來訪問這個(gè)屬性。


傳遞參數(shù)

ES中所有函數(shù)的參數(shù)都是按值傳遞的。也就是說,把函數(shù)外部的值復(fù)制給函數(shù)內(nèi)部的參數(shù),就和把值從一個(gè)變量復(fù)制到另一個(gè)變量一樣。例子:

function addTen(num){
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
alert(count);    //20,沒有變化
alert(result);    //30

以上代碼中,函數(shù)addTen()有一個(gè)參數(shù)num,而參數(shù)實(shí)際上是函數(shù)的局部變量。在調(diào)用函數(shù)時(shí),變量count作用參數(shù)被傳遞給函數(shù),這個(gè)變量值為20。于是數(shù)值20被復(fù)制給參數(shù)num以便在addTen()中使用。在函數(shù)內(nèi)部,參數(shù)num值被加上了10,這一變化不會影響函數(shù)外部的count變量。


檢測類型

要檢測一個(gè)變量是不是基本數(shù)據(jù)類型,typeof操作符是最佳的工具。

typeof操作符是確定一個(gè)變量是字符串、數(shù)值、布爾值,還是undefined的最佳工具,如果變量值是null或?qū)ο?,則會返回"object"。

var s = "zww";
var b = true;
var i = 19;
var u;
var n = null;
var o = new Object();
alert(typeof s);    //string
alert(typeof b);    //boolean
alert(typeof i);    //number
alert(typeof u);    //undefined
alert(typeof n);    //object
alert(typeof o);    //object

因此,ES提供了instanceof操作符,語法如下:

result = variable instanceof constructor

如果變量是給定引用類型的實(shí)例,那么instanceof操作符就會返回true。


執(zhí)行環(huán)境及作用域

執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù),決定了它們各自的行為。每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對象,環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對象中。

每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的環(huán)境就會被推入一個(gè)環(huán)境棧中。而在函數(shù)執(zhí)行之后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。

當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會創(chuàng)建變量對象的一個(gè)作用域鏈。作用域鏈的用途是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。


延長作用域鏈

雖然執(zhí)行環(huán)境的類型總共只有兩種:全局和局部(函數(shù)),但還是有其他辦法延長作用域鏈的。因?yàn)橛行┱Z句可以在作用域鏈的前端臨時(shí)增加一個(gè)變量對象,該變量對象會在代碼執(zhí)行后被移除。在兩種情況下會發(fā)生這種情況。具體的說就是當(dāng)執(zhí)行流進(jìn)入下列任何一個(gè)語句時(shí),作用域鏈就會得到加長:

  • try-catch語句的catch塊;
  • with語句。

這兩個(gè)語句都會在作用域鏈的前端添加一個(gè)變量對象。對with語句來說,會將指定的對象添加到作用域鏈中。對catch來說,會創(chuàng)建一個(gè)新的變量對象,其中包含的是被拋出的錯(cuò)誤對象的聲明。


沒有塊級作用域

聲明變量

使用var聲明的變量會自動被添加到最接近的環(huán)境中。在函數(shù)內(nèi)部,最接近的環(huán)境就是函數(shù)的局部環(huán)境;在with語句中,最接近的環(huán)境是函數(shù)環(huán)境。如果初始化變量時(shí)沒有使用var聲明,該變量會自動被添加到全局環(huán)境。例如:

function add(num1,num2){
    var sum = num1 + num2;
    return sum;
}
var result = add(10,20);    //30
alert(sum);    //由于sum不是有效的變量,因此會導(dǎo)致錯(cuò)誤

以上代碼中,函數(shù)add()定義了一個(gè)名為sum的局部變量,該變量包含加法的操作結(jié)果。雖然結(jié)果值從函數(shù)中返回了,但變量sum在函數(shù)外部是訪問不到的。如果省略例子中var關(guān)鍵字,那么add()執(zhí)行完畢后,sum也將可以訪問到:

function add(num1,num2){
    sum = num1 + num2;
    return sum;
}
var result = add(10,20);    //30
alert(sum);    //30

查詢標(biāo)識符

當(dāng)在某個(gè)環(huán)境中為了讀取或?qū)懭攵靡粋€(gè)標(biāo)識符時(shí),必須通過搜索來確定該標(biāo)識符實(shí)際代表什么。搜索過程從作用域鏈的前端開始,向上逐級查詢與給定名字匹配的標(biāo)識符。如果在局部環(huán)境中找到了該標(biāo)識符,就停止搜索,變量就緒。如果在局部環(huán)境中沒有找到,則繼續(xù)沿作用域鏈向上搜索。搜索過程將一直追溯到全局環(huán)境的變量對象。如果在全局環(huán)境中沒有找到標(biāo)識符,則意味著該變量尚未聲明。


垃圾收集

JavaScript具有自動垃圾收集機(jī)制,也就是說,執(zhí)行環(huán)境會負(fù)責(zé)管理代碼執(zhí)行過程中使用的內(nèi)存。

標(biāo)記清除

JavaScript中最常用的垃圾收集方式是標(biāo)記清除。當(dāng)變量進(jìn)入環(huán)境時(shí),就將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”。從邏輯上講,永遠(yuǎn)不能釋放進(jìn)入環(huán)境的變量所占用的內(nèi)存,因?yàn)橹灰獔?zhí)行流進(jìn)入相應(yīng)的環(huán)境,就可能會用到它們。而當(dāng)變量離開環(huán)境時(shí),則講其標(biāo)記為“離開環(huán)境”。


引用計(jì)數(shù)

另一種不太常見的垃圾收集策略叫引用計(jì)數(shù)。含義是跟蹤記錄每個(gè)值被引用的次數(shù)。當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型值賦給該變量時(shí),則這個(gè)值的引用次數(shù)就是1。如果同一個(gè)值又被賦給另一個(gè)變量,則該值的引用次數(shù)加1。相反,如果包含對這個(gè)值引用的變量又取得另外一個(gè)值,則這個(gè)值的引用次數(shù)減1。當(dāng)這個(gè)值的引用次數(shù)變?yōu)?時(shí),則說明沒有辦法再訪問這個(gè)值了,因而就可以將其占用的內(nèi)存空間回收回來。這樣,當(dāng)垃圾收集器下次再運(yùn)行時(shí),它就會釋放那些引用次數(shù)為零的值所占用的內(nèi)存。


性能問題

垃圾收集器是周期性運(yùn)行的。

IE的垃圾收集器是根據(jù)內(nèi)存分配量運(yùn)行的,具體一點(diǎn)說就是256個(gè)變量、4096個(gè)對象(或數(shù)組)字面量和數(shù)組元素(slot)或者64KB的字符串,達(dá)到上述任何一個(gè)臨界值,垃圾收集器就會運(yùn)行。

在IE中,調(diào)用window.CollectGarbage()方法會立即執(zhí)行垃圾收集。


管理內(nèi)存

JavaScript在進(jìn)行內(nèi)存管理及垃圾收集時(shí),最主要的一個(gè)問題是,分配給web瀏覽器的可用內(nèi)存數(shù)量通常要比分配給桌面應(yīng)用程序的少。這樣做的目的主要是出于安全方面考慮,目的是防止運(yùn)行JavaScript的網(wǎng)頁耗盡全部系統(tǒng)內(nèi)存而導(dǎo)致系統(tǒng)崩潰。內(nèi)存限制問題不僅會影響給變量分配內(nèi)存,同時(shí)還會影響調(diào)用棧以及在一個(gè)線程中能夠同時(shí)執(zhí)行的語句數(shù)量。

因此,確保占用最少的內(nèi)存可以讓頁面獲得更好的性能。而優(yōu)化內(nèi)存占用的最佳方式,就是為執(zhí)行中的代碼只保存必要的數(shù)據(jù)。一旦數(shù)據(jù)不再有用,最好通過將其值設(shè)置為null來釋放其引用,這個(gè)做法叫做解除引用。這一做法適用于大多數(shù)全局變量和全局對象的屬性。局部變量會在它們離開執(zhí)行環(huán)境時(shí)自動被解除引用。


小結(jié)

JavaScript變量可以用來保存兩種類型的值:基本類型值和引用類型值。

基本類型值和引用類型值具有以下特點(diǎn):

  • 基本類型值在內(nèi)存中占據(jù)固定大小的空間,因此被保存在棧內(nèi)存中;
  • 從一個(gè)變量向另一個(gè)變量復(fù)制基本類型的值,會創(chuàng)建這個(gè)值的一個(gè)副本;
  • 引用類型的值是對象,保存在堆內(nèi)存中;
  • 包含引用類型值得變量實(shí)際上包含的并不是對象本身,而是一個(gè)指向該對象的指針;
  • 從一個(gè)變量向另一個(gè)變量復(fù)制引用類型的值,復(fù)制的其實(shí)是指針,因此兩個(gè)變量最終都指向同一個(gè)對象;
  • 確定一個(gè)值是哪種基本類型可以使用typeof操作符,而確定一個(gè)值是哪種引用類型可以使用instanceof操作符。

所有變量都存在于一個(gè)執(zhí)行環(huán)境(也稱作用域)當(dāng)中,這個(gè)執(zhí)行環(huán)境決定了變量的生命周期,以及哪一部分代碼可以訪問其中的變量。

以下是關(guān)于執(zhí)行環(huán)境的幾點(diǎn)總結(jié):

  • 執(zhí)行環(huán)境有全局執(zhí)行環(huán)境和函數(shù)執(zhí)行環(huán)境之分;
  • 每次進(jìn)入一個(gè)新執(zhí)行環(huán)境,都會創(chuàng)建一個(gè)用于搜索變量和函數(shù)的作用域鏈;
  • 函數(shù)的局部環(huán)境不僅有權(quán)訪問函數(shù)作用域中的變量,而且還有權(quán)訪問其包含(父)環(huán)境,乃至全局環(huán)境;
  • 全局環(huán)境只能訪問在全局環(huán)境中定義的變量和函數(shù),而不能直接訪問局部環(huán)境中的任何數(shù)據(jù);
  • 變量的執(zhí)行環(huán)境有助于確定應(yīng)該何時(shí)釋放內(nèi)存。

JavaScript是一門具有自動垃圾收集機(jī)制的編程語言,開發(fā)人員不必關(guān)心內(nèi)存分配和回收問題,可以對JavaScript的垃圾收集例程做如下總結(jié):

  • 離開作用域的值將被自動標(biāo)記為可以回收,因此將在垃圾收集期間被刪除;
  • “標(biāo)記清除”是目前主流的垃圾收集算法,這種算法思想是給當(dāng)前不使用的值加上標(biāo)記,然后再回收其內(nèi)存;
  • 另一個(gè)垃圾收集算法是“引用計(jì)數(shù)”,這種算法思想是跟蹤記錄所有值被引用的次數(shù)。JavaScript引擎目前都不再使用這種算法;
  • 當(dāng)代碼中存在循環(huán)引用現(xiàn)象時(shí),“引用計(jì)數(shù)”算法就會導(dǎo)致問題;
  • 解除變量的引用不僅有助于消除循環(huán)引用現(xiàn)象,而且對垃圾收集也有好處。為了確保有效地回收內(nèi)存,應(yīng)該及時(shí)解除不再使用的全局對象、全局對象屬性以及循環(huán)引用變量的引用。

引用類型

Object類型

創(chuàng)建Object實(shí)例的兩種方式:

  1. 使用new操作符后跟Object構(gòu)造函數(shù),例如:
var person = new Object();
person.name = "ZWW";
person.age = 22;
  1. 使用對象字面量表示法,例如:
var person = {
    name: "ZWW",
    age: 22
};

在對象字面量中,使用逗號來分隔不同的屬性,并且在最后一個(gè)屬性后面不能添加逗號。

在使用對象字面量時(shí),屬性名也可以使用字符串;如果留空其花括號,則可以定義只包含默認(rèn)屬性和方法的對象。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多