中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript的基礎知識有哪些

發布時間:2021-01-21 09:46:59 來源:億速云 閱讀:205 作者:小新 欄目:web開發

小編給大家分享一下JavaScript的基礎知識有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

一、什么是JavaScript

1-1、JavaScript實現

雖然JavaScript和ECMAScript基本上是同義詞,但JavaScript遠不限于ECMA-262所定義的那樣。完整的JavaScript實現包含:

  • 核心(ECMAScript)

  • 文檔對象模型(DOM)

  • 瀏覽器對象模型(BOM)

Web瀏覽器只是ECMAScript實現可能存在的一種宿主環境(hostenvironment)。宿主環境提供ECMAScript的基準實現和與環境自身交互必需的擴展。擴展(比如DOM)使用ECMAScript核心類型和語法,提供特定于環境的額外功能。其他宿主環境還有服務器端JavaScript平臺Node.js和即將被淘汰的Adobe Flash。
在基本層面,描述這門語言:語法,類型,語句,關鍵字,保留字,操作符,全局對象

ECMAScript只是對實現這個規范描述的所有方面的一門語言的稱
呼。JavaScript實現了ECMAScript,而Adobe ActionScript同樣也實現了
ECMAScript。

1-2、DOM

文檔對象模型(DOM,Document Object Model)是一個應用編程接口(API),用于在HTML中使用擴展的XML。DOM將整個頁面抽象為一組分層節點。HTML或XML頁面的每個組成部分都是一種節
點,包含不同的數據。

DOM通過創建表示文檔的樹,讓開發者可以隨心所欲地控制網頁的內容和結構。使用DOM API,可以輕松地刪除、添加、替換、修改節點。

1-3、BOM

IE3和Netscape Navigator 3提供了瀏覽器對象模型(BOM) API,用于支持訪問和操作瀏覽器的窗口。使用BOM,開發者可以操控瀏覽器顯示頁面之外的部分。而BOM真正獨一無二的地方,當然也是問題最多的地方,就是它是唯一一個沒有相關標準的JavaScript實現。HTML5改變了這個局面,這個版本的HTML以正式規范的形式涵蓋了盡可能多的BOM特性。由于HTML5的出現,之前很多與BOM有關的問題都迎刃而解了。

總體來說,BOM主要針對瀏覽器窗口和子窗口(frame),不過
人們通常會把任何特定于瀏覽器的擴展都歸在BOM的范疇內。下面就是這樣一些擴展:

  • 彈出新瀏覽器窗口的能力;

  • 移動、縮放和關閉瀏覽器窗口的能力;

  • navigator 對象,提供關于瀏覽器的詳盡信息;

  • location 對象,提供瀏覽器加載頁面的詳盡信息;

  • screen 對象,提供關于用戶屏幕分辨率的詳盡信息;

  • performance 對象,提供瀏覽器內存占用、導航行為和時間統

  • 計的詳盡信息;

  • 對cookie的支持;

  • 其他自定義對象,如 XMLHttpRequest 和IE的

  • ActiveXObject

二、HTML中的JavaScript

2-1、script元素

將JavaScript插入HTML的主要方法是使用 script 元素。這
個元素是由網景公司創造出來,并最早在Netscape Navigator 2中實現
的。后來,這個元素被正式加入到HTML規范。 script 元素有下
列8個屬性。

  • async:可選。表示應該立即開始下載腳本,但不能阻止其他頁面動作,比如下載資源或等待其他腳本加載。只對外部腳本文件有效。

  • charset :可選。使用 src 屬性指定的代碼字符集。這個屬性很少使用,因為大多數瀏覽器不在乎它的值。

  • crossorigin :可選。配置相關請求的CORS(跨源資源共享)設置。默認不使用CORS。crossorigin=“anonymous” 配置文件請求不必設置憑據標志。 crossorigin=“use-credentials” 設置憑據標志,意
    味著出站請求會包含憑據。

  • defer :可選。表示在文檔解析和顯示完成后再執行腳本是沒有問題的。只對外部腳本文件有效。在IE7及更早的版本中,對行內腳本也可以指定這個屬性。

  • integrity :可選。允許比對接收到的資源和指定的加密簽名以驗證子資源完整性(SRI,Subresource Intergrity)。如果接收到的資源的簽名與這個屬性指定的簽名不匹配,則頁面會報錯,腳本不會執行。這個屬性可以用于確保內容分發網絡(CDN,Content Delivery Network)不會提供惡意內容。

  • language :廢棄。最初用于表示代碼塊中的腳本語言(如 “JavaScript” 、 “JavaScript1.2” 或 “VBScript” )。大多數瀏覽器都會忽略這個屬性,不應該再使用它。

  • src :可選。表示包含要執行的代碼的外部文件。

  • type :可選。代替 language ,表示代碼塊中腳本語言的內容類型(也稱MIME類型)。

包含在 script 內的代碼會被從上到下解釋

2-2、

使用了 src 屬性的 script 元素不應該再在 script 和 /script 標簽中再包含其他JavaScript代碼。如果兩者都提供的話,則瀏覽器只會下載并執行腳本文件,從而忽略行內代碼。

script 元素的一個最為強大、同時也備受爭議的特性是,它可以包含來自外部域的JavaScript文件。跟 img 元素很像, script 元素的 src 屬性可以是一個完整的URL,而且這個URL指向的資源可以跟包含它的HTML頁面不在同一個域中

2-3、文檔模式

可以使用 doctype 切換文檔模式。最初的文檔模式有兩種:混雜模式(quirks mode)和標準模式(standards mode)。前者讓IE像IE5一樣(支持一些非標準的特性),后者讓IE具有兼容標準的行為。雖然這兩種模式的主要區別只體現在通過CSS渲染的內容方面,但對JavaScript也有一些關聯影響,或稱為副作用。本書會經常提到這些副作用。

IE初次支持文檔模式切換以后,其他瀏覽器也跟著實現了。隨著瀏覽器的普遍實現,又出現了第三種文檔模式:準標準模式(almost
standards mode)。這種模式下的瀏覽器支持很多標準的特性,但是沒有標準規定得那么嚴格。主要區別在于如何對待圖片元素周圍的空白(在表格中使用圖片時最明顯)。

混雜模式在所有瀏覽器中都以省略文檔開頭的 doctype 聲明作為開關。這種約定并不合理,因為混雜模式在不同瀏覽器中的差異非常大,不使用黑科技基本上就沒有瀏覽器一致性可言。

2-4、noscript 元素

針對早期瀏覽器不支持JavaScript的問題,需要一個頁面優雅降級的處理方案。最終, 元素出現,被用于給不支持JavaScript的瀏覽器提供替代內容。雖然如今的瀏覽器已經100%支持JavaScript,但對于禁用JavaScript的瀏覽器來說,這個元素仍然有它的用處。

元素可以包含任何可以出現在 中的HTML元素,

  1. 瀏覽器不支持腳本

  2. 瀏覽器對腳本的支持被關閉

三、語法基礎

3-1、語法

首先要知道的是,ECMAScript中一切都區分大小寫。無論是變量、函數名還是操作符,都區分大小寫。換句話說,變量 test 和變量 Test 是兩個不同的變量。類似地, typeof 不能作為函數名,因為它是一個關鍵字(后面會介紹)。但 Typeof 是一個完全有效的函數名。

3-2、標識符

所謂標識符,就是變量、函數、屬性或函數參數的名稱。標識符可以由一或多個下列字符組成:

  • 第一個字符必須是一個字母、下劃線( _ )或美元符號( $ );

  • 剩下的其他字符可以是字母、下劃線、美元符號或數字。

標識符中的字母可以是擴展ASCII(Extended ASCII)中的字母,也可以是Unicode的字母字符,如à和?(但不推薦使用)。

按照慣例,ECMAScript標識符使用駝峰大小寫形式,即第一個單詞的首字母小寫,后面每個單詞的首字母大寫

3-3、嚴格模式

ECMAScript 5增加了嚴格模式(strict mode)的概念。嚴格模式是一種不同的JavaScript解析和執行模型,ECMAScript 3的一些不規范寫法在這種模式下會被處理,對于不安全的活動將拋出錯誤

3-4、關鍵字與保留字

ECMA-262描述了一組保留的關鍵字,這些關鍵字有特殊用途,比如表示控制語句的開始和結束,或者執行特定的操作

ECMA-262第6版規定的所有關鍵字:

break			  do	      	 in		       	 typeof
case	 		  else	      	 instanceof      var
catch			  export	     new			 void
class			  extends        return			 while
const			  finally	     super			 with
continue	 	  for		     switch			 yield
debugger	 	  function	     this
default			  if		     throw
delete	   		  import try

規范中也描述了一組未來的保留字,同樣不能用作標識符或屬性名。雖然保留字在語言中沒有特定用途,但它們是保留給將來做關鍵字用的

3-5、變量

ECMAScript變量是松散類型的,意思是變量可以用于保存任何類型的數據。每個變量只不過是一個用于保存任意值的命名占位符。有3個關鍵字可以聲明變量: var 、 const 和 let 。其中, var 在CMAScript的所有版本中都可以使用,而 const 和 let 只能在ECMAScript 6及更晚的版本中使用

3-6、var關鍵字

  1. var聲明作用域
    關鍵的問題在于,使用 var 操作符定義的變量會成為包含它的函數的局部變量。比如,使用 var 在一個函數內部定義一個變量,就意味著該變量將在函數退出時被銷毀

  2. var 聲明提升
    使用 var 時,下面的代碼不會報錯。這是因為使用這個關鍵字聲明的變量會自動提升到函數作用域頂部

3-7、let 聲明

let 跟 var 的作用差不多,但有著非常重要的區別。最明顯的區別是, let 聲明的范圍是塊作用域,而 var 聲明的范圍是函數作用域。

  1. 暫時性死區
    let 與 var 的另一個重要的區別,就是 let 聲明的變量不會在作用域中被提升。

  2. 全局聲明
    與 var 關鍵字不同,使用 let 在全局作用域中聲明的變量不會成為 window 對象的屬性( var 聲明的變量則會)

  3. 條件聲明
    在使用 var 聲明變量時,由于聲明會被提升,JavaScript引擎會自動將多余的聲明在作用域頂部合并為一個聲明。因為 let 的作用域是塊,所以不可能檢查前面是否已經使用 let 聲明過同名變量,同時也就不可能在沒有聲明的情況下聲明它

  4. for 循環中的 let 聲明
    在 let 出現之前, for 循環定義的迭代變量會滲透到循環體外部

  5. const 聲明
    const 的行為與 let 基本相同,唯一一個重要的區別是用它聲明變量時必須同時初始化變量,且嘗試修改 const 聲明的變量會導致運行時錯誤。

3-8、聲明風格及最佳實踐

ECMAScript 6增加 let 和 const 從客觀上為這門語言更精確地聲明作用域和語義提供了更好的支持。行為怪異的 var 所造成的各種問題,已經讓JavaScript社區為之苦惱了很多年。隨著這兩個新關鍵字的出現,新的有助于提升代碼質量的最佳實踐也逐漸顯現。

  1. 不使用 var
    有了 let 和 const ,大多數開發者會發現自己不再需要 var了。限制自己只使用 let 和 const 有助于提升代碼質量,因為變量有了明確的作用域、聲明位置,以及不變的值。

  2. const 優先, let 次之
    使用 const 聲明可以讓瀏覽器運行時強制保持變量不變,也可以讓靜態代碼分析工具提前發現不合法的賦值操作。因此,很多開發者認為應該優先使用 const 來聲明變量,只在提前知道未來會有修改時,再使用 let 。這樣可以讓開發者更有信心地推斷某些變量的值永遠不會變,同時也能迅速發現因意外賦值導致的非預期行為。

四、數據類型

ECMAScript有6種簡單數據類型(也稱為原始類型):Undefined 、 Null 、 Boolean 、 Number 、 String 和Symbol 。 Symbol (符號)是ECMAScript 6新增的。還有一種復雜數據類型叫 Object (對象)。 Object 是一種無序名值對的集合。因為在ECMAScript中不能定義自己的數據類型,所有值都可以用上述7種數據類型之一來表示。只有7種數據類型似乎不足以表示全部數據。但ECMAScript的數據類型很靈活,一種數據類型可以當作多種數據類型來使用

4-1、typeof 操作符

因為ECMAScript的類型系統是松散的,所以需要一種手段來確定任意變量的數據類型。 typeof 操作符就是為此而生的。對一個值使用 typeof 操作符會返回下列字符串之一:
“undefined” 表示值未定義;
“boolean” 表示值為布爾值;
“string” 表示值為字符串;
“number” 表示值為數值;
“object” 表示值為對象(而不是函數)或 null ;
“function” 表示值為函數;
“symbol” 表示值為符號。

4-2、Undefined 類型

Undefined 類型只有一個值,就是特殊值 undefined 。當使用 var 或 let 聲明了變量但沒有初始化時,就相當于給變量賦予了 undefined 值

即使未初始化的變量會被自動賦予 undefined 值,但我們仍然建議在聲明變量的同時進行初始化。這樣,當 typeof 返回 “undefined” 時,你就會知道那是因為給定的變量尚未聲明,而不是聲明了但未初始化。

4-3、Null 類型

Null 類型同樣只有一個值,即特殊值 null 。邏輯上講,null 值表示一個空對象指針,這也是給 typeof 傳一個 null 會返回 “object” 的原因

在定義將來要保存對象值的變量時,建議使用 null 來初始化,不要使用其他值。這樣,只要檢查這個變量的值是不是 null 就可以知道這個變量是否在后來被重新賦予了一個對象的引用

用等于操作符( == )比較 null 和 undefined 始終返回true 。但要注意,這個操作符會為了比較而轉換它的操作數。
即使 null 和 undefined 有關系,它們的用途也是完全不一樣的。如前所述,永遠不必顯式地將變量值設置為 undefined 。但null 不是這樣的。任何時候,只要變量要保存對象,而當時又沒有那個對象可保存,就要用 null 來填充該變量。這樣就可以保持null 是空對象指針的語義,并進一步將其與 undefined 區分開來。
null 是一個假值。因此,如果需要,可以用更簡潔的方式檢測它。不過要記住,也有很多其他可能的值同樣是假值。所以一定要明確自己想檢測的就是 null 這個字面值,而不僅僅是假值

4-4、Boolean 類型

Boolean (布爾值)類型是ECMAScript中使用最頻繁的類型之一,有兩個字面值: true 和 false 。這兩個布爾值不同于數值,因此 true 不等于1, false 不等于0

注意:布爾值字面量 true 和 false 是區分大小寫的,因此True 和 False (及其他大小混寫形式)是有效的標識符,但不是布爾值。

4-5、Number 類型

ECMAScript中最有意思的數據類型或許就是 Number 了。Number 類型使用IEEE 754格式表示整數和浮點值(在某些語言中也叫雙精度值)。不同的數值類型相應地也有不同的數值字面量格式

  1. 浮點值
    要定義浮點值,數值中必須包含小數點,而且小數點后面必須至
    少有一個數字。雖然小數點前面不是必須有整數,但推薦加上。

  2. 值的范圍
    由于內存的限制,ECMAScript并不支持表示這個世界上的所有數值。ECMAScript可以表示的最小數值保存在Number.MIN_VALUE 中,這個值在多數瀏覽器中是5e-324;可以表示的最大數值保存在 Number.MAX_VALUE 中,這個值在多數瀏覽器中是1.797 693 134 862 315 7e+308。如果某個計算得到的數值結果超出了JavaScript可以表示的范圍,那么這個數值會被自動轉換為一個特殊的 Infinity (無窮)值。任何無法表示的負數以 -Infinity (負無窮大)表示,任何無法表示的正數以 Infinity (正無窮大)表示。如果計算返回正 Infinity 或負 Infinity ,則該值將不能再進一步用于任何計算。這是因為 Infinity 沒有可用于計算的數值表示形式。要確定一個值是不是有限大(即介于JavaScript能表示的最小值和最大值之間),可以使用 isFinite() 函數

  3. NaN
    有一個特殊的數值叫 NaN ,意思是“不是數值”(Not a Number),用于表示本來要返回數值的操作失敗了(而不是拋出錯誤)。比如,用0除任意數值在其他語言中通常都會導致錯誤,從而中止代碼執行。但在ECMAScript中,0、+0或-0相除會返回NaN

  4. 數值轉換
    有3個函數可以將非數值轉換為數值: Number() 、parseInt() 和 parseFloat() 。 Number() 是轉型函數,可用于任何數據類型。后兩個函數主要用于將字符串轉換為數值。對于同樣的參數,這3個函數執行的操作也不同。

4-6、 NaN

有一個特殊的數值叫 NaN ,意思是“不是數值”(Not aNumber),用于表示本來要返回數值的操作失敗了(而不是拋出錯誤)。

4-7、數值轉換

有3個函數可以將非數值轉換為數值: Number() 、 parseInt() 和 parseFloat() 。 Number() 是轉型函數,可用于任何數據類型。后兩個函數主要用于將字符串轉換為數值。對于同樣的參數,這3個函數執行的操作也不同。Number() 函數基于如下規則執行轉換。布爾值, true 轉換為1, false 轉換為0。
數值,直接返回。null ,返回0。 undefined ,返回 NaN 。

4-8、String 類型

String (字符串)數據類型表示零或多個16位Unicode字符序列。字符串可以使用雙引號(")、單引號(’)或反引號(`)標示,

  1. 字符字面量
    字符串數據類型包含一些字符字面量,用于表示非打印字符或有其他用途的字符

  2. 字符串的特點
    ECMAScript中的字符串是不可變的(immutable),意思是一旦創建,它們的值就不能變了。要修改某個變量中的字符串值,必須先銷毀原始的字符串,然后將包含新值的另一個字符串保存到該變量

  3. 轉換為字符串
    有兩種方式把一個值轉換為字符串。首先是使用幾乎所有值都有的 toString() 方法。這個方法唯一的用途就是返回當前值的字符串等價物

  4. 模板字面量
    ECMAScript 6新增了使用模板字面量定義字符串的能力。與使用單引號或雙引號不同,模板字面量保留換行字符,可以跨行定義字符串

  5. 字符串插值
    模板字面量最常用的一個特性是支持字符串插值,也就是可以在一個連續定義中插入一個或多個值。技術上講,模板字面量不是字符串,而是一種特殊的JavaScript句法表達式,只不過求值后得到的是字符串。模板字面量在定義時立即求值并轉換為字符串實例,任何插入的變量也會從它們最接近的作用域中取值

  6. 模板字面量標簽函數
    模板字面量也支持定義標簽函數(tag function),而通過標簽函數可以自定義插值行為。標簽函數會接收被插值記號分隔后的模板和對每個表達式求值的結果。標簽函數本身是一個常規函數,通過前綴到模板字面量來應用自定義行為,

  7. 原始字符串
    使用模板字面量也可以直接獲取原始的模板字面量內容(如換行符或Unicode字符),而不是被轉換后的字符表示。為此,可以使用默認的 String.raw 標簽函數

五、操作符

ECMA-262描述了一組可用于操作數據值的操作符,包括數學操作符(如加、減)、位操作符、關系操作符和相等操作符等。ECMAScript中的操作符是獨特的,因為它們可用于各種值,包括字符串、數值、布爾值,甚至還有對象。在應用給對象時,操作符通常會調用 valueOf() 和 / 或 toString() 方法來取得可以計算的值。3.5.1 一元操作符只操作一個值的操作符叫一元操作符(unary operator)。一元操作符是ECMAScript中最簡單的操作符。

5-1、一元操作符

  1. 遞增 / 遞減操作符
    遞增和遞減操作符直接照搬自C語言,但有兩個版本:前綴版和后綴版。顧名思義,前綴版就是位于要操作的變量前頭,后綴版就是位于要操作的變量后頭。前綴遞增操作符會給數值加1,把兩個加號( ++ )放到變量前頭即可

2.一元加和減
一元加和減操作符對大多數開發者來說并不陌生,它們在ECMAScript中跟在高中數學中的用途一樣。一元加由一個加號( + )表示,放在變量前頭,對數值沒有任何影響

5-2、位操作符

  1. 按位非
    按位非操作符用波浪符( ~ )表示,它的作用是返回數值的一補數。按位非是ECMAScript中為數不多的幾個二進制數學操作符之一

  2. 按位與
    按位與操作符用和號( & )表示,有兩個操作數。本質上,按位與就是將兩個數的每一個位對齊,然后基于真值表中的規則,對每一位執行相應的與操作。

  3. 按位或
    按位或操作符用管道符( | )表示,同樣有兩個操作數。

  4. 按位異或
    按位異或用脫字符( ^ )表示,同樣有兩個操作數

  5. 左移
    左移操作符用兩個小于號( << )表示,會按照指定的位數將數值的所有位向左移動。比如,如果數值2(二進制10)向左移5位,就會得到64(二進制1000000)

  6. 有符號右移
    有符號右移由兩個大于號( >> )表示,會將數值的所有32位都向右移,同時保留符號(正或負)。有符號右移實際上是左移的逆運算

  7. 無符號右移
    無符號右移用3個大于號表示( >>> ),會將數值的所有32位都向右移。對于正數,無符號右移與有符號右移結果相同

5-3、布爾操作符

  1. 邏輯非
    邏輯非操作符由一個嘆號( ! )表示,可應用給ECMAScript中的任何值。這個操作符始終返回布爾值,無論應用到的是什么數據類型。邏輯非操作符首先將操作數轉換為布爾值,然后再對其取反

  2. 邏輯與
    邏輯與操作符由兩個和號( && )表示,應用到兩個值

  3. 邏輯或
    邏輯或操作符由兩個管道符( || )表示

5-4、乘性操作符

  1. 乘法操作符
    乘法操作符由一個星號( * )表示,可以用于計算兩個數值的乘積。

  2. 除法操作符
    除法操作符由一個斜杠( / )表示,用于計算第一個操作數除以第二個操作數的商

  3. 取模操作符

  • 取模(余數)操作符由一個百分比符號( % )表示

  • 如果操作數是數值,則執行常規除法運算,返回余數。

  • 如果被除數是無限值,除數是有限值,則返回 NaN 。

  • 如果被除數是有限值,除數是0,則返回 NaN 。

  • 如果是 Infinity 除以 Infinity ,則返回 NaN 。

  • 如果被除數是有限值,除數是無限值,則返回被除數。

  • 如果被除數是0,除數不是0,則返回0。

  • 如果有不是數值的操作數,則先在后臺用 Number() 函數將其轉換為數值,然后再應用上述規則。

六、語句

ECMA-262描述了一些語句(也稱為流控制語句),而ECMAScript中的大部分語法都體現在語句中。語句通常使用一或多個關鍵字完成既定的任務。語句可以簡單,也可以復雜。簡單的如告訴函數退出,復雜的如列出一堆要重復執行的指令。

6-1、do-while 語句

do-while 語句是一種后測試循環語句,即循環體中的代碼執
行后才會對退出條件進行求值。換句話說,循環體內的代碼至少執行
一次

6-2、while 語句

while 語句是一種先測試循環語句,即先檢測退出條件,再執行循環體內的代碼。因此, while 循環體內的代碼有可能不會執行

七、函數

函數對任何語言來說都是核心組件,因為它們可以封裝語句,然后在任何地方、任何時間執行。ECMAScript中的函數使用function 關鍵字聲明,后跟一組參數,然后是函數體。

ECMAScript中的函數不需要指定是否返回值。任何函數在任何時間都可以使用 return 語句來返回函數的值,用法是后跟要返回的值

函數 sum() 會將兩個值相加并返回結果。注意,除了 return語句之外沒有任何特殊聲明表明該函數有返回值

嚴格模式對函數也有一些限制:
函數不能以 eval 或 arguments 作為名稱;
函數的參數不能叫 eval 或 arguments ;
兩個函數的參數不能叫同一個名稱。

八、變量,作用域與內存

4-1、原始值與引用值

ECMAScript變量可以包含兩種不同類型的數據:原始值和引用值。原始值(primitive value)就是最簡單的數據,引用值(referencevalue)則是由多個值構成的對象。

在把一個值賦給變量時,JavaScript引擎必須確定這個值是原始值還是引用值。上一章討論了6種原始值: Undefined 、 Null 、Boolean 、 Number 、 String 和 Symbol 。保存原始值的變量是按值(by value)訪問的,因為我們操作的就是存儲在變量中的實際值。

引用值是保存在內存中的對象。與其他語言不同,JavaScript不允許直接訪問內存位置,因此也就不能直接操作對象所在的內存空間。在操作對象時,實際上操作的是對該對象的引用(reference)而非實
際的對象本身。為此,保存引用值的變量是按引用(by reference)訪問的

注意:在很多語言中,字符串是使用對象表示的,因此被認為是引用類型。ECMAScript打破了這個慣例。

  1. 動態屬性
    原始值和引用值的定義方式很類似,都是創建一個變量,然后給它賦一個值。不過,在變量保存了這個值之后,可以對這個值做什么,則大有不同。對于引用值而言,可以隨時添加、修改和刪除其屬性和方法

  2. 復制值
    除了存儲方式不同,原始值和引用值在通過變量復制時也有所不同。在通過變量把一個原始值賦值到另一個變量時,原始值會被復制到新變量的位置。

  • 在把引用值從一個變量賦給另一個變量時,存儲在變量中的值也會被復制到新變量所在的位置。區別在于,這里復制的值實際上是一個指針,它指向存儲在堆內存中的對象。操作完成后,兩個變量實際上指向同一個對象,因此一個對象上面的變化會在另一個對象上反映出來

  1. 傳遞參數
    ECMAScript中所有函數的參數都是按值傳遞的。這意味著函數外的值會被復制到函數內部的參數中,就像從一個變量復制到另一個變量一樣。如果是原始值,那么就跟原始值變量的復制一樣,如果是引用值,那么就跟引用值變量的復制一樣。對很多開發者來說,這一塊可能會不好理解,畢竟變量有按值和按引用訪問,而傳參則只有按值傳遞

在按值傳遞參數時,值會被復制到一個局部變量(即一個命名參數,或者用ECMAScript的話說,就是 arguments 對象中的一個槽位)。在按引用傳遞參數時,值在內存中的位置會被保存在一個局部變量,這意味著對本地變量的修改會反映到函數外部

  1. 確定類型
    前一章提到的 typeof 操作符最適合用來判斷一個變量是否為原始類型。更確切地說,它是判斷一個變量是否為字符串、數值、布爾值或 undefined 的最好方式。如果值是對象或 null ,那么typeof 返回 “object”

按照定義,所有引用值都是 Object 的實例,因此通過instanceof 操作符檢測任何引用值和 Object 構造函數都會返回 true 。類似地,如果用 instanceof 檢測原始值,則始終會返回 false ,因為原始值不是對象。

注意 typeof 操作符在用于檢測函數時也會返回 “function” 。當在Safari(直到Safari 5)和Chrome(直到Chrome 7)中用于檢測正則表達式時,由于實現細節的原因,typeof 也會返回 “function” 。ECMA-262規定,任何實現內部 [[Call]] 方法的對象都應該在 typeof 檢測時返回 “function” 。因為上述瀏覽器中的正則表達式實現了這個方法,所以 typeof 對正則表達式也返回 “function” 。在IE和Firefox中, typeof 對正則表達式返回 “object” 。

4-2、執行上下文與作用域

執行上下文(以上簡稱“上下文”)的概念在JavaScript中是頗為重要的。變量或函數的上下文決定了它們可以訪問哪些數據,以及它們的行為。每個上下文都有一個關聯的變量對象(variable object),而
這個上下文中定義的所有變量和函數都存在于這個對象上。雖然無法通過代碼訪問變量對象,但后臺處理數據會用到它。
全局上下文是最外層的上下文。根據ECMAScript實現的宿主環境,表示全局上下文的對象可能不一樣。在瀏覽器中,全局上下文就是我們常說的 window 對象(第12章會詳細介紹),因此所有通過
var 定義的全局變量和函數都會成為 window 對象的屬性和方法。使用 let 和 const 的頂級聲明不會定義在全局上下文中,但在作用域鏈解析上效果是一樣的。上下文在其所有代碼都執行完畢后會被銷毀,包括定義在它上面的所有變量和函數(全局上下文在應用程序退出前才會被銷毀,比如關閉網頁或退出瀏覽器)。
每個函數調用都有自己的上下文。當代碼執行流進入函數時,函數的上下文被推到一個上下文棧上。在函數執行完之后,上下文棧會彈出該函數上下文,將控制權返還給之前的執行上下文。ECMAScript
程序的執行流就是通過這個上下文棧進行控制的。上下文中的代碼在執行的時候,會創建變量對象的一個作用域鏈(scope chain)。這個作用域鏈決定了各級上下文中的代碼在訪問變量和函數時的順序。代碼正在執行的上下文的變量對象始終位于作用域鏈的最前端。如果上下文是函數,則其活動對象(activationobject)用作變量對象。活動對象最初只有一個定義變量:arguments 。(全局上下文中沒有這個變量。)作用域鏈中的下一個變量對象來自包含上下文,再下一個對象來自再下一個包含上下文。以此類推直至全局上下文;全局上下文的變量對象始終是作用域鏈的最后一個變量對象

  1. 作用域鏈增強
    雖然執行上下文主要有全局上下文和函數上下文兩種( eval()調用內部存在第三種上下文),但有其他方式來增強作用域鏈。某些語句會導致在作用域鏈前端臨時添加一個上下文,這個上下文在代碼
    執行后會被刪除。

  2. 變量聲明
    ES6之后,JavaScript的變量聲明經歷了翻天覆地的變化。直到
    ECMAScript 5.1, var 都是聲明變量的唯一關鍵字。ES6不僅增加了
    let 和 const 兩個關鍵字,而且還讓這兩個關鍵字壓倒性地超越
    var 成為首選。

  • 使用 var 的函數作用域聲明
    在使用 var 聲明變量時,變量會被自動添加到最接近的上下文。在函數中,最接近的上下文就是函數的局部上下文。在with 語句中,最接近的上下文也是函數上下文。如果變量未經聲明就被初始化了,那么它就會自動被添加到全局上下文
    注意:未經聲明而初始化變量是JavaScript編程中一個非常常見的錯誤,會導致很多問題。為此,讀者在初始化變量之前一定要先聲明變量。在嚴格模式下,未經聲明就初始化變量會報錯
    var 聲明會被拿到函數或全局作用域的頂部,位于作用域中所有代碼之前。這個現象叫作“提升”(hoisting)。提升讓同一作用域中的代碼不必考慮變量是否已經聲明就可以直接使用。可是在實踐中,提升也會導致合法卻奇怪的現象,即在變量聲明之前使用變量。

  • 使用 let 的塊級作用域聲明
    ES6新增的 let 關鍵字跟 var 很相似,但它的作用域是塊級的,這也是JavaScript中的新概念。塊級作用域由最近的一對包含花括號 {} 界定。換句話說, if 塊、 while 塊、 function塊,甚至連單獨的塊也是 let 聲明變量的作用域。

  • 使用 const 的常量聲明
    除了 let ,ES6同時還增加了 const 關鍵字。使用 const 聲明的變量必須同時初始化為某個值。一經聲明,在其生命周期的任何時候都不能再重新賦予新值

注意 開發實踐表明,如果開發流程并不會因此而受很大影響,就應該盡可能地多使用 const 聲明,除非確實需要一個將來會重新賦值的變量。這樣可以從根本上保證提前發現重新賦值導致的bug

4-3、垃圾回收

JavaScript是使用垃圾回收的語言,也就是說執行環境負責在代碼執行時管理內存。在C和C++等語言中,跟蹤內存使用對開發者來說是個很大的負擔,也是很多問題的來源。JavaScript為開發者卸下了這個負擔,通過自動內存管理實現內存分配和閑置資源回收。基本思路很簡單:確定哪個變量不會再使用,然后釋放它占用的內存。這個過程是周期性的,即垃圾回收程序每隔一定時間(或者說在代碼執行過程中某個預定的收集時間)就會自動運行。垃圾回收過程是一個近似且不完美的方案,因為某塊內存是否還有用,屬于“不可判定的”問題,意味著靠算法是解決不了的。

我們以函數中局部變量的正常生命周期為例。函數中的局部變量會在函數執行時存在。此時,棧(或堆)內存會分配空間以保存相應的值。函數在內部使用了變量,然后退出。此時,就不再需要那個局部變量了,它占用的內存可以釋放,供后面使用。這種情況下顯然不再需要局部變量了,但并不是所有時候都會這么明顯。垃圾回收程序必須跟蹤記錄哪個變量還會使用,以及哪個變量不會再使用,以便回收內存。如何標記未使用的變量也許有不同的實現方式。不過,在瀏覽器的發展史上,用到過兩種主要的標記策略:標記清理和引用計數。

  1. 標記清理
    JavaScript最常用的垃圾回收策略是標記清理(mark-and-sweep)。當變量進入上下文,比如在函數內部聲明一個變量時,這個變量會被加上存在于上下文中的標記。而不在上下文中的變量,邏輯上講,永遠不應該釋放它們的內存,因為只要上下文中的代碼在運行,就有可能用到它們。當變量離開上下文時,也會被加上離開上下文的標記。
    給變量加標記的方式有很多種。比如,當變量進入上下文時,反轉某一位;或者可以維護“在上下文中”和“不在上下文中”兩個變量列表,可以把變量從一個列表轉移到另一個列表。標記過程的實現并不重要,關鍵是策略。
    垃圾回收程序運行的時候,會標記內存中存儲的所有變量(記住,標記方法有很多種)。然后,它會將所有在上下文中的變量,以及被在上下文中的變量引用的變量的標記去掉。在此之后再被加上標記的變量就是待刪除的了,原因是任何在上下文中的變量都訪問不到它們了。隨后垃圾回收程序做一次內存清理,銷毀帶標記的所有值并收回它們的內存。
    到了2008年,IE、Firefox、Opera、Chrome和Safari都在自己的JavaScript實現中采用標記清理(或其變體),只是在運行垃圾回收的頻率上有所差異。

  2. 引用計數
    另一種沒那么常用的垃圾回收策略是引用計數(referencecounting)。其思路是對每個值都記錄它被引用的次數。聲明變量并給它賦一個引用值時,這個值的引用數為1。如果同一個值又被賦給另一個變量,那么引用數加1。類似地,如果保存對該值引用的變量被其他值給覆蓋了,那么引用數減1。當一個值的引用數為0時,就說明沒辦法再訪問到這個值了,因此可以安全地收回其內存了。垃圾回收程序
    下次運行的時候就會釋放引用數為0的值的內存。引用計數最早由Netscape Navigator 3.0采用,但很快就遇到了嚴重的問題:循環引用。所謂循環引用,就是對象A有一個指針指向對象B,而對象B也引用了對象A。

  • 把變量設置為 null 實際上會切斷變量與其之前引用值之間的關系。當下次垃圾回收程序運行時,這些值就會被刪除,內存也會被回收。
    為了補救這一點,IE9把BOM和DOM對象都改成了JavaScript對象,這同時也避免了由于存在兩套垃圾回收算法而導致的問題,還消除了常見的內存泄漏現象。

  1. 內存泄漏
    寫得不好的JavaScript可能出現難以察覺且有害的內存泄漏問題。在內存有限的設備上,或者在函數會被調用很多次的情況下,內存泄漏可能是個大問題。JavaScript中的內存泄漏大部分是由不合理的引用導致的

以上是“JavaScript的基礎知識有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

龙州县| 新巴尔虎右旗| 灵石县| 保定市| 丰台区| 周至县| 马山县| 黑龙江省| 洛南县| 定远县| 拉孜县| 南汇区| 黎平县| 赫章县| 图木舒克市| 南丰县| 金川县| 绥江县| 林芝县| 青海省| 措勤县| 绵竹市| 壤塘县| 湖南省| 耒阳市| 黄山市| 容城县| 南投市| 商城县| 鞍山市| 天峨县| 崇义县| 栾城县| 鹤壁市| 和田市| 阳江市| 依安县| 定陶县| 景泰县| 抚宁县| 中阳县|