2016年6月26日 星期日

javascript 特性與觀念整理

紀錄目前為止個人覺得蠻重要的javascript特性和觀念:
以下程式碼,你能看出console的輸出結果嗎?

1、
var var1 = 'a';

function fun1 (var1) {
    var1='b';
    console.log(var1);
}

fun1(var1);

console.log(var1);


2、
var var2 = {
    proper: 'a'
};

function fun2(var2) {
     var2.proper = 'b';
     console.log(var2.proper);
   
     var var3 = var2;

     console.log(var3.proper);
}

fun2(var2);

console.log(var2.proper);

console.log(var3.proper);


3、
var var4 = {
    proper1: 'a'
};

function fun3(var4) {
    var4 = {
        proper1: 'b',
        proper2: 'w'
    };
    console.log(var4.proper1);
    console.log(var4.proper2);
}

fun3(var4);

console.log(var4.proper1);
console.log(var4.proper2);


4、
var var5 = {
    proper1: 'a',
    proper2: {}
};

function fun4(){
    var var6 = var5,
          proper1 = var6.proper1,
          proper2 = var6.proper2;
 
    proper1 = 'b';
    console.log(var6.proper1);
    proper2.attr = 'w';

    proper2 = 'y';
    console.log(typeof var6.proper2);
    console.log(var6.proper2.attr);
    var obj = {
        properx: 'z'
    };
    var6.proper2.z = obj;
    console.log(var6.proper2.z.properx);
    return var6;
}

var var7 = fun4();

console.log(var5.proper1);
console.log(var5.proper2.attr);

var5 = '';

console.log(var7.proper2.attr);
console.log(var7.proper2.z);
console.log(var7.proper2.z.properx);


以下解答:

1、
var var1 = 'a';

function fun1 (var1) {
    var1='b';
    console.log(var1);
}

fun1(var1); //呼叫fun1並傳入global 變數var1的值(基本形態的字串'a')存入local變數var1之中,於fun1中修改了local變數var1的值為字串的'b',緊接著在console輸出local變數var1的值 'b'

console.log(var1);//輸出global變數var1的值'a'

//程式碼1執行結果驗證


2、
var var2 = {
    proper: 'a'
};

function fun2(var2) {
     var2.proper = 'b';
     console.log(var2.proper);
   
     var var3 = var2;

     console.log(var3.proper);
}

fun2(var2);//呼叫fun2並傳入global變數var2的值(global物件形態指標),存入local變數var2,在函數內部對global物件的proper屬性值做修改,改為'b',接著console輸出這個屬性的值'b',接著宣告一個local變數var3,並將local var2的值(global 物件指標)賦於var3,接著console輸出global物件的proper屬性值'b'

console.log(var2.proper);//console輸出global var2的值(global物件)的proper屬性值'b'

console.log(var3.proper);//因scope限制,無法存取local變數var3的值(global物件的指標),於console輸出var3 is not defined,也就無法進一步讀取物件的proper屬性值

//程式碼2執行結果驗證


3、
var var4 = {
    proper1: 'a'
};

function fun3(var4) {
    var4 = {
        proper1: 'b',
        proper2: 'w'
    };
    console.log(var4.proper1);
    console.log(var4.proper2);
}

fun3(var4);//呼叫fun3並傳入global變數var4的值(物件形態指標)存入local變數var4中,於函數內部對local變數var4做賦新值的動作,宣告一個local的物件存入其中,覆蓋掉原本的global物件指標,新物件擁有兩個屬性,接著console輸出local物件的兩個屬性值,分別為'b'和'w'

console.log(var4.proper1);//console輸出global物件的proper1屬性值'a'
console.log(var4.proper2);//global物件未定義proper2這個屬性,console輸出undefined

//程式碼3執行結果驗證


4、
var var5 = {
    proper1: 'a',
    proper2: {}
};

function fun4(){
    var var6 = var5,
          proper1 = var6.proper1,
          proper2 = var6.proper2;
 
    proper1 = 'b';
    console.log(var6.proper1);
    proper2.attr = 'w';

    proper2 = 'y';
    console.log(typeof var6.proper2);
    console.log(var6.proper2.attr);
    var obj = {
        properx: 'z'
    };
    var6.proper2.z = obj;
    console.log(var6.proper2.z.properx);
    return var6;
}

var var7 = fun4();//呼叫func4,於函數內宣告local變數var6,並將global變數var5的值(global物件指標)賦於它,接著宣告兩個local變數proper1, proper2並分別將global物件的proper1屬性的值('a')與proper2屬性的值(global物件指標)賦予兩者,

接著修改local變數proper1的值為文字'b',接著console輸出global物件的proper1屬性值'a',接著為置於local變數proper2中的global物件新增一個名為attr的屬性,並賦予其值為文字'w',接著修改local變數proper2的值為文字'y',覆蓋掉原本的global物件指標,

接著console輸出置於local變數var6中的global物件的proper2屬性之形態,結果為object,然後接著console輸出其attr屬性值'w',接著宣告一個local變數obj,賦於其一個local物件,此物件擁有一個properx屬性,值為文字'z',接著為global物件的proper2屬性值(global物件指標),新增一個屬性名為z,並將local變數obj的值(local物件指標)賦予它,

然後console輸出置於global物件中的global屬性變數z中的local物件之properx屬性值'z',最後回傳local變數var6的值(與global變數var5相同的global物件指標)存於global變數var7中

console.log(var5.proper1);//console輸出置於global變數var5中的global物件的proper1屬性值'a'
console.log(var5.proper2.attr);//console輸出global物件的proper2屬性值(物件指標)的attr屬性值'w'

var5 = '';//修改global變數var5的值為''

console.log(var7.proper2.attr);//console輸出global變數var7的值(global物件指標,此時var5已解除與此物件的reference)的proper2屬性值(物件指標)的attr屬性值'w'

寫到這邊忽然領悟到{}物件形態是指標,無scope限制,文中'global物件'以及'local物件'之修詞並不恰當,應統一稱'物件形態指標'

console.log(var7.proper2.z);//因scope限制,無法存取z屬性中儲存的local物件,console輸出undefined => 更正,物件形態指標不受scope影響,console輸出Object {properx: "z"}

console.log(var7.proper2.z.properx);//因上列原因,無法進一步存取local物件的properx屬性,console輸出undefined => 更正,物件形態指標不受scope影響,console輸出屬性值'z'

//程式碼4執行結果驗證

記憶體管理:

未被任何變數參照的記憶體會被GC回收,然後釋放記憶體(滿足特定條件時,不一定即時)
var ref1 = {
    proper1: 'abc'
};//ref1參照到此物件

var ref2 = ref1;//現在ref2也參照到該物件,該物件被兩個變數參照

ref1 = '';//ref1不再參照到該物件,剩ref2參照

ref2 = '';//現在物件{proper1: 'abc'}已無任何變數參照,將會被GC回收釋放記憶體

更詳細的解說可參考下列連結文章:

簡單理解 JavaScript 的記憶體管理機制

刪除變數使用delete關鍵字


沒有留言:

張貼留言