人類在白色的底色上描繪圖畫,地球在黑色的底色上創造生命,
變數、作用域與記憶體
JavaScript的變數可以說是獨樹一幟,只需要一個(或兩個等)關鍵字(const,let)就可以創建變數,創建時不考慮變數的型別,這是其他語言少有的強大功能,當然強大的功能總是伴隨著問題,
值
原始值:Undefined,Null,Boolean,Number,String,Symbol,它們都是按值訪問的,因此我們操作的就是儲存在變數中的實際值,
參考值:保存在記憶體中的物件,參考值是按參考訪問的(類似指標),我們操作的實際上是參考而不是物件本身,
兩者的不同:
- 原始值沒有屬性,參考值有,但如果使用
new關鍵字,就會為原始值創造物件,從而使他們可以獲得屬性,(實際上字串原始值,即使不用建構式創建也有length等屬性和方法,但是想要添加屬性和方法就必須要使用包裝型別物件) - 原始值在復制的時候會獲得一個獨立的副本,而參考值只是復制了這個參考,它們指向同一個物件,(類似指標那樣理解)
傳遞引數
ECMAscript中所有的函式引數都是按值傳遞的,也就說明函式內的引數和函式外的變數沒有什么關系,只是值的賦值,即使是參考值也只是傳值(雖然他的賦值是傳址的),這里我的理解是傳入指標本身的內容而非指向的地址本身,實際上,函式內部的引數是一個區域變數,
下面的例子,可以幫助我們理解這個問題:
function setName(obj){
obj.name = 'jake'; //obj這個"指標"指向的地址(假設地址為1,則person的地址也為1)的name為jake,則1地址內的name被修改
obj = new Object(); //obj不再指向1,而是指向其他地址(假設為2),1中的name值obj取不到了
obj.name = 'james'; //2中的name為james,與1無關,也就與person無關
}
let person = new Object();
setName(person);
console.log(person.name);//jake
console.log(obj);//obj沒有定義,他在函式執行結束的時候就被銷毀了
instance用來確定物件的型別
背景關系與作用域
執行背景關系
紅寶書中對于執行背景關系的解釋并沒有那么深入,我在學習的程序中也在網上閱讀了一些相關文章,對于JavaScript的執行背景關系邏輯有了一點淺顯的理解,日后在對js有更深入了解之后,會詳細介紹,現在先簡單說一下我的理解,如果后續發現不嚴謹的地方會隨時修改,也歡迎指正,
執行背景關系本質是一個變數物件,包含了背景關系中定義的所有變數和函式,JavaScript在運行代碼之前,會對整個代碼進行一次掃描,進行一些配置(提升,配置全域背景關系等),在配置全域背景關系的時候,會將整個代碼的變數和函式宣告全部放入其中,但不會進行陳述句操作(賦值等),同時,全域背景關系會永遠放在執行背景關系堆疊的最底部,在完成這些后,才會運行每一個陳述句,當代碼執行流進入函式時,就會創建函式背景關系,當然它也是個物件,它會將當前函式中的變數和函式宣告放入其中,同時它也會被放入執行上下堆疊中,函式背景關系和全域背景關系的一些操作是相通,如果函式中還有函式,那就是不斷往背景關系堆疊中push的套娃程序,當函式執行完畢,它的背景關系就會被銷毀,因此外部無法訪問內部的變數,但是內部卻可以訪問外部的,
當你在函式內部使用變數時,如果它并沒有在該函式內部定義,那么JavaScript引擎會幫你找該函式的外層函式,這樣一層層的找下去直到最外層,這和物件中屬性和方法的搜索機制很像(一個是作用域鏈一個是原型鏈),作用域鏈就是把背景關系堆疊串了起來,前面的內部的(堆疊上層的)背景關系,可以使用后面的外部的(堆疊下層的)背景關系中的一切,反之則不行,
除了上面兩種執行背景關系外,eval()呼叫內部存在第三種背景關系(在這里就不細說了),還有一些陳述句會在作用域鏈前端臨時添加一個背景關系,
- try/catch陳述句中的catch塊:在前端創建一個新的物件,包含要拋出的錯誤物件宣告
- with陳述句:在前端添加指定物件
作用域
變數如果不使用任何關鍵字宣告,會被添加到全域背景關系,
- var的函式作用域宣告
使用var會將變數自動添加到最近的執行背景關系中, - let的塊級作用域宣告
作用域由最近一對花括號界定(對于for回圈等,在回圈條件中let宣告的物件,{}內可以使用) - const的常量宣告(也是塊作用域)
使用const宣告變數時必須同時進行初始化,并且此變數不允許修改,但如果變數是物件,則物件中的屬性或方法可以修改,這個特點讓我聯想到Vue中的props配置,同樣是不允許修改,但是如果props傳遞了物件,則可以通過v-model對這個物件內部進行修改,不知道是Vue開發者留下的問題,還是原生js的const宣告的問題,
無論JavaScript是否對變數宣告進行提升,都不建議在變數未宣告的時候就使用變數,
垃圾回收
對代碼中不再使用的變數進行及時銷毀,釋放其記憶體,其中的關鍵就是對于變數的追蹤與標記,瀏覽器的發展史上主要使用過兩種標記策略:標記清理和參考計數
標記清理:這也是JavaScript最常用的垃圾回收策略,使用標記方法對不再使用的變數進行標記,
參考計數:變數每次被參考,值+1,當沒有變數參考該變數時(值為0),則進行回收,如果兩個物件對彼此互相參考,則會造成回圈參考的問題
性能提升
多使用const和let宣告變數
共享和洗掉:避免“先創建再補充”式的動態屬性賦值,在建構式中一次性宣告所有屬性,同時避免delete動態洗掉屬性,而是將不在使用的屬性值設定為null
記憶體泄漏:閉包中的回呼會參考外部的變數,導致外部變數一直被參考無法回收,
靜態分配:在函式中創建物件,如果函式不斷使用,就會不斷有物件記憶體需要回收,從而不斷呼叫垃圾回收程式,可以在外部創建好物件,再將其以引數的形式傳入函式,從而進行靜態分配,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/555113.html
標籤:JavaScript
上一篇:CSS常用屬性
下一篇:返回列表
