javascript 變量、作用域和內存問題
一、基本類型和引用類型的值
1.基本類型和引用類型的值
基本類型值:指那些保存在棧內存中的簡單數據,即這種值完全保存在內存中的一個位置,他們所占據的空間大小是固定的。
引用類型值:指那些保存在堆內存中的對象,這些類型的真正數據是保存在堆內存中的,而同時在棧內存中保存的只是一個指針,這個指針指向的是這個對象在堆內存中的一塊地址。
基本類型的復制:基本類型在內存中占有的空間大小是固定的,復制的時候會重新在棧內存中開辟一塊空間,是按值來訪問的。
引用類型的復制:由於這種對象所占的大小是不固定的,是放在堆內存中的,但是內存的地址大小是固定的,故棧中存放的是對象在堆內存的地址。這樣當查找引用的時候,是先從棧內存中取出地址,然後再到堆內存中找到對應的值
2.復制變量的值
基本類型:復制的是變量本身的值,復制後是在棧空間重新開辟一塊空間,復制完成後兩個變量是相互獨立的,各不相幹,故一個變量的值改變後不會影響另外一個變量的值。
引用類型:復制的時候只是復制的棧空間的地址,而堆內存中還是同一個對象,也就是復制的引用,結果是兩個變量指向的是同一個內存塊,所以,復制後兩個變量中某一個改變了對象的值那麽另外一個變量輸出的結果也會改變,因為他們是指向的內存中同一個對象。
3.傳遞參數
在js中參數傳遞都是值傳遞,不存在引用傳遞。
值類型:傳遞的是變量本身的值,和復制是一樣的,函數中改變了變量的值,不會影響源變量值
引用類型:同樣是值傳遞,傳遞的是變量再棧內存空間中的地址值,如果在函數中改變了對象某一個屬性的值,源變量中的值也會改變,因為在堆內存中它們是指向的同一個對象。
function func(num){ num.name=123; } var box={}; box.name=‘abcd‘; alert(box.name); //abcd func(box); alert(box.name); //123 值在函數func中被改變了
4.檢測類型
檢測變量的類型的時可以用 typeof 來實現,但是這個只是返回的幾大基本的數據類型,在檢測Object類型的時候則不是那麽好用,因為Null,Object,Array,RegExp 等都會返回object,那樣就不知道變量到底是什麽類型。
可以 用instanceof 來確定變量是某種具體的引用類型。
var box = [1,2,3]
alert(box instanceof Object); //true alert(box instanceof Array); console.log(Array.isArray(box)) //true //準確檢測類型是否是數組 如果是這種類型就返回true,否則就返回false
二、執行環境及作用域
執行環境也就是作用域在很多的編程語言中都是一個很重要的概念,規定了變量或者函數有權訪問其他數據的權限,規定了各自的行為。
全局執行環境是最外圍的執行環境,在web瀏覽器中,全局執行環境被認為是window對象,故所有的全局變量和函數都是以window對象的屬性和方法創建的。
每個函數都有自己的執行環境,當執行環境中代碼執行完成後,就會銷毀該執行環境,也會銷毀裏面的變量和函數等。(全局執行環境是需要在網頁關閉或者應用程序退出後才會被銷毀。)
當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈,作用域鏈的用途是保證執行環境有權訪問的所有變量和函數的有序訪問。
函數體內還包含著函數,只有這個函數才可以訪問內一層的函數。而內部函數的變量可以通過作用域鏈訪問外部函數的變量,可以向上搜索作用域鏈,以查詢變量。但是不能反過來。
沒有塊級作用域
塊級作用域表示諸如if等有花括號封閉的代碼段塊,所以支持條件判斷來定義變量。 像 if,for 等代碼塊中定義的變量在花括號外面是可以訪問的,這和其他語言中有很大的差別。
if(true){ var color = ‘red‘; } console.log(color); //red
var關鍵字在函數中的區別
在函數中聲明變量的時候,如果不加上關鍵字 var 那變量會被認為是全局的,函數外面也可以訪問它,當然在訪問之前要先執行一次函數,加了則是局部的。
最好不要不用var關鍵字就初始化變量,因為這種情況下可能會導致各種錯誤,所有初始化變量的時候一定要加上關鍵字 var。
一般確定某一個變量的時候是通過搜索來確定的,現在本級作用域上找,如果沒有,在向上級作用域找,依次類推,故訪問局部變量要比訪問全局變量的效率更高。因為不需要向上收索作用域鏈
3、內存相關
js中也存在垃圾回收機制,我們不需要擔心內存的泄露問題,垃圾回收機制會自動的管理內存的分配和無用內存的回收。
JS中最常用的垃圾回收的方式是標記清除,就是在運行的時候會給內存中的所有變量加上一個標記,然後去掉環境中正在使用的變量的標記,而沒有被去掉標記的變量將被視為準備刪除的變量。最後垃圾清理器完成內存清理的工作,銷毀那些帶有標記的變量,並且回收他們所占用的內存空間 。
垃圾收集器是周期性的運行,不是隨時運行,這樣可能會遇到一些性能問題,但是一般情況下不需要擔心這個問題。
一般來說,確保頁面占用的內存更少可以讓頁面獲得更好的性能,最好的減少內存占用量的方式就是,一旦變量或者對象不再使用的時候,將其賦值為空,即:box=null; 來釋放引用,這種方式叫做刪除引用,這種方式使用大多數的全局變量和全局對象。
javascript 變量、作用域和內存問題