javascript
【javascript 变量和作用域】
今天學習了javascript 的變量和作用域的基本知識,對于以前在開發中遇到的一些不懂的小問題也有了系統的認識,收獲還是比較多的。
【基本類型和引用類型】
ECMAScript 變量可能包含兩種不同數據類型的值:基本類型值和引用類型值。基本類型值指的是簡單的數據段,而引用類型值指那些可能由多個值構成的對象。我們常見的五種基本類型的值:Undefined、Null、Boolean、Number 和 String ,這五種基本數據類型是按值訪問的,因此可以操作保存在變量中的實際的值。引用類型的值是保存在內存中的對象,也就是說不能夠直接操作對象的內存空間,引用類型的值是按引用訪問的。注意:我們不能給基本類型的值添加屬性,例如以下代碼:
var name = 'name1'; name.age = 22; console.log(name.age); // undefined【復制變量值】
從一個變量向另一個變量復制基本類型值很引用類型值時存在不同的情況,如果從一個變量向另一個變量復制基本類型的值,會在變量對象上創建一個新值,然后把該值復制到為新變量分配的位置上,例如:
var num1 = 5; var num2 = num1;通過以上的復制方式,num1 中的 5 和 num2 中的 5 是完全獨立的,也就是說修改 num1 或者 num2 是不會影響到另外一個值的,我們參考如下的代碼:
var num1 = 5; var num2 = num1; console.log(num1,num2); // 5 5 num1 = 6; console.log(num1,num2); // 6 5下面的表格形象的展示的復制基本類型值的一個過程:
?
| 復制前的變量對象 | 復制后的變量對象 | ||
| ? | ? | ? | ? |
| ? | ? | num2 | 5 (Number類型) |
| num1 | 5 (Number類型) | num1 | 5 (Number類型) |
?
當從一個變量向另一個變量復制引用類型的值的時候,同樣也會將存儲在變量對象中的值復制一份放到為新變量分配的空間中。但是這個值的副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。復制操作結束后,兩個變量引用的其實是一個值。因此,改變任意一個變量都會影響到另外一個變量。例如以下代碼:
var per1 = new Object(); var per2 = per1; per1.name = 'name1'; console.log(per1.name,per2.name); // name1 name1 per1.name = 'name2'; console.log(per1.name,per2.name); // name2 name2 per2.name = 'name3'; console.log(per1.name,per2.name); // name3 name3下圖詳細的展示了保存在變量對象中和保存在堆中的對象之間的關系:
【傳遞參數】
ECMAScript 中所有函數的參數都是按值傳遞的,也就是說,把函數外部的值復制給函數內部的參數,就和把值從一個變量復制到另外一個變量一樣。基本類型值的傳遞如同基本類型變量的復制一樣,引用類型的傳遞如同引用類型變量的復制一樣。例如以下代碼:
function addNum(num){num += 10;return num; } var count = 20; var result = addNum(count); console.log(count,result); // 20 30這里的函數 addNum() 有一個參數 num ,而參數實際上是函數的局部變量。在調用這個函數時,變量 count 作為參數被傳遞給函數,這個變量的值是20。于是,數值20被復制給參數 num 。但是 num 的改變并不能影響 count 的值,所以 count 輸出的值仍然是20 。再舉一個例子:
function setName(obj){obj.name = 'name5'; } var newObj = new Object(); setName(newObj); console.log(newObj.name); // name5這段代碼看起來是在局部作用域中修改了 newObj 的 name 的值,在全局作用域也反映出來了,這樣的理解是錯誤的。再看一段代碼:
function setName(obj){obj.name = 'name6';var obj = new Object();obj.name = 'name7'; } var newObj = new Object(); setName(newObj); console.log(newObj.name); // name6對比兩段代碼可以看出,如果 newObj 是按引用傳遞的,那么?newObj 的 name 屬性應該是 name7 才對,但是?name 屬性是 name6,這說明及時在函數內部修改了參數的值,但原始的引用仍然保持未變。
【執行環境和作用域】
執行環境定義了變量或函數有權訪問的其他數據,決定了他們各自的行為。全局執行環境是最外圍的一個執行環境,在Web瀏覽器中,全局執行環境被認為是 window 對象,因此所有的全局變量和函數都是作為 window 對象的屬性和方法創建的。每個函數都有自己的執行環境。當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈。作用域鏈的用途,是保證對執行環境有權訪問的所有變量和函數的有序訪問。作用域鏈的前端,時鐘都是當前執行的代碼所在環境的變量對象。如果這個環境是函數,則將其活動對象作為變量對象。作用域鏈中的下一個變量對象來自包含(外部)環境,再下一個變量對象則來自下一個包含環境。全局執行環境的變量對象始終都是作用域鏈的最后一個對象。標識符解析是沿著作用域鏈一級一級的搜索標識符的過程。請看如下代碼:
var color = 'blue'; function changeColor(){if(color == 'blue'){color = 'red';}else{color = 'blue';} } changeColor(); console.log(color); // red函數 changeColor() 的作用域包含兩個對象:它自己的變量對象(其中定義著 arguments 對象)和全局環境的變量對象。當 changeColor 在執行的時候,在自己的作用域中并沒有找到 color ,于是便到全局環境中找,找到了 color 的值為 blue ,然后按照?changeColor() 函數的規則將 color 的值設置為 red 。再看一段更加詳細的代碼:
//這里只能訪問 color var color = 'blue'; function changeColor(){ //這里可以訪問 color 、newColor ,但是不能訪問 temColor var newColor = 'red';function swapColor(){ //這里可以訪問 color 、newColor 和 temColorvar temColor = newColor;newColor = color;color = temColor;} swapColor();console.log(color,newColor); //red blue } function showColor(){console.log(color); //blue } showColor(); changeColor();代碼的內容自己體會一下,這里不做詳細的解釋。
【沒有塊級作用域】
看如下的代碼:
for(var i = 0;i < 10;i ++){i += 1; } console.log(i); // 10對于有塊級作用域的語言來說, for 語句初始化變量的表達式所定義的變量,只會存在于循環的環境之中。在 javascript 中, i 并會在 for 循環執行結束后被銷毀,反而被添加到了當前的執行環境(全局環境)中。
1.聲明變量
使用 var 聲明的變量會自動被添加到最接近的環境中。在函數內部,最接近的環境就是函數的局部環境。請看如下代碼:
function addNum(num1,num2){var num = num1 + num2;return num; } var result = addNum(10,20); console.log(result); // 30 console.log(num); // num is not defined以上代碼如果不使用 var 聲明 num 的話是不會導致錯誤的,例如:
function addNum(num1,num2){num = num1 + num2;return num; } var result = addNum(10,20); console.log(result); // 30 console.log(num); // 302.查詢標識符
當在某個環境中為了讀取或寫入而引用一個標識符時,必須通過搜索來確定該標識符實際代表什么。搜索過程從作用域鏈的前端開始,向上逐級查詢與給定名字匹配的標識符。如果在局部環境中找到該標識符,搜索過程停止,變量就緒。如果在局部變量中沒有找到該變量名,則繼續沿作用域鏈向上搜索。搜索過程會一致追溯到全局環境變量。如果在全局環境變量也沒有找到該標識符,說明該變量尚未定義。請查看以下代碼:
var color = 'blue'; function getColor(){return color; } console.log(getColor()); // bluegetaColor() 在搜索局部變量的時候沒有找到 color ,而函數執行語句是一定要返回一個 color ,與是便到全局環境變量中去搜索,找到了 color 。需要注意的是,搜索的過程中如果存在一個局部變量的定義,則搜索會自動停止,不再進入另一個變量對象。也就是說,如果局部環境存在著同名標識符,就不會使用位于父環境的標識符,例如以下代碼:
var color = 'blue'; function getColor(){var color = 'red';return color; } console.log(getColor()); // red作用域鏈對于理解閉包的概念至關重要,還望能夠加深理解。
轉載于:https://www.cnblogs.com/guduoduo/p/3687411.html
總結
以上是生活随笔為你收集整理的【javascript 变量和作用域】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用访问控制列表控制用户登录
- 下一篇: JavaScript Memory Ma