基本數據類型和引用數據類型的區別和變量及作用域(函數和變量)


基本類型和引用類型的值

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

基本類型值指的是那些保存在棧內存中的簡單數據段,即這種值完全保存在內存中的一個位置。

而引用類型值則是指那些保存在堆內存中的對象,意思是變量中保存的實際上只是一個指針,這個指針指向內存中的另一個位置,該位置保存對象。

將一個值賦給變量時,解析器必須確定這個值是基本類型值,還是引用類型值。

基本類型值:

有以下幾種:Undefined、Null、Boolean、Number 和 String。這些類型在內存中分別占有固定大小的空間,他們的值保存在棧空間,我們通過按值來訪問的。在某些語言中,字符串以對象的形式來表示,因此被認為是引用類型。ECMAScript放棄這一傳統

引用類型的值:必須在堆內存中為這個值分配空間。由於這種值的大小不固定,因此不能把它們保存到棧內存中。但內存地址大小是固定的,因此可以將內存地址保存在棧內存中。這樣,當查詢引用類型的變量時,先從棧中讀取內存地址,然后再通過地址找到堆中的值。對於這種,我們把它叫做按引用訪問。

        

 

 

定義基本類型值和引用類型值的區別

定義基本類型值和引用類型值的方式是相似的:創建一個變量並為該變量賦值。但是,當這個值保存到變量中以后,對不同類型值可以執行的操作則大相徑庭。

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM