JS-基礎概念(上篇)

有在寫JS的朋友,應該或多或少都會有一些感覺,就是覺得JS非常好上手,也知道自己在寫什麼。但是寫起來就是不踏實...

這是為什麼呢?

因為JS的語言特性跟其他語言不大相同,來舉個例子看看

1=="1"

如果這是在C#,會直接報錯,因為型別不同。

而在JS之中呢,卻會發現沒有錯耶!執行也正常耶!那就這樣寫好了> O <

然後事隔多年,悲劇就發生了


相信部分朋友也跟我一樣,對JS抱有憧憬,卻又害怕受傷害。

因為現在JS正夯,不論是NG、Vue、React,甚至是D3、桌面應用程式、APP,都可以透過JS達成,既然如此,能說JS不重要嗎?

當然重要!那有認真的啃完犀牛書過嗎?

當然沒有

也因此造就了對JS沒把握,寫起來不踏實的感覺,不了解語言的特性,自然而然就寫不出漂亮的程式碼~

於是乎,報名了保哥的Javascript核心實戰課程,也就有了這篇文章的產生。

 


一、基礎型別

Javascript只有二種型別:原始型別、物件型別

原始型別:數值、字串、布林、undefined、null

物件型別:除了上述這五種之外的型別,皆為物件,因此,陣列、函式皆可以認定是物件型別。

擴充型別:其實這個型別不能跟原始型別、物件型別相提並論,而是該放在物件型別底下。擴充型別是類似Date這種型別,本身不是原始型別,而是透過物件型別擴充的型別,算是JS本身建立來便利使用的型別,骨子裡還是屬於物件。

 

那原始型別跟物件型別有什麼差別呢?差在記憶體之中宣告的位置

原始型別:直接存在記憶體位址之中的型別,

物件型別:物件會在記憶體之中建立一個位址,而物件中的屬性會另外再建立一份記憶體位置。因此存放的記憶體位址數量是N+1,N是物件中的屬性,1是物件。

再來說說原始型別的undefined、null,undefined屬於未經賦值的型別,就是已經宣告,但裡面空無一物,是JS中預設無資料的型別。

那null呢?除非主動給予null值,不然非常少情況值會是null,所以就別太糾結了XD

 

希望這樣的說明在多年以後還看得懂在講什麼鬼東西...

 


二、資料參照以及var的特性

變數及屬性差異

由於JS的特性為,非原始型別皆為物件,因此連Window都是物件型別,而物件型別可以任意增加、刪除屬性

那屬性又是什麼,跟變數又有什麼差別?

在Windows底下,輸入這二行時,會有些微的差異

a = "我是屬性";
var a="我是變數";

屬性:僅存在於物件底下,可以被刪除

變數:在開發時期宣告,編譯時期檢查。並且無法被刪除

通常JS的汙染即是這二個東西在搞鬼,仍需要特別注意的是,在JS的Window中,如果先a再var a,則a則會從屬性轉為變數導致a的屬性無法被刪除

 

2.var的特性

這東西哪有什麼生命週期可言,有夠邪惡亂七八糟的

好啦...var有幾個特性,務必要注意以及小心使用

  1. 生命週期:如果宣告在函式之中,有效範圍僅存在於函式中,聽不懂的話認function的大括號就對了!因此不會有宣告二個同名的var變數衝突問題,但這種寫法應該要避免才對。
  2. Hoisting:由於javascript會在程式碼執行之前,先進行一次編譯,編譯什麼呢?就是把使用var的宣告都移至第一行,為了避免錯誤的判斷,建議把var都提升到第一行會比較好!
  3. 資料重複性:由於var本身是一個宣告,因此在非同步之中,迴圈中跑var i的話,如果迴圈先跑完,此時會導致i的值為最後一次迴圈的值,當非同步函式開始執行時,會導致印出來的資料非預期。如迴圈印i的答案不是1~9,而是999999999。解決方式改用let即可。

 


三、記憶體的配置方式及優化方式

這邊要先講的變數,變數是JS中執行時期宣告出來的,這筆資料紀錄的並非資料本身,而是記憶體存放位址

詳細的就看程式碼吧!如果看不懂,建議打一行,再跟著看一次會比較清楚!

// 1.在記憶體位址中建立 1 的資料
// 2.宣告a的變數,資料 為1的記憶體位址
//   如果第二點看不懂,可以這樣想像
//   是指向門牌(位址),而不是門牌內住的人(值)
var a = 1;

// 3.建立b的變數,並且取得跟a一樣的記憶體位址
var b = a;

// 4.在記憶體中再建立 3 的資料
// 5.清除a原本指向1的記憶體位址的路徑
//   注意!
//   1依舊存在,只是a的記憶體位址發生改變
//     而b的記憶體位址依舊指向1
// 6.a重新指向 3 的記憶體位址
a = 3;

// 印出來會是3
console.log(a);
// 印出來會是1
console.log(b);

這個概念懂了就大概能理解資料是怎麼變化的,再來就是要注意JS的資料生命週期了,例如物件中屬性、變數,以及函式中的屬性、變數。

接著我們來看看如何釋放記憶體資源

1.delete 屬性名稱

2.清除該筆資料與根物件的連結

第二點會比較難懂,直接舉例會比較好懂一些。

根物件:Window

子物件:A

子物件的屬性:B,型別為物件

因此我們可以知道,若是要取得B,要這樣輸入Window.A.B對吧。但如果我直接把A給刪除掉呢?

此時由於B的屬性依附在A之中,是而B透過A跟Window做聯繫的,當A消失了,B自然而然也就跟Window斷了聯繫,此時會被認定為無效的物件,進而釋放該筆資源。

 

如果上面懂了就再來談談IIFE吧!

IIFE又名立即函式,主要是將函式轉變為物件來執行,由於執行完畢後,並未將值存下,因此函式中所宣告的資源會立即被釋放。

有看到宣告被加粗嗎?這是說如果在函式中直接使用屬性處理值的話,會直接汙染到WIindow的屬性,也就失去IIFE原先的美意了。

如果看不懂也沒關係!謹記立即函式中愛用宣告即可!

來看個範例吧!

// 透過第一行的左括號,以及最後一行的右括號
// 將函式轉變成一個物件,物件中的資料即是函式
(function (a,b){
	return a + b;
})(2,4);

// 再最後一行則直接呼叫 物件中的函式,因此可以傳入二個參數
// 這個範例的重點就是左右括號將函式轉為物件
// 並且執行完畢後會立即釋放資源,可以有效管理記憶體

 


LINE討論群FB討論區

歡迎您的加入,讓這個社群更加美好!

聯絡方式:
FaceBook
E-Mail