今天好像是情人節?所以最適合物件導向,JavaScript 也有物件,我們也可以隨時物件導向,方便得很,那怎樣才有物件呢?下面告訴你!
1. 陣列
陣列,字面意思就是一堆數的組合,但是它是有順序的,學了陣列就不僅可以儲存一個資料,還可以儲存一堆資料,這就是我們為什麼學了簡單資料型別之後還要學陣列的原因。
1.1 宣告陣列
可以看到,陣列裡面的定義和 python 裡的差不多,也可以儲存不同資料型別。獲取陣列元素也是一樣通過下標獲取,下標從 0 開始,而且 JavaScript 的陣列可以隨意根據下標進行賦值,不管你的陣列長度,因為 JavaScript 的陣列長度是動態的。
1.2 遍歷陣列
遍歷陣列,根據陣列長度可以輕易知道迴圈次數,所以可以使用 for 迴圈,獲取陣列的長度可以通過 length 屬性進行獲取。
這裡有個提高效率的地方,就是在獲取陣列的長度時放在了 for 語句的初始化表示式裡,而不是放在判斷表示式裡,當你這個值需要運算才能獲得的時候,這樣做就可以不用在每次判斷時都需要通過運算獲得,減少運算,也就提高效率了,當然,陣列的長度在這裡只是一個屬性,不需要運算,放不放在初始化表示式都差不多。
1.3 清空陣列
JavaScript 這裡清空陣列簡單粗暴,直接將長度賦值為 0 即可。
1.4 陣列小練習
- 找出陣列中最大的值
這個直接通過遍歷陣列,然後將每個值進行比較即可,很容易。
- 翻轉陣列
這個就是將陣列中的元素前後互相替換,也不多說了。
2. 函式
當我們需要在對多個陣列進行上面的其中練習之一,比如進行尋找最大值,我們總不能每個陣列都各自寫一段尋找最大值的程式碼,否則這樣子的話程式碼的複用性太低了。
函式的出現就是解決這個問題的,函式就是把一段相對獨立的具有特定功能的程式碼抽取出來進行封裝,形成一個獨立的個體。當需要多次使用的時候,我們只需要使用函式名呼叫即可。
2.1 函式的定義
函式定義這裡有兩種方法,如下:
- 使用函式宣告,語法為
- 使用函式表示式,語法為:
上面只是函式的定義而已,並不會去執行,只有你呼叫函式的時候才會去執行。
2.2 函式呼叫
呼叫函式的語法也比較簡單,就是函式加上一個括號就行了。
所以當需要多次使用這段功能的時候,就多次呼叫即可,不需要每次都寫一段相同的程式碼。
2.3 函式引數
不需要多次寫同一段程式碼解決了,但是當有不同的資料內容參與運算時,好像我還需要重複寫呀!就比如前面說的求陣列最大值。這個時候就需要我們的函式引數了,函式引數就是解決這個不確定的資料內容的。當我們需要對不確定資料內容進行操作時,只需要在呼叫函式的時候把資料內容當作引數傳進去即可。
函式的引數定義與呼叫語法:
- 形參:在宣告函式時,有些值是固定的,而有些值不是固定的,對於這些不固定的值,我們可以給它們設定引數,但是這個引數不是具體的值,只是一個形式而已,所以叫做形參
- 實參:在函式宣告設定的形參,我們呼叫函式就需要傳入對應的引數,而這個引數就是實參。
瞭解了這個之後,是不是很容易就可以寫出一個求陣列最大值的函式了?
咦?上面的我都看明白了,但是 return 那個語句又是什麼?return 後面跟的內容就是函式的返回值,當函式執行到這裡的時候就會結束函式並且把該值返回給呼叫處,就相對於一段程式碼執行之後的反饋。所以 return 語句也會常常用於終止函式的執行,還有也可以不寫 return 語句,但是會預設返回 undefined
2.4 函式內部的 arguments 物件
JavaScript 中,函式的內部都有一個 arguments 物件,用來記錄在呼叫函式時所傳進來的引數,可以說是一個偽陣列。
這個物件可以用於當我們需要傳進來的引數個數不確定時就可以使用這個,就比如求一堆數的和。
2.5 匿名函式
匿名函式就是沒有名字的函式,當我們只需要只需要呼叫一次的話就可以使用匿名函式,或者需要回撥函式的時候就會使用匿名函式,至於什麼是回撥函式,以後遇到了就說,匿名函式宣告如下:
這是將匿名函式賦值給一變數,然後可以通過該變數進行呼叫,也可以傳參的,除了這樣子呼叫匿名函式,匿名函式還可以進行自呼叫。
這裡需要注意的是在自呼叫的時候別忘了定義函式的部分需要加括號括起來。這自呼叫的匿名函式就常用於防止全域性被汙染,就是當你寫的程式碼量大了,難免會有些全域性變數會有重名的可能,這時候使用匿名函式自呼叫就可以新開闢了一個作用域,不同作用域的變數就算同名也不怕了,至於具體的後面我也會應用到,到時再詳講。
2.6 函式其他
- 函式也是一種資料型別,可以說是一個物件吧,至於具體的後面再詳講,現在瞭解就好。
- 函式不僅可以作為引數進行傳遞,還可以作為返回值,畢竟函式也是一種資料型別。作為引數傳遞主要就是我們所說的回撥函式,遇到就會說,作為返回值的應用,閉包就是一個應用,也不多說,以後會講。
2.7. 作用域
作用域就是變數可以起作用的範圍,在 JavaScript 中定義的變數符合詞法作用域,就是說變數的作用域是在定義時決定的,不是在執行時決定的,即變數作用域只需要通過原始碼分析就知道了。
1. JavaScript 中 詞法作用域的規則為:
- 函式內部的變數允許訪問函式外部的。
- 整個程式碼結構只能函式限定作用域,這就是為什麼上文說使用自呼叫函式來開闢新的作用域的原因了。
- 作用域規則首先使用提升規則分析,下文說的預解析就是這個
- 如果當前作用域有該變數了,就不會考慮外面的了。
2. 下面再看看 JavaScript 中三種作用域
- 全域性作用域:JavaScript 中認為在函式外部定義的變數就是全域性變數,而這個全域性變數所在的作用域就是全域性作用域。
- 區域性作用域:在函式內部就是區域性作用域,在這裡定義的內部變數也就是區域性變數。
- 塊級作用域:這個是 ES6 才有的,簡單說下,就是隻使用一對大括號{} 括起來的就是塊級作用域。
3. 作用域鏈
只有函式才可以限定作用域,那麼在要有程式碼,這裡就至少存在一個全域性作用域,而寫程式碼難免又會有函式,這裡的函式就會構成另一個作用域,如果函式中還有函式,則他還會構成一個新的作用域,等等。將上面的這些作用域列出來,就會形成一個結構,這個結構就是作用域鏈。如下面程式碼:
按照全域性作用域就是 0 級鏈,函式就是 1 級鏈,函式的函式就是 2級鏈,就會有下圖:
2.8 預解析
JavaScript 的直譯器在執行程式碼的時候有兩個過程,就是預解析和再從上往下執行程式碼過程。預解析就是先把程式碼中的變數提升,然後函式提升,接著再執行程式碼。
- 變數提升:變數的宣告會被提升到作用域的最上面,注不會將賦值提升。
- 函式提升:把當前作用域的函式宣告提升到當前作用域的最上面。
如果你懂了再看看下面幾段程式碼會不會報錯?
1.
解答:不會報錯,因為經過預解析後程式碼成這樣
2.
解答:也不會報錯,不過 a 列印的值為 undefined
3.
解答:會報錯,原因可以結合上下兩張圖看即可。
3. 物件 object
物件是一個具體的事物,比如你和我都是物件,但是汽車和手機不是事物,可以說它們是一個類別。
JavaScript 中的物件可以說是一個無序的屬性的集合,屬性可以包括基本值、物件或函式,也可以把 JavaScript 中的物件想像為一組鍵值對。
把現實中的事物抽象為程式碼中的物件,其的特徵可以作為物件的屬性,其的行為可以作為方法。
3.1 建立物件
JavaScript 中建立物件的方法有四種,並不像其他語言中只能通過 new 來建立。
- 直接宣告一個鍵值對的集合
這個 obj 變數就是一個物件了裡面有兩個屬性和一個方法。使用這種方法也只適合建立一個類,因為當需要建立大量同型別的物件時,使用這個方法就需要寫大量的方法。
- 使用 new Object() 建立
這個是先建立一個空物件,然後動態增加物件的屬性和方法,也是隻適合建立只有一個物件的型別,還不如第一種,也不推薦。
- 使用工廠模式建立
這種方法就是使用一個模板函式,就相當於一個工廠,還有記得返回建立的物件。當需要建立物件的時候只需要呼叫一下函式傳參就可以了,就比上面兩種程式碼的複用性提高了。
但是這有一個問題,我們在判斷物件型別的時候,結果都是 Object
判斷物件型別使用 instanceof,而使用 typeof 判斷物件,無論什麼物件的結果都是 Object
- 自定義建構函式來建立
這個自定義建構函式名字需要首字母大寫,當然這只是個規範而已。
裡面使用了 this 關鍵字,這個 this 的指向就是使用建構函式建立的物件,也不需要返回 物件了。
注意:建立物件也需要使用 new 關鍵字,如上圖,通過這種方法就既可以建立大量同型別的物件,也可以判斷所屬型別,非常方便。
這個 new 建立物件的過程為:
- 在記憶體中先建立一個空的物件
- 讓建構函式的 this 指向剛剛建立的物件
- 執行建構函式內部的屬性和方法定義
- 返回當前物件
3.2 物件屬性和方法的相關操作
- 訪問屬性語法為物件.屬性,還可以 物件[`屬性名`] 這樣, 當然也可以通過這兩個來修改物件屬性的值
當然,當對一個不存在的屬性訪問的時候就會返回 undefined,若是修改一個不存在的屬性就是向該物件動態增加一個新的屬性。
這兩種方法推薦第二種,因為有時我們得到的屬性是一個變數名,並不知道具體的名字,這時候就只能使用第二種方法
- 訪問方法直接使用 物件.函式名() 即可
- 遍歷物件成員
可以使用 for…in… 語句
- 刪除物件成員
使用 delete 關鍵字
3.3 簡單資料型別和複雜資料型別的區別
基本型別又叫做值型別,複雜型別又叫做引用型別
值型別:簡單資料型別,基本資料型別,在儲存時,變數中儲存的是值本身,因此叫做值型別。
引用型別:複雜資料型別,在儲存時,變數中儲存的僅僅是地址(引用),因此叫做引用資料型別。
終於寫完了,下一篇常用內建物件走起。