基本類型和引用類型的值javascript
ECMAScript 變量可能包含兩種不一樣的數據類型的值:基本類型值和引用類型值。java
基本類型值指的是那些保存在棧內存中的簡單數據段,即這種值徹底保存在內存中的一個位置。瀏覽器
而引用類型值則是指那些保存在堆內存中的對象,意思是變量中保存的實際上只是一個指針,這個指針指向內存中的另外一個位置,該位置保存對象。函數
將一個值賦給變量時,解析器必須肯定這個值是基本類型值,仍是引用類型值。spa
基本類型值:指針
有如下幾種:Undefined、Null、Boolean、Number 和 String。這些類型在內存中分別佔有固定大小的空間,他們的值保存在棧空間,咱們經過按值來訪問的。在某些語言中,字符串以對象的形式來表示,所以被認爲是引用類型。ECMAScript放棄這一傳統code
引用類型的值:必須在堆內存中爲這個值分配空間。因爲這種值的大小不固定,所以不能把它們保存到棧內存中。但內存地址大小是固定的,所以能夠將內存地址保存在棧內存中。這樣,當查詢引用類型的變量時,先從棧中讀取內存地址,而後再經過地址找到堆中的值。對於這種,咱們把它叫作按引用訪問。對象
定義基本類型值和引用類型值的區別blog
定義基本類型值和引用類型值的方式是類似的:建立一個變量併爲該變量賦值。可是,當這個值保存到變量中之後,對不一樣類型值能夠執行的操做則截然不同。ip
var box = new Object(); //建立引用類型 box.name = 'Lee'; //新增一個屬性 alert(box.name); //輸出 /*若是是基本類型的值添加屬性的話,就會出現問題了。*/ var box = 'Lee'; //建立一個基本類型 box.age = 27; //給基本類型添加屬性 alert(box.age); //undefined
基本類型值和引用類型值在賦值上的區別
在變量複製方面,基本類型和引用類型也有所不一樣。基本類型複製的是值自己,而引用類型複製的是地址。
基本類型
var box = 'Lee'; //在棧內存生成一個 box 'Lee' var box2 = box; //在棧內存再生成一個 box2 'Lee' alert(box); alert(box2); //box2 是雖然是 box1 的一個副本,但它是徹底獨立的。也就是說,兩個變量分別操做時互不影響。 box2 = 'kkkk'; alert(box2)
引用類型
/* 在引用類型中,box2 其實就是 box,由於他們指向的是同一個對象。若是這個對象中的 name 屬性被修改了,box2.name 和 box.name 輸出的值都會被相應修改掉了。 */ var box = new Object(); //建立一個引用類型 box.name = 'Lee'; //新增一個屬性 var box2 = box; //把引用地址賦值給 box2 alert(box2.name);
函數中傳遞參數是按值傳遞
javaScript 中全部函數的參數都是按值傳遞的,言下之意就是說,參數不會按引用傳遞,雖然變量有基本類型和引用類型之分。
function box(num) { //按值傳遞,傳遞的參數是基本類型 num += 10; //這裏的 num 是局部變量,全局無效 return num; } var num = 50; var result = box(num); alert(num); //仍是50 alert(result); //60 /*以上的代碼中,傳遞的參數是一個基本類型的值。而函數裏的 num 是一個局部變量,和外面的 num 沒有任何聯繫。*/
function box(obj) { //傳遞的參數是引用類型,可是是按值傳遞的,看似傳遞的是p對象的地址值,實際上是將這個對象直接傳進去的 obj.name = 'Lee'; } var p = new Object(); box(p); alert(p.name);
function box(obj) { obj.name = 'Lee'; var obj = new Object(); //函數內部又建立了一個對象 obj.name = 'Mr.'; //並無替換掉原來的 obj } var p = new Object(); box(p); alert(p.name);
執行環境及做用域
執行環境是 JavaScript 中最爲重要的一個概念。執行環境定義了變量或函數有權訪問的其餘數據,決定了它們各自的行爲。
全局執行環境是最外圍的執行環境。在 Web 瀏覽器中,全局執行環境被認爲是 window對象。
所以全部的全局變量和函數都是做爲 window 對象的屬性和方法建立的。
var box = 'blue'; //聲明一個全局變量 function setBox() { console.log(box); //全局變量能夠在函數裏訪問 } setBox(); //執行函數 /*全局的變量和函數,都是 window 對象的屬性和方法*/ var box = 'blue'; function setBox() { console.log(window.box); //全局變量即 window 的屬性 } window.setBox(); //全局函數即 window 的方法
function setBox1(){ function setColor(){ return 322; } return 22; } //console.log(window.setColor()); //結果報錯,由於setColor這個方法是不屬於全局的,沒法直接調用
函數裏的局部做用域裏的變量替換全局變量,但做用域僅限在函數體內這個局部環境。
var box = 'blue'; function setBox() { var box = 'red'; //這裏是局部變量,出來就不認識了console.log(box); } setBox(); console.log(box); // blue
var box = 'blue'; function setBox() { box = 'red'; //去掉var就變成全局變量了 } setBox(); console.log(box); // red
經過傳參,能夠替換函數體內的局部變量,但做用域僅限在函數體內這個局部環境。
var box='blue'; function setBox(box){ console.log(box); } setBox('red'); //red console.log(box); //blue
函數體內還包含着函數,只有這個函數才能夠訪問內一層的函數。
var box = 'blue'; function setBox() { function setColor() { var b = 'orange'; console.log(box); // blue console.log(b); //orange,只能在這個函數裏面訪問,不能在外部,由於做用域在這裏 } // console.log(b) // 報錯:b is not defined setColor(); //setColor()的執行環境在 setBox()內 } setBox()
沒有塊級的做用域
塊級做用域表示諸如 if 語句等有花括號封閉的代碼塊,因此,支持條件判斷來定義變量。
if (true) { //if 語句代碼塊沒有局部做用域 var box = 'Lee'; } console.log(box); //Lee for (var i = 0; i < 10; i ++) { //沒有局部做用域 var box = 'Lee'; } console.log(i); 10 console.log(box); // Lee
/*var 關鍵字在函數裏的區別*/ function box(num1, num2) { var sum = num1 + num2; //若是去掉 var 就是全局變量了 return sum; } alert(box(10,10)); alert(sum); //報錯,很是不建議不使用 var 就初始化變量,由於這種方法會致使各類意外發生。因此初始化變量的時候必定要加上 var。
var box = 'blue'; function getBox() { return box; //表明全局 box } //若是加上函數體內加上 var box = 'red' 那麼最後返回值就是 red console.log(getBox()); //blue
變量查詢中,訪問局部變量要比全局變量更快,由於不須要向上搜索做用域鏈。
全局變量和局部變量
<script type="text/javascript"> for(var x = 0;x<3;x++){ //在腳本片斷中定義的變量,是全局變量 document.write("x="+x); } document.write("X======="+x);//在java中x變量已經釋放,但在js中還可使用x變量 </script> <script type="text/javascript"> document.write("X======="+x);//在java中x變量已經釋放,但在js中還可使用x變量,甚至在這裏也能夠訪問的到 </script>
var x = 4;//全局的變量 function show(x){//局部的變量 x = 8; } show(x); document.write("X======="+x);//結果仍是4
在函數做用域中能夠訪問到全局做用域的變量,在全局做用域中沒法訪問到函數做用域的變量
function show(){ var x = 8;//這裏是局部變量 } document.write("X======="+x);//這裏訪問不到函數裏的局部變量
變量做用域的練習
當在函數做用域操做一個變量時,它會先在自身做用域中尋找,若是有就直接使用。
若是沒有則向上一級做用域中尋找,直到找到全局做用域,若是全局做用域中依然沒有找到,則會報錯ReferenceError在函數中要訪問全局變量可使用window對象
var a = 123; function fun(){ console.log(a); // 函數內部沒有變量a,往外面找,結果是123 } fun();
var a = 123; function fun(){ console.log(a); // 函數內部有a變量,只是變量的聲明提早了,因此是undefined var a = 456; } fun(); console.log(a); // 全局做用域下的a變量,因此是123
var a = 123; function fun(){ console.log(a); // 函數內部沒有聲明變量,因此結果是外部的a變量123 a = 456; // 修改了外部變量a的值 } fun(); console.log(a); // 結果是456
var a = 123; function fun(a){ console.log(a); // 調用這個函數的時候沒有傳參數,因此形參變量a是undefined a = 456; // 無效,由於a變量是行參 } fun(); console.log(a); // 123
var a = 123; function fun(a){ console.log(a); // 123 a = 456; // 無效,由於a是形參數,出了這個函數就沒有了 console.log(a) // 456 } fun(123); console.log(a); // 123