JS笔记(函数)

函数

函数好处:
1:方便代码的复用。
2:方便代码的维护。

函数的定义的语法:

function 函数名(参数列表){ 函数体 }
解释:
1:函数,也称为方法。
2:function:js 的关键字。用来定义函数的。
3:函数名:是一种标识符,命名规范和变量的规范一致,首字符小写,多个单词构成,从第二个单词的首字符大写。一定要可以通过函数名体现出要实现的功能。
4:(参数列表):小括号必不可少,可以为空。可以称为形参列表,简称参数、或者是形参。
参数代表了,函数体功能中变化的量,有几个变化的量,就要写几个参数,使用逗号分隔。
语法:(参数1,参数2,参数3…)
上面的参数1,参数2,这些参数的命名都要符合变量的命名,本质上就是变量。
5: { 函数体 }:大括号中是函数的主体实现部分。
函数的使用:
通过 函数名(实参列表); 调用函数。

<script>
    //自定义方式,实现打印任意两个数的和。
    function logSum(num1,num2) {
        var sum = num1 + num2;
        console.log (`${num1}+${num2}=${sum}`);
    }

    logSum(1,2);
</script> 

函数的分类:

1:定义的源
    a: js的内置函数  isNaN
    b:自定义函数    开发者自定义函数
2:是否有参数
    a:有参函数
    b:无参函数
3:是否有返回值
    a:有返回值函数    Math.random();
    b: 无返回值,返回值为undefined。

函数的参数说明:

定义函数的参数部分:形参列表。
形参列表:
1:参数的存在可以更好的扩展函数的功能。
2:形参代表了函数这个功能体需要的外部提供的数据列表。
3: 形参的个数没有限制,个数取决于希望外部提供几个数据。就需要
定义几个参数来接收外部提供的数据。
4:形参的名字和变量的命名方式一样,希望接收外部什么样的数据就起什么样的名字。
5:参数之间使用逗号分开。最后一个参数后不需要添加逗号。

调用函数的时候使用的参数:实参列表。
实参列表:
1:实际参与函数内部运算的数据的列表。
2:通常情况下,实参的个数和形参的个数应该是一致的。其他语言中必须一致。
3:在js中实参的个数可以和形参的个数不一致。不建议。
4:实参的个数多于形参的个数,实参多出来的部分直接被忽略。没有形参接收这些数据。
5:实参个数少于形参的个数,那么多余的形参的值为undefined。

<script>
    //自定义方式,实现打印任意两个数的和。
    function logSum(num1,num2) {//num1,num2是形参列表。
        console.log (num1);
        console.log (num2);
        var sum = num1 + num2;
        console.log (`${num1}+${num2}=${sum}`);
    }
    logSum(1,2);//传参的过程
    logSum(1);
</script>

函数的定义:

function 函数名(参数列表){函数体}

参数:形式参数(形参);实际参数:实参

形式参数: 函数中形式上参与运算的数据。 只是一个占位符。
1:函数定义的时候的小括号中的内容:形参列表。
2:形参的作用,用来接收方法的使用者传递的实际的参数。
3:形参的个数没有限制,也不需要添加var 关键字。直接写参数的名字即可。
形参的名字和变量的名字的规范一致。形参就是局部变量。只能在方法内使用。
多个形参之间使用逗号分隔。
4:形参的名字要能体现出要接收的实参的数据的内容。

实际参数:函数中实际参与运算的数据。
1:实参的个数通常要和形参的个数一致。
2:实参的个数如果少于形参的个数。多余的形参的值为 undefined。
3:函数调用的时候,是将实参的值按照顺序依次赋值给形式参数。
4:实参可以是任意的有返回值的js的表达式。
5: 实参之间使用逗号分隔。

函数调用的传参问题

函数调用的时候。
会进行参数的传递:将实参的值依次赋值给形式参数的过程。

<script>
    var num1 = 10;
    var num2 = 20;

    /* var temp = num1;
     num1 = num2;
     num2 = temp;*/
    change (num1, num2);

    console.log (`num1 = ${num1}\tnum2 = ${num2}`);

    function change(val1, val2) {
        console.log (`val1 = ${val1}\tval2 = ${val2}`);
        var temp = val1;
        val1 = val2;
        val2 = temp;
        console.log (`val1 = ${val1}\tval2 = ${val2}`);
    }
</script>

程序中的内存说明

js中的数据占用的内存,主要分为了2部分。
1:栈内存 stack
全局变量、函数内的局部变量。
栈是一种数据结构。
数据结构:具有某种关系的一组数据的集合。类似一个容器,容器中保存了
很多的数据,数据之间存在某种关系。不同的数据结构中的数据的关系是不同的。
不同的关系,导致了访问数据结构中的数据的特点不同。
学习数据结构,要了解数据结构中的数据的关系和特点。
2:堆内存 heap
对象

函数的返回值

函数的分类:
按照返回值:有返回值的函数、无返回值的函数。
1:如果希望函数执行完毕之后,函数自身会带有一个结果,那么该函数就需要有返回值。
2:如果希望函数执行完毕之后,不要一个结果,只是实现了某些功能,那么就不需要有返回值。
没有返回值的函数有一个默认的返回值 undefined。
如何让一个函数执行完毕之后有一个结果?
要通过一个js关键字实现:return;
如果我们希望一个函数执行完毕之后返回一个结果,那么在函数体内,必须使用关键字return 后面
跟你需要返回的结果的表达式。
格式:return 结果;
return 的使用方式:
1:在有返回值的函数内,使用return 返回需要返回的值。 return 值;
2: 在不需要返回值的函数内使用,直接使用 return; 用来结束函数的执行的。
3:return 只能在函数中使用,别管后面是否有值,那么一旦使用了return,那么函数立即结束执行。
一般称为 【函数返回】。

<script>
    //需求,求任意两个数的最大值。 这个需求的函数应该要有返回值,返回的是两个实参中比较大的那个
    function max(num1, num2) {
        var max = num1 > num2 ? num1 : num2;
        return max;
    }

    /**
     * 检查 指定的数是质数还是合数,打印结果
     * @param num 要检查的数
     * 如果不是合法的数据,返回 -1,如果是质数返回0,如果是合数返回1.
     */
    function checkNumber(num) {
        //特殊情况
        var str = typeof num;
        if (str !== "number") {//不是数值类型
            return -1;
        } else if (num <= 1) {
            return -1;
        } else {//大于1 的数。
            //小数的情况
            var temp = ~~num;
            if (temp != num) {//小数
                return -1;
            } else {
                //一般情况
                var flag = false;
                for (var i = 2; i < num; i++) {
                    if (num % i === 0) {//合数
                        flag = true;
                        break;
                    }
                }
                if (flag)
                    return 1;
                else
                    return 0;
            }
        }
    }

    console.log (max (1, 2));

    console.log (checkNumber (null));
    console.log (checkNumber (1));
    console.log (checkNumber (3));
    console.log (checkNumber (4));

    //求任意数的绝对值
    function abs(num) {
        if (num < 0)
            return -num;
        return num;
    }

    function abs(num) {
        return num < 0 ? -num : num;
    }

    console.log (abs (-1));
    console.log (abs (2));

    //
    /**
     * 判断一个数是否是质数
     * @param num 被判断的数
     * 如果num 值质数,返回true,否则false。
     */
    function isPrime(num) {
        //特殊情况
        var str = typeof num;
        if (str !== "number") {//不是数值类型
            return false;
        }
        if (num <= 1) {
            return false;
        }
        //大于1 的数。
        //小数的情况
        var temp = ~~num;
        if (temp != num) {//小数
            return false;
        }
        //一般情况
        var flag = false;
        for (var i = 2; i < num; i++) {
            if (num % i === 0) {//合数
                return false;
            }

        }
        return true;
    }

    console.log (isPrime (null));//false
    console.log (isPrime (0));//false
    console.log (isPrime (2));//true
    console.log (isPrime (11));//true
    console.log (isPrime (12));//false

    //判断某个一数知否是 true
    function isTrue(val) {
        return val === true;
    }

    //实现求四舍五入的函数
    function round(num) {
        //正数情况
        var val = num - ~~(num);
        if (val >= 0.5) {
            return ~~(num + 1);
        }
        return ~~num;
    }

    console.log (round (1.1));//1
    console.log (round (1.5));//2
    console.log (round (1.51));//2
    console.log (round (1.9));//2
</script>

函数的使用

有返回值的函数的使用:
1:直接调用。(很少)
2: 用一个变量接收方法的返回值。(最多的)
3: 作为操作数使用。(不多)
4: 作为函数调用的实参使用。(不多)
5: 作为log函数的实参直接打印。(现阶段比较多)
无返回值的函数的使用:
1:直接调用。

<script>
    function random(min, max) {
        return ~~(Math.random () * (max - min) + min);
    }

    //1
    random (1, 100);
    //2
    var num = random (1, 299);
    //3
    num = 1 + random (1, 20);
    //4
    num = random (random (1, 20), random (30, 80));
    //5
    console.log (random(1,20));

    //1: 无参直接调用。
    function log(msg) {
        console.log (msg);
    }
    log(true);
</script>

js中不存在函数重载

函数的重载:overload。
1:概念:方法名字相同,形参列表不同的函数,称为函数的重载。
在js中不存在重载这个问题。如果多个方法的名字相同,那么后定义的会覆盖前面的

<script>
    //会被覆盖掉
    function add(num1, num2) {
        return num1 + num2;
    }
    //这个会覆盖掉上面的
    function add(num1, num2, num3) {
        return num1 + num2 + num3;
    }
    console.log (add(1,2));//NaN
    console.log (add(1,2,3));//6
</script>

函数的定义的几种方式

js中关于函数定义的几种方式:
1:方法声明方式 使用最多的。
function 方法名(参数列表){方法体}

2:方法的直接赋值方式   使用一般多。
    var 变量名 = function(参数列表){方法体}
    匿名方法定义的形式。

3: 使用构造函数。  基本不用
    var 变量名 = new Function("参数列表","方法体");
    所有的function 实例。函数对象都是通过  构造函数 Function 创建出来的。

三种定义方式的区别:
1:第一种方式,可以在定义之前和之后调用该方法。而且方法是有名字的。
2: 第二种方式,是匿名的函数,是将一个匿名函数赋值给了一个变量。还有该方式,必须先
    定义后使用。
3:第三种方式,很繁琐,必须先定义后使用。
<script>
    //
    test();
    //函数定义的直接声明方式
    function test() {
        console.log ("helloworld!");
    }
    test();

    // sum 是一个对象变量,通过变量名来访问。
    sum(1,2);
    var sum = function (num1,num2) {
        return num1 + num2;
    }
    console.log (sum(1,2));

    var value = 10;

    // 使用构造函数
    var log = new Function("","{alert('helloworld')}");
    log();
</script>

局部变量和全局变量

变量的作用域:
变量可以被访问的范围。
变量的分类
1:全局变量
在方法外定义的,script标签内定义的变量。就是全局变量。
2: 局部变量
在方法内定义的变量就是局部变量。
局部变量和全局变量的不同
1:作用域不同。
a:全局变量的作用域是整个script代码块。包括里面的方法体中.
b:局部变量的作用域就是其所在的方法范围内。
2: 生命周期不同。
a:局部变量的生命周期从方法开始调用开始,从方法结束调用结束。
依赖于所在的方法何时被调用。
b:全局变量的生命周期从script代码块开始加载就开始了。关闭浏览器的时候结束。
3:如果全局变量和局部变量的作用域存在冲突:被访问的优先级不同。
a:局部的高于全局的。
b:如果在冲突的作用域中访问全局的变量,可以通过 window.变量 或者是 this.变量 访问
总结:
1:全局的变量会一直占用内存空间。
2:js中可以重复定义变量,可能会出现多次定义一个全局变量。在函数内没有使用var 定义变量污染了全局数据。

<script>
    //全局变量
    var num = 0;
    var val = 10;
    var number = 100;

    function fn() {
        //局部变量 和 全局变量存在命名的冲突。
        var num = 10;
        console.log ("局部:"+num);//10
        //访问全局变量
        console.log (window.num);//0
        console.log (this.num);//0

        var value = 10;
        //访问全局变量
        val = 100;

        number = 100;
    }
    fn();

    var val = 200;

    function a() {d();}
    function c() {}
    function d() { c();}
    function test() {
        a();
    }
</script>

let和var的区别

let 关键字:用来定义变量的。let的后期版本推出的新的关键字。
var 关键字:用来定义变量的。
不同点:
1-1:let 定义的变量具有块级作用域。在代码块定义的变量只能在代码块中使用。出了代码块就不能被访问了。
1-2:var 定义的变量不具有块级作用域。在代码块中定义的变量,就是全局的变量。
2-1:使用var声明的全局变量会作为window的属性存在。可以通过 window. 访问全局变量。
2-2: 使用let 定义的全局变量不会作为window的属性存在。
3-1: var 可以重复定义同名变量,后面会覆盖前面的。
3-2: let 不可以重复定义同名变量。
总结:var 定义变量不够严谨,let定义变量更加的严谨。

<script>
    let value = 10;
    // let value = 10;
    var num = 10;
    var num = 100;
    if (true) {
        //把外面定义的变量污染了。
        var num = 100;
        //不会污染全局的value。
        let value = 20;
    }
    console.log (num);//100
    console.log (value);//10
    function test() {
        console.log ("hello");
    }
    console.log (window.num);//100
    window.test ();//hello
    console.log (window.value);//undefined
</script>

方法的执行符

方法的执行符:()
调用方法,必须使用方法名+()在这里插入图片描述

执行符的作用:定义匿名函数,并直接执行。
<script>

    function test() {
        console.log ("hello");
    }
    //直接打印方法的名字,输出的是方法的完整的定义的形式。
    /*
    ƒ test() {
        console.log ("hello");
    }
    */
    console.log (test);
    //调用方法
    test();

    var fn = function () {
        console.log ("world");
    }
    /*
    * ƒ () {
        console.log ("world");
    }
    * */
    console.log (fn);
    fn();
    //定义匿名函数,并执行该函数,不要有全局方法名字。
    (function () {
        console.log ("world11111");
    })();
    //使用函数作为实参,在方法内执行实参函数。
    function fn1(fn) {
        fn();
    }
    console.log ("------------");
    fn1(test);
    fn1(function () {
        console.log ("我是匿名函数")
    });
</script>

传参示意图

在这里插入图片描述

在这里插入图片描述

函数的执行符

函数的执行符:()
对象引用
立即自执行匿名函数
函数作为实参使用

<script>
    //第二种定义函数的方式
    //log 对象变量、对象引用。指向了堆内存中的一个匿名函数。
    var log = function (msg) {
        console.log (msg);
    }
    function show(){
        console.log ("可是你却并不在意");
    }
    //如何让匿名函数执行。通过对象引用+执行符。来执行匿名函数。
    log ("千万里我追寻着你");
    //调用其他方法的方法  funName 方法的名字,或者是方法的对象引用。
    function invokeFunction(funName) {
        funName();
    }
    invokeFunction(show);
    invokeFunction(log);
    //立即自执行匿名函数.就是希望函数定义之后立即执行。而且我只需要执行一次。
    (function (msg) {
        console.log (msg);
    })("你不像是在我梦里,在梦里你是我的唯一!");
    ~function test() {
        console.log ("helloworld!")
    }();
</script>

函数的属性和方法介绍

函数是一种引用数据类型。
是我们接触到的第一种引用数据类型。
函数是一种特殊的对象,对象就可以具有属性和功能(函数、方法)。

函数的属性:
    name:函数的名字
    length: 代表了函数的形参的个数。是个整数.
函数的方法:
    toString(): 得到函数的字符串表示形式。
<script>
    function show() {
        console.log ("我今生注定要独行,热情以被你耗尽!");
    }
    console.log (typeof show);//function
    var log = function(){
        console.log ("我已经变的不再是我,而你却依然是你!");
    }
    console.log (show.name);//show
    console.log (log.name);//log
    //调用其他方法的方法。
    function invokeFunction(fnName) {
       if(fnName.name = = = "show"){
           console.log ("*************");
       }else if(fnName.name === "log"){
           console.log ("-----------");
       }
    }
    invokeFunction(log);
    invokeFunction(show);
    console.log (invokeFunction.length);//1
    console.log (show.length);
   /* ƒ (){
        console.log ("我已经变的不再是我,而你却依然是你!");
    }*/
    console.log (log);
    /*function(){
        console.log ("我已经变的不再是我,而你却依然是你!");
    }*/
    console.log (log.toString());
</script>

函数的arguments对象

函数的arguments对象
1:arguments 参数的意思。
2:arguments 是一个对象,是函数的一个对象,只能在函数体中使用。
3: arguments 是一个集合。类数组对象。可以像访问数组一样去访问它。通过下标。
下标从0开始。 arguments[下标] 访问。
4:有一个length属性。代表了元素的个数。
5:arguments 还有一个属性是一个对象。callee。是当前函数自身。主要用于递归调用。
6:arguments 对象中的元素是实参的内容。可以通过该对象来访问传入的实参的内容。
7:通常情况下都是使用方法的形参来接收实参的,不建议使用arguments来访问实参。
8:如果传入的实参的个数不确定。可以使用arguments来访问传入的实参。
补充:arugments不太建议使用。因为在严格模式下,arguments无效。
arguments 在一定程度上弥补了js不存在重载的问题。

<script>
    function show(msg) {
        console.log (msg);
        // ["time time again,you ask me", callee: ƒ, Symbol(Symbol.iterator): ƒ]
        console.log (arguments);
        console.log (arguments.callee);
    }
    show ("time time again,you ask me");

    //实现任意个数的累加和的方法。就可以使用arguments来处理。
    function add(num1, num2) {
        return num1 + num2;
    }
    function add(num1, num2, num3) {
        return num1 + num2 + num3;
    }
    function add() {
        //在方法的内部使用arguments来访问所有的实参。
        const LEN = arguments.length;
        if (LEN === 0)
            return NaN;
        //遍历arguments中的所有的内容。累加返回
        var sum = 0;
        for (let i = 0; i < LEN; i++) {
            sum += arguments[i];
        }
        return sum;
    }
    console.log (add());//NaN
    console.log (add(1,2,3,4,5));//15
    console.log (add(1,2,2,1,1,2,3,4,4));//20
</script>

递归

递归:recursion 指的就是函数调用。
概念:函数直接的或者是间接的调用了自身。
使用递归的解决的问题特点:
1:问题可以分解为若干个子问题。
2:子问题的解决的方案和问题本身的解决方案一致。
3:最终一定存在某一个子问题可以直接解决。
4:最终问题的解决要依赖于所有的子问题的解决。
求 n! n的阶乘。
n! == n*(n-1)(n-2)321;
n!= n
(n-1)!
5! = 54321;
5! = 54!;
4! = 4
3!
3! = 32!
2! = 2
1!
1! = 1;

<script>
    function test(n) {
        //直接递归调用
        // test(n-1);
        //间接递归调用。
        test2 ();
    }
    function test2() {
        test (1);
    }
    // Maximum call stack size exceeded
    // test(1);
    //使用递归求n的阶乘
    /**
     * 求n的阶乘。返回n的阶乘的结果。
     * @param n
     */
    function factorial(n) {
        let result = 1;
        if (n === 1)
            return result;
        result = n * factorial (n - 1);
        return result;
    }
    console.log (factorial (5));//120
    console.log (factorial (6));//720
    //斐波那切数列,第一个和第二个数为1,从第三个数开始,是它前两个数之和。
    //求第n个位置上的数的值。
    function fibo(n) {
        if (n === 1 || n === 2)
            return 1;
        return fibo (n - 1) + fibo (n - 2);
    }
// overflow
    for (let i = 1; i < 10; i++) {
        document.write (fibo (i) + ",");
    }
</script>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值