理解Javascript_14_函数形式参数与arguments 【转】

在‘执行模型详解‘的‘函数执行环境‘一节中对arguments有了些许的了解,那么让我们深入的分析一下函数的形式参数与arguments的关系。

注:在阅读本博文前请先阅读《理解javascript_13_执行模型详解》

注:本文的部分内容是自已的一些推论,并无官文文档作依据,如有错误之后,还望指正。

生涩的代码

我们先来看一段比较生涩的代码:


1

2

3

4

5

6

7

8

9

10

11

function say(msg,other,garbage){

    alert(arguments[1]);//world

    var other = ‘nice to meet you!‘;

    var msg;

    alert(arguments.length);

    alert(msg);//hello

    alert(other);//nice to meet you!

    alert(arguments[1]);//nice to meet you!

    alert(garbage);//undefined

}

say(‘hello‘,‘world‘);

  你能正确的解释代码的执行结果吗?思考一下.

  我想代码运行的结果,应该会和你的想象有很大的出入吧!为什么msg正常输出为hello,而不是undefined呢?函数定义的参数和函数内部定义的变量重复了会发生什么呢?arguments和函数定义时的参数有什么关系呢?让我们来一一解答:

简单的内存图

注:虚线表示的是曾经引用的指向。

解答

  首先,我们来了解两个概念,形式参数和实际参数。形式参数指的是定义方法时所明确指定的参数,由于Javascript语言的灵活性,javascript并不要求方法调用时,所传递的参数个数与形式参数一致.而javascript实际调用时所传递的参数就是实际参数。arguments指的就是实际参数。从say方法中可以看出,say定义了三个形式参数,而实际调用时只传递了两个值。因此arguments.length的值为2,而不是3.接着我们来看一下arguments的特殊行为,个人感觉arguments会将所有的实际参数都当作对象来看待,对于基本数据类型的实际参数则会转换为其对应的对象类型。这是根据在函数内定义与形式参数同名的变量并赋值,arguments对应的值会跟着改变来判断的。

接着我们来分析一下构建say方法执行上下文的过程,由于逻辑比较复杂,这里我写一些‘伪代码‘来进行说明:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

function say(msg,other,garbage){

    //先对函数声明的变量进行‘预解析‘,内部执行流程,它是是不可见的

    var msg = undefined;

    var other = undefined;

    var garbage = undefined;

    //再对函数内部定义的变量进行‘预解析‘

    var other = undefined;//很明显,此时这个定义已经无意义了。

    var msg = undefined;//无意义

    

    //对实际参数进行赋值操作

    msg = new String(‘hello‘);//arguments的会将所有实际参数当作对象看待

    other = new String(‘world‘);

    //正式进入函数代码部分

    alert(arguments[1]);//world

    other = ‘nice to meet you!‘;

    //var msg;这个已经被预解析了,因此不会再执行

    alert(arguments.length);//2

    alert(msg);//hello

    alert(other);//nice to meet you!

    alert(arguments[1]);//nice to meet you!

    alert(garbage);//undefined

}

这段代码已经可以解释一面的所有的问题了。我就不多说了。

唯一强调的一点是在内部用var定义与形式参数同名的变量是无意义的,因为在程序‘预解析‘后,会将它们看作为同一个变量。

其它

关于arguments还有很多特性,我在《伪数组》一文中提到也提到了arguments,有兴趣的读者可以去看一下。arguments的实际应用你还可以参考一下这一篇文章 :


1

<a href="http://www.gracecode.com/archives/2551/">http://www.gracecode.com/archives/2551/</a>

时间: 2025-01-18 09:08:25

理解Javascript_14_函数形式参数与arguments 【转】的相关文章

jacascript 函数参数与 arguments 对象

前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 调用函数时,实参和形参需要一一对应,但如果参数多了的话,会很苦恼: 我们可以用键值对(字面量对象)的方式传参,这样参数的顺序就无关紧要了: <script type="text/javascript"> function test4(name,age,height,pos){ return name+age+height+pos; } console.log(test4('Shan

深入理解javascript函数系列第三篇

前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数系列第三篇--属性和方法 属性 [length属性] 函数系列第二篇中介绍过,arguments对象的length属性表示实参个数,而函数的length属性则表示形参个数 function add(x,y){ console.log(arguments.length)//3 console.log(

JavaScript服务器端开发(函数实参对象arguments使用的几个注意事项)

为什么引入实参对象arguments 在JS开发中,每一个函数都对应一个实参对象,称为arguments.这个对象引用的目的是为了解决如下问题: 当调用函数的时候传入的实参个数超过函数定义时的形参个数时,没有办法直接获得未命名值的引用. 因为JS函数定义与调用极其灵活,参数个数是不确定的,而且系统也不会作自动检测.这为开发带来灵活性的同时也带来相当的麻烦.下文将结合实际开发中使用到arguments时经常遇到的几个"麻烦"进行讨论,并给出对应的解决方案. 在函数体内,标识符argume

理解JavaScript函数参数

前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数. arguments javascript中的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查.实际上,javascript函数调用甚至不检查传入形参的个数 ? 1 2 3 4 5 6 7 function add(x){ return x+1; } console.log(add(1));//2 console

正确理解Python函数是第一类对象

正确理解 Python函数,能够帮助我们更好地理解 Python 装饰器.匿名函数(lambda).函数式编程等高阶技术. 函数(Function)作为程序语言中不可或缺的一部分,太稀松平常了.但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性.那到底什么是第一类对象呢? 函数是对象 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性

2、函数内部属性 arguments是类数组对象,主要用途是保存函数参数,但这个对象中有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数

例如:(1).function factorial(num){ if(num<=1){ return 1; }else{ return num*factorial(num-1); } }//此时是递归算法 var trueFactorial=factorial;//将factorial复制给trueFactorial factorial=function(){ return 0; }//覆盖factorial函数 alert(trueFactorial(5));//0;因为辞职factorial

理解fork()函数

学习 C 语言的进程概念时,会遇到 fork()函数.而遇到时要是有例子,会像下边的样子.执行后双输出.起初见到时,甚为难以理解. 我把见到的例子略作修改,以便于我理解这个函数涉及的进程概念. vim child_process.c    gcc child_process.c ./a.out 这里的显示表示运行在父进程中.[[email protected] chapter 7 进程控制]# 这个显示内容是在子进程中输出的. echo $? 3 ------------------------

More Effective C++----(24)理解虚拟函数、多继承、虚继承和RTTI所需的代价

Item M24:理解虚拟函数.多继承.虚继承和RTTI所需的代价 C++编译器们必须实现语言的每一个特性.这些实现的细节当然是由编译器来决定的,并且不同的编译器有不同的方法实现语言的特性.在多数情况下,你不用关心这些事情.然而有些特性的实现对对象大小和其成员函数执行速度有很大的影响,所以对于这些特性有一个基本的了解,知道编译器可能在背后做了些什么,就显得很重要.这种特性中最重要的例子是虚拟函数. 当调用一个虚拟函数时,被执行的代码必须与调用函数的对象的动态类型相一致:指向对象的指针或引用的类型

函数中的 arguments 对象

JavaScript函数具有像数组一样的对象,这些对象称为arguments,与传递给函数的参数相对应.传递给JavaScript函数的所有参数都可以使用arguments对象来引用. 现在我们开始学习,仔细看下面列出的代码: function add(num1, num2) { var res = num1 + num2; return res; } var r = add(7, 8); console.log(r); 在上面的函数中,num1和num2是两个参数.你可以使用名为num1和nu