理解JavaScript(1):JavaScript函数参数传递

JavaScript函数参数传递

javascript函数的参数与大多数其他语言的函数的参数有所不同。javascript中的函数定义并未指定函数形参的类型,也不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数。

参数传递规则

  • 函数同名,后面的函数会覆盖前面的函数
function add (a, b) {
    return a + b;
}
function add (a, b) {
    return a + a + b;
}
console.log(add(1, 2)); // 4
  • 在非严格模式下,函数中可以出现同名形参,且只能访问最后出现的该名称的形参,而在严格模式下,出现同名形参会抛出语法错误
function get(x, x, x) {
    return x;
}
console.log(get(1, 2, 3)); // 3
  • 当实参比函数声明指定的形参个数要少,剩下的形参都将设置为undefined值,常常使用逻辑或运算符给省略的参数设置一个合理的默认值,当实参比形参个数要多时,剩下的实参没有办法直接获得,需要使用即将提到的arguments对象。
function add (x, y, z) {
    console.log(x, y, z);
    console.log(arguments);
}
add(1, 2, 3, 4); 
// 1,2,3
// [1,2,3,4]
  • javascript中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制到函数内部的参数,就和把值从一个变量复制到另一个变量一样。在向参数传递基本类型(Undefined、Null、Boolean、Number、String(虽然String有些特殊))的值时,被传递的值会被复制给一个局部变量(命名参数或arguments对象的一个元素);在向参数传递引用类型(Object,Array,Function)的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部,当在函数内部重写引用类型的形参时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁
// 内部不重写形参
var argumentsChange0 = function (paramter) {
    // 判断是否为数组, 为了对值类型和引用类型做不同的处理
    if (Object.prototype.toString.call(paramter) === "[object Array]") {
        paramter[0] = 1;
    } else {
        paramter = '1';
    }
}
// 内部重写形参
var argumentsChange1 = function (paramter) {
    // 判断是否为数组, 为了对值类型和引用类型做不同的处理
    if (Object.prototype.toString.call(paramter) === "[object Array]") {
        var paramter = [0, 1, 2];
        paramter[0] = 100;
    } else {
        var paramter = '0';
        paramter = '100';
    }
}
// 值类型传递
var string = '0'; 
argumentsChange0(string);
console.log('string:', string); // string:'0'
string = '0';
argumentsChange1(string);
console.log('string:', string);// string:'0'
// 值类型传递不会改变函数外部的变量

// 引用类型
var arr = [0, 1, 2];
argumentsChange0(arr);
console.log('arr:', arr); // arr:[1,1,2]
arr = [0, 1, 2]
argumentsChange1(arr);
console.log('arr:', arr); // arr:[0,1,2]

arguments对象

实际上,javascript函数调用甚至不检查传入形参的个数,javascript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数。在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

  • arguments对象并不是Array的实例,它是一个类数组对象,可以使用方括号语法访问它的每一个元素。可以通过arguments.length查询实际调用函数传入的参数,可以通过函数的length属性显示形参的个数。形参只是提供便利而不是必须的
function argumentsToArray () {
    return Array.prototype.slice.call(arguments, 0, arguments.length);
}
console.log(argumentsToArray(1, 2, 3)); // [1,2,3]
console.log(argumentsToArray(1, 2, 3) instanceof Array); // true
  • 当形参与实参的个数相同时,arguments对象的值和对应形参的值保持同步,但在严格模式下,arguments对象的值和形参的值是独立的。当形参与实参个数不同时arguments对象的值和对应形参的值不对应。这是很好理解的

  • arguments对象有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数,但是,上面这个函数的执行与函数名紧紧耦合在了一起,可以使用arguments.callee可以消除函数解耦,但在严格模式下,访问这个属性会抛出TypeError错误,这时,可以使用具名的函数表达式

function factorial (num) {
    // 'use strict'; 
    // 如果加上'use strict'运行的时候会抛出 "TypeError:'caller',''callee',and 'arguments' may not be access on..."
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num - 1);
    }
}
console.log(factorial(5));  

对其加以改进

var factorial = function fn(num) {
        if (num <= 1) {
        return 1;
    } else {
        return num * fn(num - 1);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值