1. 程式人生 > >例項解析JS區域性變數與形參之間衝突、全域性變數的引用造成的慘案例項分析?

例項解析JS區域性變數與形參之間衝突、全域性變數的引用造成的慘案例項分析?

1.JS區域性變數與形參之間的衝突

(1).區域性變數慘案例項:


首先建立一個全域性陣列變數arrayList;
var arrayList= [
    {tel:1234657,name:'a'},
    {tel:1234658,name:'b'},
    {tel:1234659,name:'c'},
    {tel:1234651,name:'d'},
    {tel:1234652,name:'e'},
]


//普通方法openSign(i),形參i;
function openSign(i){
    for(var i=0;i<arrayList.length; i++){
        if
(arrayList[i].name == 'e'){ showLog('此處已執行'); return; } } return arrayList[i]; }

(2).呼叫openSign(1)結果返回的結果為undefined;並不是{tel:1234658,name:’b’}物件;
原因分析:首先,例子中有個重要的變數i,形參和for迴圈中都有i變數,js中的變數無論在任何情況下都會有“變數提升”,變數提升後i的作用域並不只是在for迴圈中有效,而是整個方法openSign中有效,當形參遇到區域性變數時,區域性變數優先順序高於形參,當for迴圈執行完之後i就是arrayList的長度值5,而arrayList[5]並不存在,所以取出的內容就是undefined。如果想正確輸出{tel:1234658,name:’b’}物件,可以將for迴圈中的變數i換成其他字母表示即可。

**

2.全域性變數與形參的賦值慘案例項:

**
(1).建立全域性變數 arr1,arr2,arr3,var arr4;和函式change();//並將arr4賦初值。

var arr1,arr2,arr3;
var arr4 = [
    {name:'張山1',age:'男'},
    {name:'張山2',age:'男'},
    {name:'張山3',age:'男'},
    {name:'張山4',age:'男'},
    {name:'張山5',age:'男'}
];

function change(params){//形參params
    for
(var i = 0; i<params.leng;i++){ params.name = params.name +'aaa';//這種場景大家都遇到過吧 } return params;//有沒有這個返回無所謂 }

(2).將arr4賦值給其他全域性變數

arr1 = arr4;
arr2 = arr4;
arr3 = arr4;

將其中的arr1 ,arr2 ,arr3 任何一個作為實參傳遞給(1)的中函式change();

如:change(arr2);

(3).經過(2)的函式呼叫之後如果你不再使用全域性變數arr4中的原始值,你可能並不覺得有什麼異常,但是,如果你在呼叫過change()函式之後還想使用arr4中的原始值,那麼慘案此時已經出現:此時你會發現arr4中打印出的值變成下面的樣子:

    {name:'張山1aaa',age:'男'},
    {name:'張山2aaa',age:'男'},
    {name:'張山3aaa',age:'男'},
    {name:'張山4aaa',age:'男'},
    {name:'張山5aaa',age:'男'}

原因解析:js中同一內容的全域性變數無論為賦值給n個其他全域性變數或形參,只要修改其中的一個全域性變數的值被修改,那麼該內容所有被賦值或間接賦值的全域性變數或形參的值都會被修改。

有同學可能很困惑,為什麼我在change()函式中只是使用了它的形參進行改變name屬性而已,為什麼arr4中的所有name的值也被改變了呢?如果你把arr1 ,arr2 ,arr3的值都打印出來,你會發現他們的值都變了;

上述原因分析如下:

在計算機記憶體中,系統對變數的申明在“棧”中,變數的值在“堆”中,賦值時的內容地址指向如下:
這裡寫圖片描述

上圖是解釋該問題比較直觀的方式,再詳細點解釋:

arr1 = arr4; arr2 = arr4; arr3 = arr4 的賦值只是將arr4的值的地址指向了arr1,arr2,arr3;記憶體中並沒有為其建立內容空間,這樣就導致直接或間接的修改變數的值,那麼原始值都將被修改。注意形參也是區域性變數,及變數;到此,上述問題原因已經解釋完了。

有同學可能這樣想,那在change()中重現建立一個數組或物件能不能解決這個問題呢?答案不能。

例如:

function change(params){//形參params
    var arrTemp = new Array();//有時可能場景是 var objTemp = Object();
    for(var i = 0; i<arrTemp.leng;i++){
        arrTemp.name = arrTemp.name +'aaa';
   }
   return arrTemp;//有沒有這個返回無所謂
}

有興趣的童鞋可以下去嘗試一下;

  obj1 = { a: 0 , b: { c: 0}};
  let obj3 = JSON.parse(JSON.stringify(obj1));
  obj1.a = 4;
  obj1.b.c = 4;
  console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

為了能及時的將自己踩到的前端坑分享給大家,以後會逐漸將文章轉移到微信公眾號:前端e家(front_e_family)。可直接掃碼關注,公眾號會不定期更新新文章,分享踩坑筆記!期待您的關注!
這裡寫圖片描述