JavaScript Fortnight-Diary0:變量、作用域與內存

原始值和引用值

除了object外的變量都是原始值,引用值就是對象,對象實際上保存在內存空間,而js不允許訪問內存空間,因此在對對象進行任何操作時,操作的就是這個引用(reference)

  • 用new時有區(qū)別
let name1 = "lpj";
let name2 = new String("lpj")'
name1.age = 19;
name2.age = 19;
console.log(name1.age);//undefined name1類型為string
console.log(name2.age);//19 name2類型為object
  • 對象的“復制”
    把引用值從一個變量賦給另一個變量時,其儲存的值也會復制,區(qū)別在于,這個值是指向這個對象的指針

  • 傳參只傳值不傳引用

        function setName(obj){
            obj.name = "lpj"
            obj = new Object({
                name:"hjy"
            })
        }
        let person = Object()
        setName(person)
        console.log(person.name)//lpj而非hjy

在函數(shù)內部 obj和person都指向同一個對象,obj.name = "lpj"可以成功對這個對象進行操作,但是obj = new Object后,obj會被設置為一個新的引用值(新指針值),而非把這個引用指向一個新對象,這說明了傳參時不會傳引用,而只是傳了個指針值。換句話說,跟c++不同,c++傳一個數(shù)組變量進來,然后清空,那就是直接清空了。

上下文和作用域鏈 P89

變量或函數(shù)的上下文(即作用域)決定了他們能訪問哪些數(shù)據(jù)以及他們的行為
每個上下文都有一個關聯(lián)的變量對象,這個上下文中的所有變量和函數(shù)都存在這個對象上,這個以一定順序排列鏈接變量對象集合就稱為作用域鏈,當前作用域的變量對象始終在鏈的最前
這樣就可以按順序去進入各個作用域的變量對象,從而訪問數(shù)據(jù)。
舉個例子說明作用域鏈規(guī)則



簡單來說:變量對象就像一個個車間,里面按順序裝著不同機器和原料
(如果是全局變量對象Windows的話,那就是總工廠,各種車間(函數(shù)、對象)和各種總工廠原料(全局變量)都算是這個工廠的機器/原料(屬性))
作用域鏈就像一條單向傳送帶連接不同車間,從小車間連向大車間最終連向總工廠

函數(shù)在創(chuàng)建和執(zhí)行時發(fā)生了什么?待辦什么是context,https://blog.csdn.net/konglingyuan/article/details/51441829

  • 創(chuàng)建時:創(chuàng)建Function對象的內部屬性[[scope]],包含了一個函數(shù)當前作用域中對象的集合,即當前作用域的變量對象(是嗎),這個集合就是函數(shù)的作用域鏈

它決定哪些數(shù)據(jù)可以被函數(shù)所訪問,它將把自己完全復制到執(zhí)行環(huán)境的作用域鏈中

  • 執(zhí)行時:為函數(shù)創(chuàng)建一個執(zhí)行環(huán)境(execution context)內部對象
    該對象與函數(shù)一一對應,會重復創(chuàng)建,執(zhí)行完畢即銷毀
  • 為執(zhí)行環(huán)境初始化作用域鏈,初始化為當前函數(shù)的[scope]](即函數(shù)的作用域鏈)的對象

注意 這里的作用域鏈不是上面的函數(shù)的作用域鏈,而是屬于環(huán)境的,用于解析標識符

  • 至此,活動對象創(chuàng)建完畢,成為函數(shù)運行時的一個變量對象

  • 作用域鏈增強
    指原本作用鏈前端對應的變量對象被換成了別的變量對象
    try/catch的catch(創(chuàng)建新的變量對象)以及with語句(挪動變量對象到最前端)

  • 變量的作用域聲明

    • var
      在函數(shù)里var name,外面訪問不到,因為這個變量被添加到這個函數(shù)上下文的變量對象當中了但是如果不var,直接寫name,會自動添加為全局變量,放在全局變量對象當中
      • 提升(有點抽象)
        var name = "lpj" 等價于 name = "lpj"; var name
        也就是說 var在執(zhí)行的時候,這個聲明會被提升到頂端(函數(shù)頂端或全局頂端),但是這個賦值卻不會 舉例:
console.log(name)//undefined
var name = 'lpj'//聲明被提升 但是賦值沒被提升
  • let
    塊作用域:指最近的一堆{}就是一個塊,這解釋了為什么使用let可以防止for語句的i泄露出去

  • 標識符查找 P93
    就是指沿著作用域鏈搜索這個變量的過程,如果在當前作用域找到了color = ''blue''查找即停止,在父級的color = "green"就不會生效

內存與性能P95

  • 垃圾回收
    每隔一段時間判定哪個變量不會再使用了,就釋放它的內存
  • 性能
    手動解除引用,即設為null,能確保下次垃圾回收時被成功回收而非馬上被回收
    • 函數(shù)內局部變量會自動被解除引用
    • 由于let和const以塊(而非函數(shù))為作用域,可能會更早地接觸引用從而回收
    • 隱藏類的利用
    • 內存泄露(待辦)https://www.cnblogs.com/princeness/p/11664978.html
      內存泄露是指你用不到(訪問不到)的變量,依然占居著內存空間,不能被再次利用起來。
      在某些環(huán)境中,這個閉包會導致內存泄露,即largeObject不能被及時回收
function outer() {
    var largeObject = LargeObject.fromSize('100MB');
  
    return function() {
        console.log('inner');
    };
}
var inner = outer();

遺留問題:閉包為什么能會使內存常駐,為什么能解決這里最后for循環(huán)的問題

高性能

管理作用域

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容