目 录CONTENT

文章目录

函数(二)

Administrator
2020-07-24 / 0 评论 / 2 点赞 / 14477 阅读 / 10836 字 / 正在检测是否收录...

函数(二)

函数也叫方法,在面向对象的语言里面函数就叫方法

函数的定义

第一种:function 关键字的定义

function 函数名(...参数?){
    //函数代码体
}

另一种方式:函数表达式的定义

var 函数名 =  function (...参数?){
    //函数代码体
}

函数的参数

函数里面的参数分为两种类型

  • 形参:定义方法的时候的那个参数名,叫形式参数
  • 实参:调用方法的时候的那个参数,它是一个具体的值

之前讲函数的基础的时候,我们提过了一点,形参与实参之间没有必要形成一一对应的关系,所以下面的代码它是对的

function add(a,b){
    var sum = a+b;
    return sum;
}
var x = add(1,2);  		//3
var y = add(1,2,4);		//3  实参的个数大于形参
var z = add(1);			//NaN 参数b没有赋值,就是默认的undefined   实参小于形参

ECMAScript 函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不会有什么怨言。之所以会这样,原因是 ECMAScript 中的参数在内部是用一个数组来表示的。

arguments实参数组

根据上面的理解,函数的内部会将所有的实参形成一个数组,无论你传递多个数都可以。你如果不传递,这个数组就是空数组,你如果传递了,我就将你的实参放在数组里面。而个数组就是arguments

function method1(a,b){
    console.log(a);
    console.log(b);
    //arguments就是实参数组
    console.log(arguments[2]);		//arguments[2]就是拿到第3个实参,也就是c
}

method1("a","b","c");

arguments解析

我们刚刚已经看到了怎么去使用arguments,但是它具体是什么我们还要仔细的学习

function method1(a,b){
    console.log(arguments);
    console.log(Array.isArray(arguments));
}

method1("a","b","c");

当我们在方法的内部去打印这个Array.isArray(arguments)的时候,我们发现得到的结果是false,这就说明arguments它不是一个数组。这是什么呢?我们现在将arguments与数组Array来做一个对比

arguments Array
image-20200722163956747 image-20200722164006211

我们将两个东西进行了对比以后我们发现

  • 数组Array会有数组的基本操作方法,而arguments则没有【不同点】
  • 它们都有索引,这们也有属性length。而这些索引与length都是数组才有特征【相同点】

总结:在JavaScript里面,如果一个对象具备数组的特征(索引与长度),但是不具备数组的方法,这种对象人们就叫类数组

同时arguments只能函数内部使用,出了函数就不能使用了

?小技巧根据上在的arguments的特性,我们可以得出下面的一个应用点

function add() {
    //函数的内部,所有的实参最终都会放在arguments
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}

//实参与形参没有必要形成一一对应的关系
add(1, 2, 3);
add(1, 2, 3, 4);
add(1, 2);
add(1, 2, 3, 4, 5);

函数的调用

之前讲到函数的时候已经知道了,函数在调用的时候是通过函数名()来调用,这个时候也请看好,它还有其它的调用方式。这几种调用方式都属于特别的调用方法

var userName = "小夫";
function abc(){
    var userName = "biaogege";
    console.log("*****************");
    console.log("hello world");
    console.log("*****************");
}
abc();

上面的函数定义与函数调用都是最基本的调用方式

立即执行函数

当一个函数定义好了以后立即执行,我们就可以把它看成是立即执行函数

var userName = "小夫";
!function abc() {
    var userName = "biaogege";
    console.log("*****************");
    console.log("hello world "+userName);
    console.log("*****************");
}();

前面的!可以换成+号,相当于这个函数abc定义好了以后立即执行了

上面的立即执行函数有一个非常大缺点,它不能返回内部的值到外边

函数表达式执行

var abc = function () {
    var userName = "biaogege";
    console.log("*****************");
    console.log("hello world " + userName);
    console.log("*****************");
}
//这个时候的abc就是方法名
abc();

上面的代码是一个函数表达式,我们可以通过方法名abc加上括号去调用这个方法,这个时候的abc还只是一个方法名。现在请看下面的代码

var abc = function () {
    var userName = "biaogege";
    console.log("*****************");
    console.log("hello world " + userName);
    console.log("*****************");

    return 123;
}();

这个时候函数会立即执行,同时abc已经变成了123,因为这个时候的abc接收了后面立即执行函数的返回值

当我们在函数表达式的后面添加了一个()立即去执行这个函数以后,这段代码就发生了本质的变化

  1. abc由函数名变成了函数的返回值
  2. 函数由原来的普通函数变成了匿名函数

闭包调用

function a(){
    var userName = "biaogege";
    console.log("hello world");
}
a();

上在的代码中,a代表的是函数名,我们只需要将这个函数名加上括号就可以执行了,所以上面的代码其实可以演变成下面的代码

(function (){
    var userName = "biaogege";
    console.log("hello world");
})();

这个时候我们就可以看到上面的代码已经立即执行了,这各写法,我们叫闭包函数。闭包函数也可以接收参数

 (function (a, b) {
     console.log(a + b);
 })(11, 23);

闭包函数还可以有返回值,并且可以接收这个返回值

 var x = (function (a, b) {
     var c = a + b;
     return c;
 })(11, 23);

这个x就是接收了内部返回的值c

?总结:上面的三种函数都是将函数定义好了以后,直接调用,它们的用法最多的就是隔绝内外变量,让代码立即执行

函数的调用者与函数的引用

所谓的函数的调用者指的是这个函数由谁在调用。如张三定义了一个函数abc与另一个函数def,如果abc的方法内部调用了def,则我们就认为def的调用者是abc

函数的调用者caller

function a() {
    console.log("hello");
    console.log(a.caller);      //a.caller代表的就是谁在调用a
}

function b() {
    console.log("world");
    console.log(b.caller);      //b.caller代表的就是谁在调用b
}
a();
b();

caller指的就是当前函数的调用者,如果我们直接在全局的环境下面去调用函数,则caller的结果是null

function a() {
    console.log("hello");
    //console.log(a.caller);      //a.caller代表的就是谁在调用a
    b();
}

function b() {
    console.log("world");
    console.log(b.caller);      //b.caller代表的就是谁在调用b
}

function c(){
    console.log("你好");
    b();
}

我们分别在a函数里面调用了b函数以及在c函数里面调用了b函数,这个时候b.caller就会分别指向a与c

function a() {
     console.log("hello");
     //console.log(a.caller);      //a.caller代表的就是谁在调用a
     b();
 }
function b() {
    //console.log(b.caller);      //b.caller代表的就是谁在调用b
    //假设这个方法只能被a调用
    if (b.caller == a) {
        console.log("world");
    } else if (b.caller == c) {
        console.log("世界");
    }

}
function c() {
    console.log("你好");
    b();
}

函数的引用

“引用”是我们第一次接触到这个词,在JavaScript里面,引用可以看成是"指针"

 function a() {
     console.log("hello");
     console.log(arguments.callee === a);
 }

在上面调用a这个函数的时候,我们可以看到arguments.callee===a这个结果是true, 这就说明它们两个是一个东西。这个时候arguments.callee就称之为函数a的引用(arguments.callee就是一个指针,它指向了当前函数自己)

var count = 0;
!function() {
    count++;
    console.log(count);
    if(count<10){
        arguments.callee();
    }
}();

上面的代码就是通过arguments.callee实现了匿名函数的递归

匿名函数

匿名函数其实就是没有名子的函数,本身非常简单,但是它可以根其它的东西进行结合,我们之前所学习的闭包函数,立即执行函数以及函数表达式都可以变成匿名函数

回调函数

回调函数是把函数当成参数,传递到另一个函数里面去,它的适用场景主要有两种

  1. 当一个函数的返回值无法返回的时候
  2. 当某些功能需要分段进行的时候(熟称流水线操作)

请看下面代码

function abc(x, y, z) {
    var a = x + y + z;
    var b = x - y - z;

    //请将a,b两个值返回到外边去
    return [a, b];
}
//如果要将上在的a,b同时返回出去,就目前阶段而言,我们可以使用数组封装在一起,然后直接返回这个数组

var result = abc(22, 10, 3);
console.log("三数之和是"+result[0]);
console.log("三数之差是"+result[1]);
//这个时候的result就是数组,问题的关键点就在于,能不能不使用数组

我们现在就看到,如果要把上面的两个值a,b返回出来,必须封装成一个数组,这知做是可以,但很麻烦

现在我们通过回调函数的形式去执行

image-20200723110427513

上面的案例就是回调函数的案例,我们现在再看下面的代码

 //这个方法只负责买
function buy(callBack) {
    var food = "热干面";
    var drink = "百事可乐";

    food = "变质了的热干面";
    drink = "摇了了百事可乐";

    callBack(food, drink);
}

//小夫只负责吃
function xiaofu(_food, _drink) {
    console.log("小夫在吃" + _food);
    console.log("小夫在喝" + _drink);
}

//标哥也只负责吃
function biaogege(_food, _drink) {
    console.log("标哥在吃" + _food);
    console.log("标哥在喝" + _drink);
}

// buy(xiaofu);

buy(biaogege);

我们可以将上面的回调函数变成下面的代码,与匿名函数结合

//这个方法只负责买
function buy(callBack) {
    var food = "热干面";
    var drink = "百事可乐";

   if (typeof callBack == "function") {
       callBack(food, drink);
   }
}

buy(function (_food, _drink) {
    console.log("小夫在吃" + _food);
    console.log("小夫在喝" + _drink);
});


buy(function (_food, _drink) {
    console.log("标哥不爱吃" + _food);
    console.log("标哥爱喝" + _drink);
});
2

评论区