# 函数参数与返回值

# 函数的参数

可以动态的改变函数的变量的类型与值,使同一函数实现不同的效果

当我们封装一个功能,例如十行十列表格,但是每次使用该功能时想动态改变实现效果,例如想输出为五行五列、两行两列的表格,这时就需要修改函数体代码。 而更好的方法就是,在调用时有使用者传入一些值来控制函数体中的相关功能,即可实现不同效果,这个使用者在调用函数时传入的值就是函数的参数。

# 参数作用

可以动态的改变函数的变量的类型与值,使同一函数产生不同的结果。

# 参数类型

  • 形参:函数在定义时,括号里所定义的变量。 (形式上存在,只有在被调用时才有值)
  • 实参:函数在调用时,括号里所传入的值。 (进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参)
// num 是形参
function ta(num){
	for(var i = 1;i <= num;i++){
	    for(var j = 1;j <= num-i;j++){
		    document.write("&nbsp;");
	    }
	    for(var k = 1;k <= i*2-1;k++){
		    document.write("*");
	    }
	    document.write("<br>");
  }
}
ta(6);    // 6 是实参

在实参为形参传递过程中,实参和形参位于内存中两个不同地址中,实参先自己复制一次拷贝,再把拷贝复制给形参。所以,在函数体中,形参的变化不会对实参有任何的影响。例如:

var number = 10
function fun(number){
    number = 100
}

fun(number);
alert(number);   // 10

# 参数详解

  1. 参数可以是任何的数据类型
  • 参数个数
  • 参数尾逗号

# 参数数据类型

参数可以是任何的数据类型

function TYPEOF(type){
alert(typeof type);
}
TYPEOF(1)
TYPEOF("a")
TYPEOF(true)
TYPEOF(null)
TYPEOF()
//甚至可以传入函数:
TYPEOF(function(){alert(1)})

# 参数个数

  1. 实参与形参的个数相同时,一一对应。

  2. 实参小于形参时,形参自动赋值为undefined。

    function aa(a,b){
        alert(a);
        alert(b);
    }
    aa(1);  //   1  undefined
    
  3. 实参大于形参时,使用arguments对象来获取。

    function aa(a,b){
        alert(a);
        alert(b);
        alert(arguments.length);
        alert(arguments[2]);
        alert(arguments.callee);
    }
    aa(1,5,7);   //依次弹出 1  5  3   7  函数本身
    
  4. arguments对象 在创建函数时,隐式的创建了arguments对象,它是用来记录函数的参数的信息的,只能在函数内部使用
    它的属性:
    * length: 函数的参数的长度
    * callee: 对函数本身的调用
    * 可以通过下标来访问具体参数的值。

    注:arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组。

  5. [es6]rest参数 ES6

    ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

    function fun(...a){
        console.log(a);    // [1,2,3,4]
    }
    fun(1,2,3,4)
    
    function fun(a, ...b){
        console.log(a,b);    //1   [2,3,4]
    }
    fun(1,2,3,4)
    
    // rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
    function f(a, ...b, c) {
        // 报错
    }
    

# 严格模式

函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。 ES2016

// 报错
function doSomething(a, b = a) {
  'use strict';
  // code
}

// 报错
const doSomething = function ({a, b}) {
  'use strict';
  // code
};

// 报错
const doSomething = (...a) => {
  'use strict';
  // code
};

const obj = {
  // 报错
  doSomething({a, b}) {
    'use strict';
    // code
  }
};

# 参数尾逗号

在ES7种,函数实参和形参末尾可以以逗号结束:ES2017

function fun(a,b,){ }

fun(10,20,)

功能:重新排列元素项,改变最后一个元素位置时不需要增删逗号

# 函数的重载

一个函数通过传入的参数的个数不同或者参数类型的不同,可以对应函数的多个实现,而且每一种实现对应一个函数体。
重载函数常用来实现功能类似而所处理的数据类型不同的问题。

模拟函数的重载:

function fun(a,b){
    if(arguments.length == 1){
            alert("只有一个参数"+a);
    }
    if(arguments.length == 2){
            alert(" 有两个参数"+a+"和"+b);
    }
    if(arguments.length >= 3){
            alert("参数太多了");
    }
}
fun(1,3.4,4);

# [es6]函数参数默认值 ES6

// 该函数计算两数之和,但如果调用只传入一个参数则结果是NaN,所以必须为参数设置默认值0
function add(a,b){
    return a+b
}

# ES5设置默认值方式

使用短路原则为变量设置默认值

// 利用短路原则为函数参数设置默认值,参数存在则取参数,参数未传则取0
function add(a,b){
   a = a||0;
   b = b||0;
   return a+b
}
// 为变量设置默认值1
var num = num || 1

# ES6函数参数设置默认值

ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。

function add(x, y = 0) {
console.log(x, y);
}
log(10) // 10 0
log(10, 100) // 10  100
log(10, '') // 10

参数默认值可以与解构赋值的默认值,结合起来使用。

function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined

# 函数的length属性 ES6

函数的length属性,将返回没有指定默认值的参数个数,仅包括第一个具有默认值之前的参数个数。

function aa(a){}
function bb(a=5){}
function cc(a,b,c=5){}

console.log(aa.length) // 1
console.log(bb.length) // 0
console.log(cc.length) // 2

# name属性 ES6

函数的name属性,返回该函数的函数名。

function foo() {}
foo.name // "foo"

这个属性早就被浏览器广泛支持,但是直到 ES6,才将其写入了标准。

需要注意的是,ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。

# 函数返回值

函数体中的计算结果可以输出查看,但是如果想对函数的结果进行处理则需要用到函数的返回值。

函数体中的关键字 return 可以将函数体中运行的结果返回给函数外部:

function fun(a,b){
    var num = a+b;
    return num;
}
var end = fun(1,2);    // 函数运行结果保存到变量end中

# return 的功能

  1. 将函数运行结果返回
  2. 停止并跳出当前函数 (不会执行return后面的语句)
function aa(){
  return;
  alert("hello world");
}
aa();   // 没有弹出 hello world

一个函数可以有多个return语句,但只有一个return执行(常用于判断)

function aa(a){
    if(a>0){
        alert(a);
        return;
    }
    if(a<=0){
        alert(a);
        return;
    }
}
aa(3);  //  3

# 函数返回值使用事项

  1. 返回值可以是任何数据类型
  2. 每个函数都默认有返回值,如果一个函数没有写return,会默认返回undefined
```javascript
function aa(a){
	if(a>0){
		alert(a);
		return;
	}
	if(a<=0){
		alert(a);
		return 1;
	}
}
alert(aa(3));   //  3  undefined
alert(aa(0));   //  0  1
```
  1. 一个函数只能有一个返回值。
```javascript
function bb(a,b,c){
	return a,b,c;
}
alert(bb(3,5,7)); //  7
```
原因:用逗号做返回值时,是按从左到右赋值的,最终赋值为最后一个值,前面的值被覆盖了。
> 如果想返回多个值,则可以将多个值打包为数组或对象