Javascript學習筆記-變量、做用域和內存問題

一、基本類型和引用類型的值

ECMAScript 變量可能包含兩種不一樣數據類型的值:基本類型值和引用類型值。前端

基本類型值指的是簡單的數據段,而引用類型值指那些可能由多個值構成的對象。瀏覽器

基本數據類型:Undefined、Null、Boolean、Number 和String。這5 種基本數據類型是按值訪問的。函數

引用類型的值是保存在內存中的對象。與其餘語言不一樣,JavaScript 不容許直接訪問內存中的位置,也就是說不能直接操做對象的內存空間。工具

(1)動態的屬性

var person = new Object();
person.name = "Nicholas";
alert(person.name); //"Nicholas"

 以上代碼建立了一個對象並將其保存在了變量person 中。而後,爲該對象添加了一個名爲name 的屬性,並將字符串值"Nicholas"賦給了這個屬性。性能

而後經過alert()函數訪問了這個新屬性。若是對象不被銷燬或者這個屬性不被刪除,則這個屬性將一直存在。優化

只能給引用類型值動態地添加屬性,好比一下例子:spa

var name = "Nicholas";
name.age = 27;
alert(name.age); //undefined

爲字符串name 定義了一個名爲age 的屬性,併爲該屬性賦值27。但在下一行訪問這個屬性時,發現該屬性不見了。指針

(2)複製變量值

若是從一個變量向另外一個變量複製基本類型的值,會在變量對象上建立一個新值,而後把該值複製到爲新變量分配的位置上。code

若是從一個變量向另外一個變量複製引用類型的值時,一樣也會將存儲在變量對象中的值複製一份放到爲新變量分配的空間中。不一樣的是,這個值的副本其實是一個指針,而這個指針指向存儲在堆中的一個對象。複製操做結束後,兩個變量實際上將引用同一個對象。所以,改變其中一個變量,就會影響另外一個變量。對象

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"

 (3)參數傳遞

ECMAScript 中全部函數的參數都是按值傳遞的。

function addTen(num) {
    num += 10;
    return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,沒有變化
alert(result); //30
function setName(obj) {
    obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

 (4)檢測類型

typeof 操做符是肯定一個變量是字符串、數值、布爾值,仍是undefined 的最佳工具。

var s = "Nicholas";
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object();
alert(typeof s); //string
alert(typeof i); //number
alert(typeof b); //boolean
alert(typeof u); //undefined
alert(typeof n); //object
alert(typeof o); //object

在檢測引用類型的值時,這個操做符的用處不大。

想知道它是什麼類型的對象,使用instanceof 操做符。

result = variable instanceof constructor
alert(person instanceof Object); // 變量person 是Object 嗎?
alert(colors instanceof Array); // 變量colors 是Array 嗎?
alert(pattern instanceof RegExp); // 變量pattern 是RegExp 嗎?

 全部引用類型的值都是Object 的實例。所以,在檢測一個引用類型值和Object 構造函數時,instanceof 操做符始終會返回true。

若是使用instanceof 操做符檢測基本類型的值,則該操做符始終會返回false,由於基本類型不是對象。

二、執行環境及做用域

執行環境定義了變量或函數有權訪問的其餘數據,決定了它們各自的行爲。每一個執行環境都有一個與之關聯的變量對象(variable object),環境中定義的全部變量和函數都保存在這個對象中。

全局執行環境是最外圍的一個執行環境。

全局執行環境直到應用程序退出——例如關閉網頁或瀏覽器——時纔會被銷燬。

當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈(scope chain)。

做用域鏈的用途,是保證對執行環境有權訪問的全部變量和函數的有序訪問。

var color = "blue";
function changeColor(){
    var anotherColor = "red";
    function swapColors(){
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        // 這裏能夠訪問color、anotherColor 和tempColor
    }
    // 這裏能夠訪問color 和anotherColor,但不能訪問tempColor
    swapColors();
}
// 這裏只能訪問color
changeColor();

 (1)延長做用域鏈

執行環境的類型總共只有兩種——全局和局部(函數),但仍是有其餘辦法來延長做用域鏈。

就是當執行流進入下列任何一個語句時,做用域鏈就會獲得加長:

  • try-catch 語句的catch 塊;
  • with 語句。

(2)沒有塊級做用域

if (true) {
    var color = "blue";
}
alert(color); //"blue"

若是是在C、C++或Java 中,color 會在if 語句執行完畢後被銷燬。但在JavaScript 中,if 語句中的變量聲明會將變量添加到當前的執行環境(在這裏是全局環境)中。

for (var i=0; i < 10; i++){
    doSomething(i);
}
alert(i); //10

 

1)聲明變量

使用var 聲明的變量會自動被添加到最接近的環境中。

2)查詢標識符

當在某個環境中爲了讀取或寫入而引用一個標識符時,必須經過搜索來肯定該標識符實際表明什麼。搜索過程從做用域鏈的前端開始,向上逐級查詢與給定名字匹配的標識符。

三、垃圾收集

JavaScript 具備自動垃圾收集機制,執行環境會負責管理代碼執行過程當中使用的內存。

(1)標記清除

JavaScript 中最經常使用的垃圾收集方式是標記清除(mark-and-sweep)。

(2)引用計數

引用計數的含義是跟蹤記錄每一個值被引用的次數。

(3)性能問題

垃圾收集器是週期性運行的,並且若是爲變量分配的內存數量很可觀,那麼回收工做量也是至關大的。

(4)管理內存

確保佔用最少的內存可讓頁面得到更好的性能。而優化內存佔用的最佳方式,就是爲執行中的代碼只保存必要的數據。一旦數據再也不有用,最好經過將其值設置爲null 來釋放其引用——這個作法叫作解除引用(dereferencing)。

相關文章
相關標籤/搜索