JavaScript中的函数

发布于:2024-10-15 ⋅ 阅读:(93) ⋅ 点赞:(0)

一、函数

1.概念

在JS中,可能会定义非常多的相同代码或者是功能相似的代码,这些代码可能需要大量重复使用。虽然for循环语句也能实现这一些简单的重复操作,但是比较具有局限性,此时我们就可以使用js中的函数。

函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用

2.使用

2.1 声明函数

语法:

function 函数名(){
    
}
  • function:是声明函数的关键字,必须小写
  • 由于函数一般是为了实现某个功能才定义,所以通常我们将函数名命名为动词,如:getSum

2.2 调用函数

语法:

//调用函数
函数名();  //通过调用函数名来执行函数体中的代码
  • 调用的时候千万不要忘记后面有一对小括号
  • **口诀:**函数不调用,自己不会执行

注意:声明函数本身并不会执行代码,只有调用函数的时候才会执行函数体中的代码。

快速体验

//需求:传入两个数字,计算两个数字的和  (求第一个数字到第二个数之间所有数的和)
//1.求1~100累加和
var sum = 0;
for(var i = 1; i <= 100; i++){
    sum += i;
}
console.log(sum)
//2.求1~10的和
var sum = 0;
for(var i = 1; i <= 10; i++){
    sum += i;
}
console.log(sum)

//函数
function getSum(num1,num2){
    var sum = 0;
    for(var i = num1; i <= num2; i++){
        sum += i;
    }
    console.log(sum);
}
//调用函数
getSum(1,10);
getSum(1,100);
getSum(1,20);

2.3 函数基本使用

        //函数的使用分为两步:声明函数  和  调用函数
        //注意:1)function是声明函数的关键字,全部小写
        //     2)函数是做某件事情,函数名一般是动词
        //     3)函数不调用自己不会执行的
        /*
            1.声明函数:
            function 函数名(){
                //函数体
            }
         */
        function sayHi(){
            console.log('hi~~~');
        }
        /*
            2.调用函数:
            函数名();
        */
       sayHi();

3.函数的封装

  • 函数的封装就是把一个或多个功能通过函数的方式放在函数里面,对外只提供一个简单的函数接口去调用。
  • 简单的理解:封装类似于将电脑配件组合组装到机箱中。

需求:利用函数计算1~100之间累加的和

//1.声明函数
function getSum(){
    var sum  = 0;
    for(var i = 1; i <= 100; i++){
        sum += i;
    }
    console.log(sum);
}

//调用函数
getSum();
getSum();

4.函数的参数

4.1 函数中参数的语法

  • 形参(形式参数):函数定时设置接口调用时传入
  • 实参(实际参数):函数调用的时候传入小括号内的真实数据
参数 说明
形参 形式上的参数,函数定义的时候传递的参数,此时我们并不知道是什么
实参 实际上的参数,函数调用的时候传入的参数,实参时传递给形参的

形参的作用:在函数内部某些值不能固定,我们就可以通过参数在调用函数时传递不同的值进去。

4.2 函数参数的运用

4.2.1 声明语法:
//带参数的函数声明
function 函数名(形参1,形参2,形参3,....){  //可以定义任意多的参数,中间用逗号分隔
    //函数体
}
4.3.2调用
//带参数函数的调用
函数名(实参1,实参2,实参3,...)
  • 调用的时候实参值时传递给形参的
  • 形参简单理解为:不用声明的变量
  • 实参和形参多个参数之间用逗号分隔
4.3.3 一个参数
        /*
        function 函数名(形参1,形参2,形参3,....){  //可以定义任意多的参数,中间用逗号分隔
            //函数体
        }
        */
       function cook(foodName){
            console.log('我正在做' + foodName);
       }
       /*
       //带参数函数的调用
        函数名(实参1,实参2,实参3,...)
       */
      cook('酸辣土豆丝');
      cook('麻婆豆腐');
4.3.4 两个参数
//1.利用函数求任意两个数字的和
function getSum(num1, num2){
    console.log(num1 + num2);
}
getSum(1,3);
getSum(3,8);
//2.利用函数求任意两个数之间的和
function getSums(start,end){
    var sum = 0;
    for(var i = start; i <= end; i++){
        sum += i;
    }
    console.log(sum);
}
getSums(1,100);
getSums(1,10);

//注意点:1)多个参数之间用逗号分隔  2)形参可以看作是不用声明的变量
4.3.5 函数参数匹配问题
//1.利用函数求任意两个数字的和
function getSum(num1, num2){
    console.log(num1 + num2);
}
getSum(1,3);
//传入3个参数。实参的个数多于形参的个数,会取到实际的形参个数
getSum(1,2,3); //实际会取到1和2

//传入1个参数,多余的形参会被定义为undefined,最终的结果就会是NaN
getSum(1); //NaN

5.函数的返回值

5.1 return

返回值:函数调用整体代表的数据;函数执行完成后可以通过return 语句将制定的数据返回。

5.2 语法

//声明函数 
function 函数名(形参){
    ...
    return 需要返回的值;
}
//调用函数
var o = 函数名(); //此时调用函数就可以得到函数体内return后面的值

5.3 注意事项

  • 在使用return语句的时候,函数会停止执行,并返回指定的值
  • 如果函数没有reutrn,返回值就是undefined

5.4 案例

案例一
        /*
            1.我们函数只是实现了某种功能,最终结果我们之前是通过console.log()打印在控制台,
            实际的开发中我们都是通过return实现的。
            2.只要函数遇到return就把后面的结果返回给函数的调用者,函数名() = return后面的结果
        */
function getResult(){
    return 666;
}

var result = getResult(); //调用了
console.log(result)

//求任意两个数字的和
function getSum(num1,num2){
    return num1 + num2;
}
var sum = getSum(1,2);
console.log(sum);
案例二

需求:传入两个数字,返回较大的

        //需求,传入两个数字,返回较大的
function getMax(num1,num2){
    /* if(num1 > num2){
            return num1;
        } else {
         	return num2;
        } */
    return num1 > num2?num1:num2;
}

var max1 = getMax(1,5);
console.log(max1);

var max2 = getMax(11,5);
console.log(max2);
案例三

需求:求一个数组中 var arr = [5,2,99,101,67,77,88]中的最大值,要求使用函数,形参传入的是一个数组

function getMax(arr){ … return …} var arr = [5,2,99,101,67,77,88] ; var max = getMax(arr);

//求数组中最大值
function getMax(arr){
    var max = arr[0];//我先认为最大值是数组中的第一个元素
    //遍历数组
    for(var i = 0; i < arr.length; i++){
        if(max < arr[i]){ //如果我们认为的最大值小于了数组中的某个元素
            max = arr[i];//max就得重新赋值,赋值为比原来大的数
        }
    }
    //返回最大值
    return max;
}

var arr = [5,2,99,101,67,200,77,88];
var max = getMax(arr); //调用函数
console.log('最大值是:' + max);

6.arguments

当不确定又多少个参数传递的时候,可以使用arguments来获取,JavaScript中,arguments实际上它是当前函数的一个内置对象。所有函数都内置了一个arguements对象,arguments对象中存储了传递的所有的实参,arguments展示形式是一个伪数组,因此可以进行遍历。

伪数组具有以下特点:

  • 具有length属性
  • 按索引方式存储数据
  • 不具有数据中的push、prop等方法

**注意:**在函数内部使用该对象,用此对象获取函数调用时传递实参

//所有的函数内部JavaScript都给我们内置了arguments
//写一个函数,传入数值后,求数值中的最大值
function getMax(){
    var max = arguments[0];//默认最大值是传入实参的第一个数字
    //遍历出传入的实参
    for(var i = 0; i < arguments.length; i++){
        if(max < arguments[i]){ //如果出现我们认为的最大值小于里面的值
            max = arguments[i];
        }
    }
    //返回最大值
    return max;
}

var max1 = getMax(1,2);
console.log(max1);
//------------------------------------
var max2 = getMax(1,2,3);
console.log(max2);

7.函数声明的两种方式

第一种方式:

命名函数:利用函数关键字function自定义函数式

//声明定义方式
function fn(){
    //....
}
//调用
fn();
  • 因为函数是有名字的,所以也被称之为命名函数
  • 调用函数的代码也可以放在声明函数的前面,也可以放在声明函数的后面

第二种方式:

匿名函数:利用函数表达式的写法如下:

//定义函数
var fn = function(){
    //...
}
//调用方式,函数调用必须写到函数体下面
fn();
  • 应为函数没有名字,所以也被称之为匿名函数
  • 这个fn里面存储的是一个函数
  • 函数白哦大师原理根变量声明的方式一样的
  • 函数调用的代码必须写到函数体后面

翻转数组案例

        /*
        var arr1 = [1,9,3,4,5];

        console.log(reverse(arr1));

        //利用函数,实现任意数组翻转
        function reverse(arr){
            var newArr = []; //翻转之后的新的数组
            //遍历原来的数组
            for(var i = arr.length - 1; i >= 0;i--){
                newArr[newArr.length] = arr[i];// 翻转
            }
            return newArr;
        }
        */


var reverse = function(arr){
    var newArr = [];//新的数组用于存放反转后的数组中的数据
    //遍历原来数组
    for(var i = arr.length - 1; i >= 0; i--){
        newArr[newArr.length] = arr[i]; //反转
    }
    return newArr;//返回翻转后的
}
var arr1 = [1,2,3,4,5];
console.log(reverse(arr1));

8.冒泡排序法

var arr = [1,4,2,9]

function sort(arr){
    //外层:比较的轮数
    for(var i = 0; i < arr.length - 1; i++){
        //内层:每轮比较的次数
        for(var j = 0; j < arr.length - i - 1; j++){
            //比较大小
            if(arr[j] > arr[j + 1]){
                var temp = arr[j];//定义一个临时的变量,该变量暂时存储最大值
                arr[j] = arr[j + 1] //前面一个位置放小的值
                arr[j + 1] = temp; //后面这个位置就放大的
            }
        }
    }
    //返回重新排序的数组
    return arr;
}
var arr = [1,4,2,9,20,8,7,16]
console.log(sort(arr))

9.函数是可以相互调用的

function f1(){
    console.log('这是f1函数');
}
function f2(){
    console.log('这是f2函数');
}
//函数之间是可以相互调用的
function f3(){
    f1(); //调用了f1函数
    console.log('这是f3函数');
    f2(); //调用了f2函数
}

f3();

函数可以自己调用自己,但是必须要有结束条件

//我们要避免这种写法
// function f1(){
//     console.log('测试');
//     f1();
// }
// f1();



//递归
//1   1   2    3    5    8    13    21    34
/*
            month
            1       getSum(1) = 1
            2       getSum(2) = 1
            3       getSum(3) = getSum(2) + getSum(1) = 1 + 1 = 2
            4       getSum(4) = getSum(3) + getSum(2) = 2 + 1 = 3
            5       getSum(5) = getSum(4) + getSum(3) = 3 + 2 = 5
            ...
*/
function getSum(month){
    if(month == 1){
        return 1;
    }
    if(month == 2){
        return 1;
    }
    return getSum(month - 1) + getSum(month - 2)
}

console.log(getSum(9));

二、作用域

1.概念

通常来说,一段程序代码中所用到的名字(变量名)并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。,作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性、减少了名字出现冲突可能。

  • 全局作用域
    • 作用域所有代码指定的环境(整个script标签内部)或者一个独立的js文件
  • 局部作用域 (函数作用域)
    • 作用域函数内的代码环境,就是局部作用域,因为跟函数有关系,所以我们称之为函数作用域
for(var i = 1; i <= 10; i++){

}
console.log(i);

//局部作用域 (函数作用域),在函数内部就是局部作用域,这个代码的名字旨在函数内部起效果和作用
function f1(){
    //局部作用域
    var num = 10;
    num++;
    return num;
}
f1();
console.log(num); //不能访问局部作用域

2.执行角度看

从执行效率角度来看局部和全局变量

  • 全局变量,只有浏览器关闭的时候才会销毁,比较占用内层
  • 局部变量,当我们程序执行完毕后就会销毁,比较节约内存资源
var num = 10;  //全局作用域
console.log(num);

function f1(){
    console.log(num);  //可以
}
f1();

function f2(){
    var num2 = 10;  //局部作用域,只能在函数内部使用
    num2++;
}

3.JS中没有块作用域

  • 块作用域由 { } 包括
  • 在其它编程语言中(如:java和python等),在if语句、循环语句中创建变量,仅仅只能在if语句、本循环中使用

java 由块级作用域:

if(true){
   int num = 123;
}

System.out.print(num); //报错的

以上java代码会报错,因为代码中{ } 即是一块作用域,其中声明的变量num,在“{ }“之外不能使用

js中没有块级作用域(在ES6之前)

if(true){
   int num = 123;
}

console.log(num); //123
if(true){
    num = 10;
}  

{
    console.log(num);
    console.log(num);
    console.log(num);
    console.log(num);
    console.log(num);
}
{
    console.log('...')
}


//对于if 或者是循环语句,后面的大括号(块作用域)是可以不写的,如果不写默认后面的第一行代码输入该块作用域
if(num < 10)
    console.log('num是10或以上');
console.log('2222');

for(var i = 1; i <= 10; i++);
console.log(i)

4.变量的作用域

4.1 概念

在JavaScript中,根据作用域的不同,变量可以分为两种

  • 全局变量
    • 在全局作用域下声明的变量都叫做全局变量(在函数外部定义的变量)
    • 全局变量在代码的任何地方都可以使用
    • 在全局作用域下var声明的变量就是全局变量
    • 特殊情况下,在函数内不使用var声明的变量也是全局变量(不建议使用
  • 局部变量
    • 在局部作用域下声明的变量都是局部变量(函数内部定义的变量)
    • 局部变量只能在该函数内部使用
    • 在函数内部var声明的变量是局部变量
    • 函数额形参实际上就是局部变量

4.2 区别

  • 全局变量:
    • 在任何一个地方都可以使用,只有在浏览器关闭的时候才会被销毁,因此比较占用内存
  • 局部变量:
    • 在函数内部使用,当执行函数时,函数内部代码块被执行的时候,会被初始化,当代码结束的时候就会被销毁。

5.作用域链

        // function f1(){
        //     var num = 123;
        //     function f2(){
        //         console.log(num); 
        //     }
        //     f2();
        // }
        // var num = 456;

        // f1(); //123


var a = 1;
function fn1(){
    var a = 2;
    var b = '22'
    fn2();
    function fn2(){
        var a = 3;
        fn3();
        function fn3(){
            var a = 4;
            console.log(a); //4
            console.log(b); //22
        }
    }
}

fn1();

在这里插入图片描述

// 案例1:结果是几?
function f1(){
    var num = 123;
    function f2(){
        var num = 0;
        console.log(num);
    }
    f2();
}
var num = 456;
f1(); //0

//案例2:结果是几?
var a = 1;
function fn1(){
    var a = 2;
    var b = '22';
    fn2();
    function fn2(){
        var a = 3;
        fn3();
        function fn3(){
            var a = 4;
            console.log(a);     //4
            console.log(b);     //22
        }
    }
}
fn1();

6.预解析

6.1 概念

JavaScript代码由浏览器中的javaScript解析器来执行的。javaScript解析器在运行javaScript代码的时候会分为两步来执行:

  • 预解析
    • 在当前的作用域下,js代码执行之前,浏览器会默认把带有var 和function声明的变量在内存中进行提前声明或者是定义
  • 代码执行
    • 从上到下执行js语句

**注意:**预解析会把变量和函数的声明在代码执行之前执行完成。

6.2 变量预解析

预解析也叫:变量、函数提升。变量的声明会被提升到当前作用域的最上面

console.log(num);  //undefined
var num = 10;

变量提升只提升声明,不提升赋值。

6.3 函数预解析

函数预解,函数的声明会被提升到当前作用域的最上面,但是不会调用函数

fn();
function fn(){
    console.log('aaaa');
}

结果会执行打印。

注意:函数声明代表函数的整体,所以函数提升后,函数名代表了整个函数,但是函数没有被调用

函数表达式声明函数问题

fn();
var fn = function(){
    console.log('aa');
}

结果:提示报错 —— ”fn is not a function“

解析:该段代码执行之前,会做变量声明提升(var fn),fn在提升之后的值是undefined,而fn调用时在fn被赋值为函数之前,此时fn的值是undefined,所以无法被作为函数调用

cript解析器来执行的。javaScript解析器在运行javaScript代码的时候会分为两步来执行:

  • 预解析
    • 在当前的作用域下,js代码执行之前,浏览器会默认把带有var 和function声明的变量在内存中进行提前声明或者是定义
  • 代码执行
    • 从上到下执行js语句

**注意:**预解析会把变量和函数的声明在代码执行之前执行完成。

6.2 变量预解析

预解析也叫:变量、函数提升。变量的声明会被提升到当前作用域的最上面

console.log(num);  //undefined
var num = 10;

变量提升只提升声明,不提升赋值。

6.3 函数预解析

函数预解,函数的声明会被提升到当前作用域的最上面,但是不会调用函数

fn();
function fn(){
    console.log('aaaa');
}

结果会执行打印。

注意:函数声明代表函数的整体,所以函数提升后,函数名代表了整个函数,但是函数没有被调用

函数表达式声明函数问题

fn();
var fn = function(){
    console.log('aa');
}

结果:提示报错 —— ”fn is not a function“

解析:该段代码执行之前,会做变量声明提升(var fn),fn在提升之后的值是undefined,而fn调用时在fn被赋值为函数之前,此时fn的值是undefined,所以无法被作为函数调用


网站公告

今日签到

点亮在社区的每一天
去签到