摘要:當代碼在一個黃靜中執行時,會創建變量對象的一個作用域鏈,作用域鏈的用途是保證對執行環境有權訪問的所有變量和函數的有序訪問。
基本類型和引用類型的值
ECMAscript 變量可能包含兩種不同的數據類型的值,基本類型值和引用類型值
基本類型指的是簡單的數據段,而引用類型指那些可能有多個值構成的對象
基本數據類型 :undefined、Null、Boolean、Number和string.這五種基本數據類型是按值訪問的,因為可以操作存在變量中的實際的值
動態屬性定義基本類型的方式和引用類型的方式是類似的,創建一個變量并為該變量賦值。
對于引用類型的值,可以為其添加屬性和方法,也可以改變和刪除其屬性和方法
var person = new Object(); person.name = sunny; console.log(person.name); // sunny
上面代碼創建了一個對象并將其保存了在變量person中,然后為該對象創建一個名為name的屬性。如果這個對象不被銷毀或者這個屬性不被刪除,則這個屬性將一直存在。
但是,我們不能給基本類型的值添加屬性
var name = "sunny"; name.age = 18; consolem.log(name.age); // undefined
上面代碼為字符串name定義了一個名為age的屬性,并為該屬性賦值18,但是在下一行訪問的這個屬性的時候,發現該屬性不見了,這說明只能給引用類型值動態添加屬性復制變量值
如果從一個變量像另一個變量復制基本類型的值,會在變量對象上創建一個新值,然后把該值復制到新變量分配的位置上
var num1 = 10; var num2 = num1; num1 = 20; connsole.log(num1,num2) // 20 10
num1中保存的值是10;當使用num1的值來初始化num2時,num2也保存了值10,但num2中的10與num1中的10是完全獨立的,該值只是num1中10的一個副本,此后,這兩個變量可以完全參與任何操作而不會互相影響
當從一個變量向另一個變量復制引用類型的值時,同樣也會將存儲在變量對象中的值復制一份放到為新變量分配的空間中。不同的是,這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象,復制操作結束之后,這兩個變量實際上將引用同一個對象,因此改變其中一個變量,就會影響另一個變量
var obj1 = new Object(); var obj2 = obj1; obj1.name = "sunny"; console.log(obj2.name); // sunny; obj2.name = "zhang"; console.log(obj1.name); // zhang;
變量obj1保存了一個對象新實例,這個值被復制到obj2中,所以obj1和obj2都指向同一個對象,當obj1或者obj2添加nane屬性的時候,這個屬性都是存儲在同一個對象。都可以通過obj1和obj2去訪問。傳遞參數
函數中的參數都是按值傳遞的,基本類型值的傳遞如同基本類型變量的復制一樣,而引用類型值的傳遞,則如同引用類型變量的復制一樣。被傳遞的值會被復制到一個局部變量(即命名參數,或者用ECMAscript的概念來說,就是arguments對象中的一個元素)。
在向參數傳遞引用類型的值時,會把這個值的內存中的地址復制給一個局部變量,因此這個局部變量的變化會反映在函數的外部。
function addTen(){ num += 10; return num; } var count = 20; var result = addTen(count); console.log(count); // 20 沒有變化 console.log(result); // 30 返回 num += 10的結果
上面變量count做為參數被傳遞給函數,這個變量的值是20;數值20被復制到參數num以便在addTen()函數中使用,在函數內部num+=10,但這一變化不會影響函數外部的count變量。參數nun和count互不認識,它們僅僅具有想同的值。
使用對象傳遞參數。
function setName(obj){ obj.name = "sunny"; } var person = new Object(); setName(person); console.log(person.name); // sunny
上面代碼中創建一個對象,并將其保在了變量person中,在這個函數內部,參數obj和變量person引用的都是同一個對象,當在函數內部為obj添加name屬性后,函數外部的person也會有所反映。因為person指向的對象在堆內存中只有一個,而且還是全局對象。
很多人錯誤的認為 (在局部作用域中修改的對象會在全局作用域中反映出來,就說明參數是按引用傳遞的),為了證明對象是按值傳遞的,下面修改一下代碼
function setName(obj) { obj.name = "sunny"; obj = new Object(); // 重新定義一個新對象 obj.name = "zhang"; } var person = new Object(); setName(person); console.log(person.name); // sunny
obj重新定義一個對象,并設置name屬性 值為 zhang,如果person是按引用傳遞的話,那么person就會自動修改為指向其name屬性值為zhang 的新對象,但是訪問person.name時,值仍然是sunny,這說明即使在函數內部修改了參數的值,但原始的引用保持不變,實際上,在函數內部重寫obj時,這個變量引用就是一個局部變量了。而這個局部變量在執行完畢后立刻被銷毀檢測類型
要檢測一個變量是不是基本數據類型,typeof操作符是最佳的工具。typeof操作符是確定一個變臉是字符串、數值、布爾值、Undefined的最佳工具,如果一個變量的值是null,則typeof操作符會返回object
var name = "sunny"; // string類型 var age = 18; // Number類型 var bool = true; // boolean var unde; // Undefined var n = null; // null var person = new Object(); // 對象實例 console.log(typeof(name)); // string console.log(typeof(age)); // number console.log(typeof(bool)); // boolean console.log(typeof(unde)); // undefined console.log(typeof(n)); // object console.log(typeof(person)); // object
雖然在檢測基本類型的時候,typeof操作符是非常得力的助手,但是在檢測引用類型的時候,這個操作符的作用不大。想知道是什么類型的對象,使用instanceof操作符
如果變量是給定引用類型(根據它的原型鏈來識別)的實例,那么instanceof就會返回 true ;
var name = "sunny"; var my_array = new Array(); var my_obj = new Object(); console.log(my_array instanceof Array); // true console.log(my_obj instanceof Object); // true console.log(name instanceof Object); // false console.log(my_array instanceof Object); // true console.log(my_obj instanceof Array); // false
所有引用類型的值都是Object的實例,在檢測一個引用類型和Object構造函數時,instanceof操作符始終會返回 true。如果使用instanceof操作符檢測基本類型的值始終會返回false,因為基本類型不是對象執行環境及作用域
執行環境定義了變量或函數有權訪問的其他數據。決定它們各自的行為,每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中。
全局執行環境是最外圍的一個執行環境,在web瀏覽器中,全局執行環境被認為是window對象。因此所有全局變量和函數都是作為window對象的屬性和方法創建的。某個執行環境中的所有代碼執行完畢后,該環境被銷毀,保存在其中的所有變量和函定義也隨之銷毀(全局執行環境直到應用程序退出后--例如關閉頁面或退出瀏覽器時才會被銷毀)。
當代碼在一個黃靜中執行時,會創建變量對象的一個作用域鏈,作用域鏈的用途是保證對執行環境有權訪問的所有變量和函數的有序訪問。如果這個環境是函數,則將其活動對象作為變量對象。活動對象在最開始時只包含一個變量,即arguments對象(這個對象在全局環境中是不存在的)。
全局執行環境的變量對象始終都是作用域鏈中的最后一個對象。標識符解析是沿著作用域鏈一級一級地搜索標識符的過程,搜索過程始終從作用域鏈的前端開始,然后逐級地向后回溯,知道找到標識符為止(如果找不到標識符,通常會導致錯誤)。
var color = "blue"; function changecolor(){ if(color === "blue"){ color = "red"; } else { color = "blue"; } } changecolor(); console.log("color is now" + color); // red
在簡單的例子中,函數changecolor()的作用域鏈包含著兩個對象,它子級的變量對象(其中定義這arguments)和全局環境變量對象。可以在函數內部訪問變量color,就是因為可以在這個作用域鏈中找到它
var color = "blue"; function changecolor(){ var anothercolor = "red"; function swapcolor(){ var tempcolor = anothercolor; anothercolor = color; color = tempcolor // 這里可以訪問到color 、anothercolor、 tempcolor } // 這里可以訪問到// 這里可以訪問到color 、anothercolor,但是不能訪問 tempcolor } // 這里只能訪問color; changecolor();
以上代碼共涉及3個執行環境:全局環境,changecolor()的局部變量環境和swapcolor()的局部變量環境,內部環境可以通過作用域鏈訪問所有的外部環境,但外部壞境不能訪問內部環境中的任何變量和函數。每個環境都可以向上搜索作用域鏈,以查詢變量和函數名,但任何環境都不能通過向下搜索作用域鏈而進入另一個執行環境。延長作用域鏈
有些語句可以在作用域鏈的前端臨時添加一個變量對象,該變量對象會在代碼執行后被移除。具體來說就是當執行流進入下列任何一個語句時,作用域鏈就得到加長。
try-catch語句中的catch塊
catch語句會創建一個新的變量對象。其中包含的是拋出的錯誤對象的聲明。
try{ affffdlert("Welcome guest!"); } catch(err){ // 創建一個err對象 console.log(err.message); }
with語句
將指定的對象添加到作用域鏈中。
var s = "?debug=true"; with(location){ var url = href + s ; // 實際引用的是location.href; } console.log(url); // 輸出 location對象下的href屬性的值。 // 等同于 console.log(location.href);沒有塊級作用域
在javascript中,if語句中的變量聲明會添加到當前的執行環境中。
if(true){ var color = "blue"; } console.log(color); // blue
在javascript中,for語句創建的變量即使在變量即使在循環執行結束后,也依舊會存在與循環環境外部的執行環境中
for (var i = 0; i < 10; i++){ } console.log(i); // 101.變量聲明
使用var聲明的變量會自動被添加到最接近的環境之中,在函數內部,最接近的環境就是函數的局部環境,在with語句中,最接近的環境是函數環境。如果初始化變量沒有使用var聲明,該變量會自動被添加到全局環境中
function add(num1,num2){ var sum = num1 + num2; return sum; } var result = add(20,30); console.log(result); // 50 console.log(sum); // sum is not defined
使用var定義的sum變量,只能在函數add內訪問到,如果忽略var關鍵字定義sum,則可以在函數外部訪問得到
function add(num1,num2){ sum = num1 + num2; return sum; } var result = add(20,30); console.log(result); // 50 console.log(sum); // 50
變量被初始化賦值的時候沒有使用var關鍵字,則該變量會添加到全局環境中。垃圾收集
javascript 中最長用的垃圾收集方式是標記清除(mark-and-sweep)。當變量進入環境(例如,在函數中聲明一個變量)時,就將這個變量標記為"進入環境"。從邏輯上講,永遠不能釋放進入環境的變量所占用的內存,當變量離開環境時,則將其標記為"離開環境"
引用計數通過跟蹤每個值被引用的次數來清除所占用的內存,當聲明一個變量并將一個引用類型賦值給該變量的時候,則這個值的引用次數就是1,如果同一個值又被賦值給另一個變量,則該值的引用次數加1,相反,如果包含這個值引用的變量又取得了另一個值,則引用次數減1,當引用次數為0時,就將其占用的內存空間回收回來。
性能問題垃圾收集器是周期性運行的,而且如果為變量分配的內存數量很可觀,那么回收工作量也是想當大的
有是瀏覽器中可以直接觸發垃圾收集過程,(但我們不建議這么做),在IE中,調用window.CollectGarbage()方法會立即執行垃圾收集,在opera7及更高版本中,調用window.opera.Collect()也會啟動垃圾收集案例管理內存
一旦數據不再有用,就將其值設置為null來釋放其引用—這個做法一般叫“解除引用”,這個做法適用于大多數全局變量和全局對象的屬性。局部變量會在它們離開執行環境時自動被解除引用。
不過,解除一個值的引用并不意味著自動回收該值所占用的內存,而是讓值脫離執行環境,以更垃圾收集器下次運行時將其回收。
function crean(name){ var localperson = new Object(); localperson.name = name; return localperson; } var globalperson = crean("sunny"); console.log(globalperson); // sunny globalperson = nill; // 手動解除 globalperson 的引用
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95183.html
摘要:執行環境的類型有兩種全局全局執行環境局部函數執行環境每個環境都可以向上搜索作用域鏈,以查詢變量和函數名但任何環境都不能通過向下搜索作用域鏈而進入另一個執行環境。內部可通過作用域鏈訪問外部,外部不能訪問內部。 變量、作用域和內存問題 ECMAScript 數據類型 基本類型(5種): Undefined,Null,Boolean,Number,String typeof() 檢測...
摘要:使用聲明的變量會動被添加到最近的環境中查詢標識符,現在作用域鏈的最前端開始搜索,逐步向上級查詢,直到找到匹配的標識符,在變量查詢中,訪問局部變量要比全局變量更快,因為不需要向上搜索作用域。 基本類型和引用類型的值 基本類型值指的是簡單的數據段;引用類型值指那些可能由多個值構成的對象。不能給基本類型添加屬性,可以給引用類型值動態的添加屬性。 基本類型按值訪問,存放在棧內存中。引用類型按引...
摘要:變量作用域和內存問題基本類型和引用類型的值基本類型就是簡單的數據段種值類型,而引用類型就是對象操控對象的引用。但是不但能訪問自己的變量,也能訪問和全局作用域下的變量。延長作用域鏈相當于創造了一個新的變量對象在當前作用域的上方。 變量作用域和內存問題 1.基本類型和引用類型的值 基本類型就是簡單的數據段(5種值類型),而引用類型就是對象(操控對象的引用)。 1.1復制變量值 引用類型實際...
摘要:在操作對象時,實際上是在操作對象的引用而不是實際的對象。為此,引用類型的值是按引用訪問的。標記清除是目前主流的垃圾收集算法,這種算法的思想是給當前不使用的值加上標記,然后再回收其內存 1.在操作對象時,實際上是在操作對象的引用而不是實際的對象。為此,引用類型的值是按引用訪問的。 2.當從一個變量向另一個變量復制引用類型的值時,兩個變量實際上將引用同一個對象,因此,改變其中一個變量,就會...
摘要:全局變量是最外圍的一個執行環境,代碼在環境中執行,會創建一個作用域鏈,用途是保證對執行環境有權訪問所有變量和函數的有序訪問。作用域鏈中最后一個對象始終是全局執行環境。內部環境可以通過作用域鏈訪問所有的外部環境,外部則不能訪問內部。 1、基本類型和引用類型的值 * 基本類型 : 指的是簡單的數據段,五種基本類型是按值訪問的,可以直接操作保存在變量中實際的值。 * 引用類型 : 指那些可能...
摘要:不允許直接訪問內存中的位置,也就是說不能直接操作對象的內存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。解除引用的真正作用是讓值脫離執行環境,以便垃圾收集器下次運行時將其回收 1 基本類型和引用類型的值 基本數據類型是按值訪問的,因為可以操作保存在變量中的實際的值 基本類型值在內存中占據固定大小的空間,因此被保存在棧內存中 引用類型的值是保存在內存中的對象。JavaSc...
閱讀 1984·2021-11-24 09:38
閱讀 3344·2021-11-22 12:07
閱讀 1912·2021-09-22 16:03
閱讀 1969·2021-09-02 15:41
閱讀 2626·2021-07-24 23:28
閱讀 2219·2019-08-29 13:17
閱讀 1560·2019-08-29 12:25
閱讀 2674·2019-08-29 11:10