JavaScript基础之方法 形参以及arguments属性

方法的定义很常见,由两种一个是常规写法,还有要给是函数表达式。

function test(){
    #执行程序
}

#函数表达式
var test1=function(){
    #执行程序
}

形参

JavaScript方法自然也可以进行参数,也就是在方法中先来一个形参进行占位。

function  test(a,b){
    
    
    
   # 执行程序
}

js中形参,不像是java中那样形参中直接定义其必须传输的数据类型。

test(1,2)
test("a","b")
调用都可以运行,甚至参数可以是方法

方法的length属性

方法的length属性得到的是形参的个数。

在这里插入图片描述

JavaScript中的参数传递,可以与形参的个数不同,比如下面:

function test(a,b){
    console.log(a+"   "+b)
    
}
test(1)# 输出的是   1  undefined

test(1,3,4)# 输出的是   1  3
test(b=3)# 输出的是   3  undefined   (为什么会这样输出,因为python中可以直接通过形参名进行赋值,二JavaScript中却不是,而是可以理解为: 创建一个变量b  然后赋值成3,然后将变量b的值传递给test第一个参数a)

方法中的arguments属性

其实方法中还有一个神奇的属性:arguments,不过其经常再方法内部使用。

function test(a,b){
    console.log(arguments.length)
    console.log(arguments[0],arguments[1],arguments[2])
    console.log(a+"   "+b)
    
}
test(1,2,3)

在这里插入图片描述

如果形参和实参不一样的话,可以看出:arguments属性得到的是实参的数据,而不是形参。 所以可以进行下面的一个实例:一个方法计算无论多少个数字参数的的和。

function add(){
    
    
     sum=0;
    for (i in add.arguments) {
    
    
      sum+=arguments[i];
     }
    return sum;
   }   
 # 调用
 test(1,3,4)  # 8
 test(1) #  1
   

不过一点arguments和形参数据一般会修改彼此的值,会影响彼此,但是有些情况下不是的,这个在下面讲。

形参的定义和赋值

讲解这个时候,需要又要扯到var这个定义变量会提升的问题,以及其会变量所在的域。先看下面这个例子:

var a=10;
function test(){
    var a=12
    console.log(a)
}
test()
console.log(a)
#最后输出
12
10
# 这个地方可以看出。如果使用var定义了变量,两个a的值不会相互影响。


var a=10;
function test(){
    a=12
    console.log(a)
}
test()
console.log(a)

#最后输出
12
12
#这个地方可以看出,当变量前面没有什么var修饰的时候,会变成全局变量,相当于 window.a=12,会将前面的var a=10的值修改掉。



var a=10
function test(){
    a=12;
    console.log(a);
    var a=2;# 
}
 console.log(a);

#输出
12
10

# 这个地方是不是很神奇,因为这个没有坐别的事情,只是在方法的域中最后添加var a;
其实这个有点涉及到局部变量(AO)了,后面我们单独一篇聊全局变量BO和AO(很重要的,毕竟了解js的闭包就需要先了解AO和BO)
test()调用方法的时候,
第一步:因为没有传递参数,加载方法的时候,先预缓存的时候,方法域中遇见var a 就提高其位置,所以运行的时候
 变成了:
   function test(){
    var a=undefined;
    a=12;
    console.log(a);
    a=2;# 
    }
这个时候 方法中a变量就被提前使用var ,所方法域中的变成了局部的变量。

讲解参数为什么会说上面呢?请看下面前面聊js中arguments属性的时候,可以看出形参会变成arguments属性的的数组中,如果赋值一样的话,很容易理解。

比如修改两者的数值,都会影响彼此(这个涉及到JavaScript 中的clone后面单独聊,现在记住即可)

function test(a,b){
     console.log(a,b);
	 console.log( arguments[0], arguments[1]);
	   console.log("------------------");
	 arguments[0]=12;
	 arguments[1]=13;
     console.log(a,b);
     console.log( arguments[0], arguments[1]);
	  console.log("------------------");
     a=12;
	 b=13;
     console.log(a,b);
     console.log( arguments[0], arguments[1]);

	}
	
# 输出
test(1,2)


在这里插入图片描述

但是涉及到一个如果传参数,和形参不一样呢?

function test(a,b){
     console.log(a,b);
	 console.log( arguments[0], arguments[1]);
     console.log("------------------");
    a=66;
   var b=99;
    
    console.log(a,b);
     console.log( arguments[0], arguments[1]);
    arguments[0]=44;
     arguments[1]=88;
     console.log(a,b);
	 console.log( arguments[0], arguments[1]);
     console.log("------------------");
    
}
# 其中 b前面带不带 var 这个关键字都不会影响结果(下面截图 b前面带var 演示)
test(1)

在这里插入图片描述

简单总结:如果形参在函数调用的时候赋值了,那就会和arguments属性中下标对应的数值相互影响否则不会。

为什么会出现这个状况:

形参和实参为什么会影响彼此呢:

  • 第一:形参和实参(arguments)本质上是不同的东西。形参在栈中,而arguments其数据存在堆中,而指向数据的指针存在栈中。
  • 第二:但是为什么修改彼此会影响。因为在方法这个里面,两者的数据会形参一个影响彼此的映射。如果在调用方法中形参中的一个未被赋值,那这个映射就不会形成,同意如果传递的参数个数多余形参,多余的也不会形成映射。

形参默认值

其实在JavaScript中形参可以设置默认值的,比如下面:

#这个只有在es6版本的时候才会支持。
function test(a=1,b){
     console.log(a,b);
}

在这里插入图片描述

可以看出a的值默认是1也可以打印出来,但是又涉及一个神奇的问题

那就是如何给b传值而你修改a的值?

function test(a=1,b){
     console.log(a,b);
}

test(2) #这样调用还是直接让a=2,b=undefined
test(1,2)#这个当然也可以,但是好像也没有什么意义了。如果公司很多接口说这个方法调用第一个参数用默认值,难道每次都看一下接口源码?
test(undefined,2)# a=1 b=2

#如果使用 null,NaN 也会影响a的值

在这里插入图片描述

前面说过,形参和实参是映射关系,但是如果用了默认值,那就是映射关系就不存在了,彼此不会影响彼此

function test(a=1,b){
     console.log(a,b);
	 console.log( arguments[0], arguments[1]);
     console.log("------------------");
    a=66;
   var b=99;
    
    console.log(a,b);
     console.log( arguments[0], arguments[1]);
    arguments[0]=44;
     arguments[1]=88;
     console.log(a,b);
	 console.log( arguments[0], arguments[1]);
     console.log("------------------");
    
}

在这里插入图片描述

两者关系不在映射影响彼此,但是形参还是可以得到实参的值,如果对应的形参和实参,其中一个是非undefined 一个是undefined的,那么方法会使用非undefined的值。

如果是es5也要又类似的用法咋办?

第一种:
 function test(a,b){
     
     #使用if 这个需要使用typeof这个方法
     if (typeof(arguments[0])!=="undefined"){
         a=arguments[0]
     }else{
         
         a=1
     }
     
 }


第二种:三目运算符
 function test(a,b){
     
     #使用if 这个需要使用typeof这个方法
     a=typeof(arguments[0])!=="undefined")?arguments[0]:1

     
 }


第三种:
 function test(a,b){
     
     #使用|| 这逻辑运算符 ""(空字符串) NaN null undefined 0  转换布尔都是false
     a=arguments[0]|| 1;
  
     
 }



补充

这种现象是突然发现的,自己还是有点没有绕明白,不过先让大家记住这种现象(为了方便记住,还是用上面例子进行对比。)

function test(a,b){
     console.log(a,b);
	 console.log( arguments[0], arguments[1]);
	   console.log("------------------");
	 arguments[0]=12;
	 arguments[1]=13;
     console.log(a,b);
     console.log( arguments[0], arguments[1]);
	  console.log("------------------");
     a=12;
	 b=13;
     console.log(a,b);
     console.log( arguments[0], arguments[1]);

	}
	
# 输出
test(1,2)



在这里插入图片描述

	
	
	function test(a,b){
    
    
	
     console.log(a,b);
	 console.log( test.arguments[0], test.arguments[1]);
	   console.log("------------------");
	 test.arguments[0]=12;
	 test.arguments[1]=13;
     console.log(a,b);
     console.log( test.arguments[0], test.arguments[1]);
	  console.log("------------------");
     a=12;
	 b=13;
     console.log(a,b);
     console.log( test.arguments[0], test.arguments[1]);

	}
	
	

在这里插入图片描述

发现再调用arguments的时候,再方法中也可以直接调用,但是无意中用方面名进行调用。就发现一点,那就是

通过带有方法名test.arguments[0]赋予值,不会修改形参传递的值。但是修改形参的值后会影响它,所以觉得是test.arguments每会复制一个新的数组,而这个方法中直接arguments,默认是一个参数数组,而这个数组会指向形参指针所指的地址,所以看下面:

	
	
	function test(a,b){
     console.log(a,b);
	 console.log(arguments);
	 console.log(test.arguments);
	 console.log(arguments==test.arguments);
	 console.log(arguments===test.arguments);
	 console.log("------------------");
    console.log(test.arguments==test.arguments);
	 console.log(test.arguments===test.arguments);
	  console.log("------------------");
   console.log( arguments==arguments);
	 console.log(arguments===arguments);
	}
	
#执行
	
test(1,3)

在这里插入图片描述

通过这个结果可以看出预测的还算正确,不过这个需要补充一点,目前只知其果,而本人还没有捋清楚具体的运行逻辑以及过程。

arguments本质是类数组

前面一直说其是数组,因为方便解释,但是其本质还真不是数组,而是一直类数组。不信看下面

function test(a,b){
    var arr=[1,3,4];
    console.log("arr的本质",typeof(arr));
    console.log("arguments的本质",arguments);
}

在这里插入图片描述

可见两者的typeof的返回值还是不一样的,这个地方涉及到一个问题,那就是数组的typeof为什么返回的是一个Object。这个问题后面聊。

return

函数默认带有一个return

function test(){
    执行程序
    return;#如果不写,系统运行的时候会自动添加一个
    
}

所以默认调用函数,都会返回一个undefined。当然如果自己添加一个return 如果程序安装逻辑运行此命令就会终止这个方法后的程序执行。

这个先不深入讲解了,后面的闭包的时候可以在深入了解一下return的妙用。

递归

简单的说,就是自己调用自己,会让代码看着简洁,但是会消耗系统性能。这个就不再阐述,很多编程语言中都有,直接用一个方法演示。比如输入要给数字,求出1到这个值的和

function test(n){
    if (n<1){
       return "输出值有问题,请检查重新输入";
        }
    if (n==1){
        return 1;
        }
    return n+test(n-1);
    
    
}


猜你喜欢

转载自blog.csdn.net/u011863822/article/details/121062463