你的位置:首页 > Java教程

[Java教程]JavaScript:修改作用域外变量


  1. 今天在看JavaScript学习指南的时候做的课后习题,也因此详细的对函数的传入参数进行比较深入的研究.

题目如下:

  函数如何才能修改其作用域之外的变量?编写一个函数,由1~5的数字组成的数组作为参数,调用该函数后将把其中的数字项替换为相应的字符串表示形式.

需要注意知识点:

  在JavaScript中函数参数的传递,对于基于原始值的参数进行值传递(数字,字符串,布尔值),函数中的修改不会影响实际参数值.而传递给函数的参数而言,对象是一个引用,对其的修改的将会反映在主调程序中.<-但是,会有这样的情况,如下

 1 var outer_number = 2; 2 var outer_boolean = true; 3 var outer_array = [1,2,3]; 4 var outer_object = {test:"122"}; 5 function display(num,bool,arr,obj){ 6 console.log("number:"+num+"\nboolean:"+bool+"\narray:"+arr+"\nobject:"+obj.test); 7 } 8  9 function test(num,bool,arr,obj){10  display(num,bool,arr,obj);//num=2,bool=true,array=[1,2,3],object.test=12211  num = 0;12  bool = false;13  arr[3] = 3;14  obj.test = "134";15  display(num,bool,arr,obj);//num=0,bool=false,array=[1,2,3,3],object.test=13416  17  arr = [3,2,1];18  obj = {test:"133"};19  display(num,bool,arr,obj);//num=0,bool=false,array=[3,2,1],object.test=13320 }21 test(outer_number,outer_boolean,outer_array,outer_object);22 display(outer_number,outer_boolean,outer_array,outer_object);//num = 2,bool=true,array=[1,2,3,3],object.test=134

在上面代码中我们创建了4个全局变量,类型分别为数字,布尔值,数组,对象.2个函数,display和test.

display执行了4次,分别结果如下:

    • "number:2
      boolean:true
      array:1,2,3
      object:122"<-传入函数时的值
    • "number:0
      boolean:false
      array:1,2,3,3
      object:134"<-执行更改
    • "number:0
      boolean:false
      array:3,2,1
      object:133"<-重新赋值
    • "number:2
      boolean:true
      array:1,2,3,3
      object:134"<-函数执行完毕后

可以看出我们对数组和对象的重新赋值并没有成功,如果按引用传递,那么我们应该也对全局变量的数组和对象重新赋值修改了呀.
其实JavaScript中所谓的按引用赋值并不是真正意义上的按引用复制,准确说应该是按共享传递.也可以叫按对象传递,按对象共享传递(call by sharing).
在这个按共享传递的条件下,我们获取的引用可以说只是实参引用的副本,它和我们经常说的按引用传递的最大差别就在于我们在对引用副本的赋值不会影响实参的值,正如我们上面那样做的那样,赋值操作是不可行的.

当然我们从对象类型和基本类型两方面看,对象是可变的基本类型是不可变的(注意!字符串修改其实是返回的新的字符串),所以按共享传递对于基本类型来说也是符合按共享传递的.

总结一下:

  JavaScript中,基本类型和对象都按共享传递(call by sharing),但是由于JavaScript的基本类型的不变性,基本类型按共享传递与按值传递没有任何区别,而对象按共享传递.

按共享传递(call by sharing):传递的是实参引用的副本,我们对引用副本的赋值不影响实参的值,但是可以使用引用副本去修改引用的内容.详细的wiki地址

函数对传入的参数:

  1. 基本类型,按值传递(或者也可以说按共享传递),内部赋值修改都不影响主调程序
  2. 对象类型,按共享传递,传入的为实参引用的副本,内部对该引用的赋值无效,对对象属性的赋值修改有效.

大概就是这么理解了,假如有什么地方我犯了什么错误,也希望能被指出来.

参考文章:

JS是按值传递还是按引用传递
赋值策略(wiki)