JavaScript基础之function

JavaScript基础四

函数

JavaScript当中,语句是构成代码的基本单位,而函数又是构成代码段(结构)的基本单位(函数就是一个片段的代码)

ECMAScript:函数是可以封装任意多条语句,而且可以在在码的执行过程当中,任意多次的调用去执行的,我们叫函数

  1. 函数是需要去封装的,function
  2. 封装以后的函数如果不去调用,它是不会执行的
  3. 调用函数的时候,我们是通过函数的名子+()来完成的,如果有参数,则在括号时面写义相应的参数,参数与参数之间通过,逗号去隔开

函数是通过关键字function去声明,它的语法格式如下所示

function 函数名(参数1,参数2...){
    //要封装的代码
}

在EMCAScript里面,我们的函数也叫方法

在JavaScript当中,我们的创建一个方法除了使用上面真用function去定义以外,还可以使用另一种方式去封装一个方法,格式如下

var 方法名=function(参数1,参数2...){
    //要封装的方法
}

注意事项:上面的两种方法都可以创建(封装)我们的方法

请看下面的例子

a();
b();
var b=function(){
    document.writeln("吃了没,世界");
}
function a(){
    document.writeln("hello world");
}

说明:在上面的代码当中,我们执行b()的方法的时候,它会报错,因为这个时候的b是通过我们的关键字var定义出来的,根据代码的运行顺序,最先出来的是function所以a()它不会出问题,而调当我们调用b()的时候,这个时候的了它只是定义了,但是没有赋值,它还是undefined,这个时候,它就会报undefined is not a functioin的错误信息

函数的参数

参数是方法在定义的过程当中,所需要指定的变量,它定义的时候,直接写在function后面的括号里面,如下代码所示

function sayHello(name){  //这一个时候,这个name它就是参数,参数的定义,不需要添加关键字
    //var name;  //如果定义在这里,叫局部变量
    document.writeln("大家好,我是:"+name);
}
sayHello("张三");
sayHello("李四");

小提示:我们的参数其实与变量意义差不多,都是在方法的内部使用,在方法内部定义变量的时候,我们使用var,代码写在方法体里面,而参数则写在function后面的括号里面,并且不需要任何关键字

参数的类型

形参

形参指的是形式参数,也就是在定义方法的时候,定义的那一个参数,如下所示

function abc(n){
    console.log(n);
}

说明:上面的代码当中,我们的n就是形式参数,形式参数统一没有默认值(undefined)

实参

实参指的是方法在调用的过程当中,我们传进去的参数,如下代码所示

function abc(n){
    console.log(n);
}
abc("王五");

说明:上面的代码当中,我们的“王五”它就是实际参数,因为这个参数它是一个实际的值

在方法调用执行的过程,我们的参数值的传递方向是由实参传向形参

arguments参数组和

arguments它是一个参数组合,它也是方法里面一个内置的变量,只有在function的内容才能去调用它,它在function里面默认会存在,不需要去自己去定义

arguments与我们的方法的参数有关,它里面存放的是我们在调用方法的时候,传进去的参数(实参),它是我们方法参数(实参)的集合

关于形参数个与实参个数不一致的情况

  1. 形参个数大于实参个数

    前面的参数会一一对应,后面没有赋值的参数为undefined

  2. 形参个数小于实参个数

    所有的形参与实参都会一一对应,但是多于的实参不能够参过形参名去调用,只能通过arguments+序号

  3. 形参个数等于实参个数

    这个时候,形参与实参一一对应

案例

现在要求写一个方法,这个方法是把所有的参数进行相加(只考虑数字),然后把得出来的和打印出来

function plus(){
    //形参的个数是0
    //          var sum=arguments[0]+arguments[1]+arguments[2]+arguments[3]+arguments[4]+arguments[5];
    //          document.writeln(sum);
    //          
    var sum=0;
    for(var i=0;i<=arguments.length-1;i++){
        sum=sum + arguments[i];
    }
    document.writeln(sum);
}
plus(2,6,9,11,45,23);

方法没有重载(overload)

概念:方法重载指的在定义方法的时候,有多个相同名子的方法,但是这些方法的参数类型或参数个数不相同

思考:为什么在JavaScript里面,我们没有方法重载这个概念?

  1. 在JavaScript里面,JS的数据类型是一个弱类型,这个参数具体是什么类型,由调用的时候,传入的值决定(没有参数类型的概念)
  2. 我们的JS方法里面,实参的个数与形参的个数可以不一致,它是由arguments来决定的,所以,我们在定义方法的时候,如果定义了N个形参,但是在调用的时候,并不一定非要传入N个实参(没有参数个条的概念)

**注意:**当两个方法名相同的时候(一个方法名定义了两次的时候,应该怎么处理)

function abc(){
    console.log("这是第一个方法");
}
function abc(a){
    console.log("这是第二个方法");
}
abc();

上面的代码以第二个方法为主(后出来的为主)

方法的返回值

在我们的方法里面,有一个关键字return,当我们在代码在方法内部一旦遇到这个关键字的时候,这个方法就会立即中止,然后跳出这个方法

所有的方法,如果没有明确的添加return ,那么,则会隐式的在代码的最后加上一个return,代表这个方法的结束

return在默认的情况之下,它结束这个方法的时候,返回到外边的值是undefined,我们可以在return的后面添加我们要返回到外边的值

案例
/*
* 现在要求写一个方法,这个方法是把所有的参数进行相加(只考虑数字)
* 然后把得出来的和交给外边,由外边处理
 */
function plus(){
    var sum=0;
    for(var i=0;i<arguments.length;i++){
        sum+=arguments[i];
    }
    return sum;  //结束方法,把值交给外边
}
var t =plus(1,3,5,7,9,2,5,6,7);
//这个时候的变量t就是plus方法调用以后的结果,这个结果通过return 返回到了外边
//      document.writeln(t);
//      console.log(t);
alert(t);   

上面的代码当中,我们的plus这个方法,仅仅是把传进去的参数求和,求和完成以后,再把得到的值给外边,至于外边拿到这个值以后要干什么,plus管不到

实参与形参的影响

在方法调用过程当中,值是由实参向形参发生传递,如果传递进去的值发生改变以后,会不会影响外边的值呢?

var a=10;
var b=20;
function abc(x,y){
    x=x-1;
    y=y-2;
    console.log(x);
    console.log(y);
}
abc(a,b);
//参数的值是由实参传向形参
//a-->x  b--->y
document.writeln(a);
document.writeln(b);

上面的代码执行完毕以后,在控制台打印了x与y的值 分别是9,18,而在页面打印了a与b的值,分别为10,20,这说明这两个值没有受到影响。这就说明,实参不会因为形参在方向内部发生了改变页改变

总结:形参在方法内部的改变不影响外边的实参(这个实参并且是基本类型

TODO:对向是引用传递,在这里,会受到影响

方法的优点

  1. 方法一旦封装完成以后,可以任意多次的调用,并用可以单独的成一个JS文件,通过这个JS文件,可以让它在不同的页面去调用(提高开发效率
  2. 高类聚,低耦合

函数的递归

概念:当一个方法在内部又去调用了自己,这一种情况,我们叫方法的递归

下面请看一个例子

案例

写一个算法,计算从1到100之间的求和(不能使用任何循环语句去完成)

var sum=0;   //保存计算结果
var i=1;     //初始条件
function add(){
    sum=sum+i;  //要执行的代码
    i++;        //自变量
    //还差一个循环的结束条件
    if(i<=100){
        add();                          
    }
}
 
add();
document.writeln(sum);

说明:在上面的代码当中,我们在定义add()的方法的时候,又在这个方法的内部调了自身,这种情况, 我们就叫递归

注意:在使用递归的时候,一定要注意它的调用条件(结束条件),如果处理不好,就会形成死循环

函数表达式

在JS里面定义函数(方法)的时候,大家都知道有两种方法,第一种是直接调用function关键字去定义,第二种则是通过变量赋值的方法,把一个function赋值给某一个变量

var a=function(){//......}

像上面这种情况的定义函数 ,我们就叫函数表达式

在我们使用函数表达式的时候,我们一旦把函数定义出来,就可以直接调用,具体如下

var b=function(x,y){
    document.writeln(x+y);
}(11,45)

在上面的代码当中,我们定义完函数b以后,这个时候,我们直接在这个function的结尾添加了一对(),这个时候,当这个函数定义完成以后,就会直接被调用

后期,我们会根据这一个函数表达式,来演变出一种写法:闭包

函数调用以及函数引用

函数调用

function a(){
    document.writeln("我是方法a");
}
 
function b(){
    a();
    document.writeln("我是方法b");
}
//      a();
//      b();
//现在,我们都知道,我们可以直接去调用a,也可以直接去调用b
//要求:方法a不能够被别人调用,只能够通过方法b去调用方法a
b();

针对上面的代码,我们方法a不能被其它人调用(不能被外部直接调用,只能对它方法b去调用,这个时候,应该怎么办呢)

第一种方案,通过作用域来控制

我们都知道,在JS当,只有方法function才有作用域,这个时候,我们可以把方法a定义在方法b里面,如下所示

function b(){
    function a(){
        var str="hello world";
        document.writeln("这是方法a");
    }
    a();
}
b();

因为方法a定义在了方法b时面,这个时候a的调用范围只能在b的作用域下面去调用,所以只能有b去调用a,这样就完成了我们的要求

第二种方案,通过控制调用者来完成

function a(){
    //能否在我执行这一个方法的时候,判断一下,到底是谁调用了我呢?
    //a.caller指的就是函数调用者:谁调用了我,这个地方的a.caller就是谁
    //如果是全局调用它就是null
    if(a.caller==b){
        console.log(a.caller);
        document.writeln("我是方法a");              
    }
}
 
function b(){
    a();
    document.writeln("我是方法b");
}
 
function c(){
    a();
    document.writeln("我是方法c");
}

说明:在上面的代码当中,我们已经在a的方法里面,做了一个if判断,使用了一个a.caller==b这样条件,其中a.caller指的是谁调用了a的方法

通过方法的caller这个属性,我们可以严格控制方法的调用者,也可以得到是谁调用了我

函数引用

在一个函数的内部,我们有一个属性,它会指向当前函数自身的引用,这个属性就是arguments.callee,这个属性通常在使用递归的时候,我们会使用它

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值