adodo0829/blog

函数类型(参数)

Opened this issue · 0 comments

函数类型(参数:arguments对象)

js 函数不限定传递进来多少个参数, 以及参数的数据类型,甚至可以不传参数

arguments对象

函数参数的一些情况, 实参&形参

形参类型不指定,随意传,所以要在函数内部检测
函数调用不对实参进行类型检查, 个数也不定
function add(x) {
  return x+1;
}
# 不同的传递和调用结果也不同, 违背了单一原则
console.log(add(1));   // 2
console.log(add('1')); // '11'
console.log(add());    // NaN
console.log(add(1,2)); // 2
  • 形参同名情况
在非严格模式下,函数中可以出现同名形参,且只能访问最后出现的该名称的形参
function add(x,x,x){
    return x ;
}
console.log(add(1,2,3)); // 3

而在严格模式下,出现同名形参会抛出语法错误
  • 参数个数
1.实参 < 形参: 剩下的形参都将设置为undefined值
function add(x,y){
  console.log(x,y); 
}
add(1); // 1 undefined

2.实参 > 形参: 剩下的实参没有办法直接获得,通过arguments对象
函数参数在内部用一个数组表示。
函数接收到的始终都是这个数组,而不关心数组中包含哪些参数。
在函数体内可以通过arguments对象来访问这个参数数组,
从而获取传递给函数的每一个参数。
arguments对象并不是Array的实例,它是一个类数组对象
function add(x){
    console.log(arguments[0],arguments[1],arguments[2]) // 1 2 3
    console.log(arguments.length) // 3
    return x+1;
}
add(1,2,3);  // 2

3. 实参 = 形参: 参数同步,arguments对象的值和对应形参的值保持同步
function test(num1,num2){
    // 形参与 arguments的命名空间是独立的, 但值是同步的
    // 严格模式下都是独立的
    console.log(num1,arguments[0]); // 1 1
    arguments[0] = 2;
    console.log(num1,arguments[0]); // 2 2
    num1 = 10;
    console.log(num1,arguments[0]); // 10 10
}
test(1);

注意: 当形参并没有对应的实参时,arguments对象的值与形参的值并不对应
function test(num1,num2){
    console.log(num1,arguments[0]);// undefined,undefined
    num1 = 10;
    arguments[0] = 5;
    console.log(num1,arguments[0]);// 10, 5
}
test();
  • 对象参数
当行参定义的太多时, 往往很麻烦(顺序不能乱), 可以传一个对象进来
function addAverage(numObj) {
  return (numObj.x + numObj.y) / numObj.keys().length
}

arguments内部属性

callee

arguments对象有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数, 严格模式下,访问这个属性会抛出TypeError错误;
一般用不到

// 递归时使用
function factorial(num){
    if(num <=1){
        return 1;
    }else{
        return num* arguments.callee(num-1);
    }
}    
console.log(factorial(5)); //120

caller

  • 函数的 caller属性

函数的caller属性保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值是null

function outer(){
    inner();
}
function inner(){
    console.log(inner.caller); 
}
outer(); // ƒ outer(){ inner();}
inner(); // null
  • arguments对象的caller
    该属性始终是undefined,定义这个属性是为了分清arguments.caller和函数的caller属性

通过参数实现函数重载

同一个函数根据传入的参数不同具有不同的功能.
可以通过检查传入函数中参数的类型和数量并作出不同的反应,来模仿方法的重载

function doAdd(){
    if(arguments.length == 1){
        alert(arguments[0] + 10);
    }else if(arguments.length == 2){
        alert(arguments[0] + arguments[1]);
    }
}
doAdd(10);   // 20
doAdd(30,20);// 50

参数传递(值传递,地址传递)

  • 参数为基础类型
# 值传递
var a = 1
function fn(o) {
    o = 3;
    console.log(o) // 3
}
fn(a);
console.log(a) // 1
  • 参数为引用类型(拷贝地址)
# 对函数形参的赋值,不会影响实参的值
var obj = {x : 1};
function fn(o) {
    o = 100; // 此时相当于一个局部变量
    console.log(o) // 100
}
fn(obj);
console.log(obj.x); // 仍然是1, obj并未被修改为100.

# 修改形参对象的属性值,也会影响到实参的属性值
# 会将外部对象内存中的地址复制给一个局部变量
var obj = {x : 1};
function fn(o) {
    o.x = 3;
}
fn(obj);
console.log(obj.x); // 3, 被修改了!

故调用函数传参时,函数接受对象实参引用的副本(虽是副本,引用的对象是相同的)