实例解析JS局部变量与形参之间冲突、全局变量的引用造成的惨案实例分析?

来源:互联网 发布:免费网上审批软件 编辑:程序博客网 时间:2024/06/14 13:38

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;//有没有这个返回无所谓}

有兴趣的童鞋可以下去尝试一下;

最后一个问题:那调用change()之后还能不能使用arr4的原始数据呢?
答案:能。
下方代码引用地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign文章中“Object.assign”的深拷贝问题;

  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}}

免责申明:本文章为笔者原创!上述问题都是根据本人在开发中遇到的实际情况总结出来,所有内容都属于个人见解,不代表其他任何人的看法。上述分享只供学习参考,若导致其他不良后果和第三方纠纷,笔者不承担任何责任!

阅读全文
0 0
原创粉丝点击