JS深入理解函数

目录

一、函数的声明

1.1、自定义函数

1.2、函数表达式(匿名函数)

二、函数的调用

2.1、自定义函数调用

2.2、函数表达式调用

2.3、自定义函数调用与函数表达式调用区别

三、函数参数

四、返回值

五、函数的内部属性

5.1、arguments

5.2、this

六、函数的方法

6.1、call()

6.2、apply()

6.3、call()和apply()的应用

6.3.1、找出数组中的最大的元素

6.3.2、将伪类数组转换为真正的数组

6.3.3、数组追加

6.3.4、利用 call 和 apply 做继承

6.4、bind()

七、立即执行函数

7.1、定义语法

7.2、立即执行函数应用


一、函数的声明

函数声明有两种方式:自定义函数和函数表达式。

1.1、自定义函数

语法格式:

        function 函数名称(参数列表) {
            函数体
            [return 值]
        }

注意:

(1)function 是声明函数的关键字必须小写;

(2)function 关键字后必须跟函数名,函数名一般使用动词,需要符合命名规则;

(3)函数名后跟一对小括号,小括号后跟一对大括号,大括号内是函数体。

1.2、函数表达式(匿名函数)

语法格式:

        var 函数引用名称 = function(参数列表) {
            函数体
            [return 值]
        }

注意:

(1)函数表达式方式声明函数仍然需要使用 function 关键字;

(2)function关键字后紧跟一对小括号,小括号后跟一对大括号,大括号内是函数体;

(3)由于这种定义的函数没有名字,因此需要把函数赋值给一个变量

二、函数的调用

根据函数的声明方式不同调用函数的方式也略有不同。

2.1、自定义函数调用

使用函数名称来调用

        // 声明函数 
        function myFunction() {

        }
        // 调用函数 
        myFunction();

2.2、函数表达式调用

需要通过函数变量名来调用

        // 声明函数
        var myFunction = function() {

        }
        // 调用函数 
        myFunction();

2.3、自定义函数调用与函数表达式调用区别

    <script>
        fn1();

        function fn1() {
            console.log('fn1');
        }

        fn2();//报错
        var fn2 = function() {
            console.log('fn2');
        };

    </script>

区别:

(1)如果是自定义函数来声明的函数,在声明函数语句的前后都可以调用;如果是函数表达式来声明的函数,只能在声明语句之后调用,不能在声明语句之前调用。

(2)对于自定义函数方式来声明的函数,使用函数名称来调用;而对于函数表达式方式声明的函数,需要通过函数变量名来调用。

三、函数参数

由于函数内部某些值是不固定的,我们需要根据调用时传递的不同值得到不同的结果,这时就需
要使用参数。而参数可分为形参和实参两种。
形参 :在声明函数时用于接收调用时传入的值,形参不需要使用 var 关键字声明。
实参 :在调用函数时传递给函数小括号内的真实数据。
语法格式:
    function 函数名称(形参列表){ 
        函数体     
    }
    函数名称(实参列表);
根据形参和实参数量匹配情况不同,所得的结果也不相同,见下表:

 示例:

    <script>
        function add(a, b) {
            console.log(a, b);
            return a + b;
        }

        var result = add(2, 3); //2 3
        console.log(result); //5

        result = add(4, 6, 9); // 4 6
        console.log(result); //10

        result = add(5); //5 undefined
        console.log(result); //5+undefined=NaN
    </script>

运行结果:

 注意:

(1)形参不需要var声明变量,否则会报错;

(2)函数声明可带参数也可不带参数;

(3)声明函数时括号内是形参,形参的默认值为 undefined;

(4)调用函数时括号内是实参

(5)多个参数之间用英文逗号分隔;

(6)当实参与形参个数不匹配时结果不可预计,因此尽量要匹配

四、返回值

对于某些函数来说,执行完后会返回执行结果给调用函数处。这时就需要在函数体内通过 return
语句来将数据返回。
语法格式:
        function 函数名(形参列表) {
            函数体;
            return 语句
        }

示例:

    <script>
        function sub(a, b) {
            return a - b;
        }
        var result = sub(3, 1);

        console.log(result); //2

        function fn(s) {
            console.log(s);
            return;
        }

        result = fn('hello'); //hello

        result = fn(); // undefined
    </script>

注意:

(1)当函数执行到 return 语句时,会结束函数执行并返回指定的值 ;

(2)如果函数无须返回值,也可以有 return 语句,但 return 后不能跟别的值

(3)如果函数没有 return 语句,返回的值是 undefined。

五、函数的内部属性

5.1、arguments

JavaScript 的函数中 arguments 属性封装了函数的实参。

arguments说明:

(1)arguments是一个伪数组对象,它不是数组类型,可用 instanceof 运算符查看;

(2)当调用函数时,所传递的实参都保存在 arguments 中 ;

(3)可通过 arguments 对象的 length 属性来获取实参个数

(4)arguments[0] 表示第一个实参,arguments[1] 表示第二个实参,以此类推;

(5)arguments 中有一个 callee 属性,它是一个函数对象,指向当前所使用的函数;

(6)只有函数才有arguments 对象,而且每个函数都内置好了这个arguments。

伪数组说明:伪数组并不是真正意义上的数组

(1)伪数组具有数组的lenght属性;

(2)伪数组可以按照索引方式进行存储;

(3)伪数组没有真正数组的一些方法pop()、push()等。

示例:

    <script>
        function add(a, b) {
            // console.log(arguments);//里面存储了所有传递过来的实参
            // console.log(typeof arguments);//object
            // console.log(arguments instanceof Array); // false
            // console.log(arguments instanceof Object);// true
            // console.log(arguments.length);//8
            // console.log(arguments[5]);//7

            // 实现简单加法
            var sum = 0;
            for (var i = 0; i < arguments.length; i++) {
                // console.log(arguments[i]);
                sum = sum + arguments[i];
            }
            console.log(sum);//44

        }

        add(2, 3, 4, 5, 6, 7, 8, 9);
    </script>

5.2、this

this 本身是 JavaScript 中的一个关键字,被称为 this 的事物指的是 拥有 当前代码的对象。在函
数调用中,根据函数的调用方式不同, this 指向的对象也不同。
示例:
    <button>按钮</button>
    <script>
        // this 指向问题 一般情况下this的最终指向的是那个调用它的对象

        // 1、全局作用域或者普通函数中的this指向全局对象window(注意定时器里面的this指向window)
        console.log(this); //window

        function fn() {
            console.log(this); //window
        }

        fn();
        window.setTimeout(function() {
            console.log(this); //window
        }, 1000)

        // 2、方法调用中谁调用this指向谁
        var obj = {
            say: function() {
                console.log(this); //obj
            }
        }
        obj.say();

        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            console.log(this); //btn
        })

        // 3、构造函数中this指向函数的实例
        function Fun() {
            console.log(this); //this指向的是fun实例对象
        }
        var fun = new Fun();
    </script>

注意:

(1)全局作用域或者普通函数中的this指向全局对象window(注意定时器里面的this指向window);

(2)方法调用中谁调用this指向谁;

(3)构造函数中this指向函数的实例。

六、函数的方法

6.1、call()

使用 call() 方法,您可以编写能够在不同对象上使用的方法,没有返回值。
语法格式:
函数名称.call();

示例:

   <script>
        window.color = 'red';
        var obj = {
            color: 'blue'
        }

        function show() {
            console.log(this.color);
        }
        show(); // red

        show.call(this); // red
        show.call(window); // red
        show.call(obj); // blue


        function add(a, b) {
            return a + b;
        }

        //console.log(window)

        var result = add(2, 3);
        console.log(result);
        // 通过 call() 方法来调用函数
        result = add.call(this, 1, 8);
        console.log(result); //9

        result = add.call(window, 2, 5);
        console.log(result); //7

        result = add.call(add, 3, 4);
        console.log(result); //7
    </script>

注意:当使用函数的 call() 方法调用时,方法的第一个参数是函数对象,如果有参数,则从 第二个位置开始依次提供。

6.2、apply()

通过 apply() 方法,您能够编写用于不同对象的方法,没有返回值。
语法如下:
函数名.apply();

示例:

    <script>
        window.color = 'red';
        var obj = {
            color: 'blue'
        }

        function show() {
            console.log(this.color);
        }
        show(); // red
        show.apply(this); // red
        show.apply(window); // red
        show.apply(obj); // blue

        console.log('------------------');

        function add(a, b) {
            return a + b;
        }

        var result = add(2, 3);
        console.log(result);
        result = add.apply(this, [1, 3]);
        console.log(result);
        result = add.apply(window, [4, 5]);
        console.log(result);
        result = add.apply(add, [4, 6]);
        console.log(result);

        console.log('----------------');

        var color = 'green';


    </script>

注意:

(1)apply() 方法在这点的应用和 call() 方法没有区别,都是可以通过第一个参数来改变引用象。

(2)apply() 方法需要将实参封装到一个数组中统一传递。第一个参数是函数对象,第二个参数是数组,里面封装了参数。

    <script>
        function print() {
            'use strict'; // 指定严格模式
            console.log(this);
            console.log(this.color);
        }

        // print.call(null);
        //print.apply(undefined);
    </script>

注意:

(1)在严格模式下,函数的指向始终是指定的值;

(2)在非严格模式下,如果使用call()或者apply()方法,传入null或者undefined会转换成一个全局的window对象。

6.3、call()和apply()的应用

6.3.1、找出数组中的最大的元素

    <script>
        var arr = [5, 20, 8, 51, 13];
        // 找出数组中的最大的元素
        var maxVal = Math.max(arr);
        console.log(maxVal); //NaN
        var maxVal = Math.max(5, 20, 8, 51, 13);
        console.log(maxVal); //51


        maxVal = Math.max.apply(this, arr); //this=Math.max
        console.log(maxVal); //51
        maxVal = Math.max.apply(this, [5, 20, 8, 51, 13]); //this=Math.max
        console.log(maxVal); //51
    </script>

6.3.2、将伪类数组转换为真正的数组

    <script>
        function add() {
            console.log(arguments); //Arguments(3)
            console.log(arguments instanceof Array); //false

            // Array.prototype原型  slice复制
            var arr = Array.prototype.slice.apply(arguments);

            console.log(arr); //Array(3)
            console.log(arr instanceof Array); //ture
        }

        add(1, 2, 3);
    </script>

6.3.3、数组追加

<script>
    var arr = [];
    Array.prototype.push.apply(arr, [1, 2, 3, 4, 5]);
    console.log(arr);

    Array.prototype.push.call(arr, 4, 5, 6);
    console.log(arr);
</script>

6.3.4、利用 call apply 做继承

    <script>
        function Animal(name, age) {
            this.name = name;
            this.age = age;
            this.show = function() {
                console.log(this.name, this.age);
            };
        }

        function Cat(name, age) {
            // 继承
            Animal.call(this, name, age);
        }

        var cat = new Cat('波斯猫', 3);
        cat.show(); //波斯猫, 3

        function Dog(name, age) {
            //Animal.apply(this, [name, age]);//可以
            Animal.apply(this, arguments);
        }

        var dog = new Dog('沙皮狗', 2);
        dog.show();
    </script>

6.4、bind()

bind() 方法是 ES5 新增的方法, 主要的作用是将函数绑定到某个对象中,并且有返回值,这个返
回值是一个函数
示例:
<script>
    function fun(y) {
        console.log(this);
        return this.x + y;
    }
    var obj = {
        x: 2
    }
    //console.log(fun(3));
    var fn = fun.bind(obj);//bind()返回一个新的函数fn

    console.log(fn(4));
</script>
注意: bind 方法的第一个参数也是一个对象。
函数式编程技术(函数柯里化):
<script>
    function getConf(color, size, other) {
        console.log(color, size, other);
    }
    var fn = getConf.bind(null, '#ff0000', '500px');
    fn('scrollTop');
    fn('display')
</script>
说明:可以使用 bind() 方法来进行绑定后产生一个新的函数对象,在这个函数对象中可以指定一些默认的参数项,然后自定义的参数项我们可以通过新的函数对象来接收。这样话就减少了开发者参数的传递。当然我们也可以把自定义中的参数来覆盖默认的参数项,从而实现框架的应用。

七、立即执行函数

函数的使用步骤是先声明再调用,才能去执行这个函数。但是某些情况下,我们需要声明好这个函数后, 这个函数就要立即执行。这时就需要立即执行函数。
IIFE (自执行函数) 中规定,圆括号 () 跟在函数后面,表示调用这个函数。
所谓立即执行函数是指函数定义完后就会立即执行。立即执行函数是一种匿名函数。

7.1、定义语法

    (function(){ 
        函数体; 
    })(); 

    或者

    (function(){ 
    函数体; 
    }());
注意:立即执行函数要定义在一对小括号中,最后这对小括号表示调用函数。
示例:
<script>
    function fn(a) {
        console.log('hello ' + a);
    }
    fn('hi');

    // 立即执行函数
    (function(){
        console.log('world')
    })();
    (function () {
        console.log('hi')
    }())

    var r = (function (a, b) {
        console.log(a, b);
        return a + b;
    })(1, 2);
    console.log(r);

</script>
注意:
(1)在立即执行函数中也是可以传参的,在调用的这对小括号中书写参数即可。
(2) 当编写有多个立即执行函数时,后面的分号不能省。

7.2、立即执行函数应用

.1、 每次调用 add ,都返回加 1 的数字(初始值为 0
    <script>
        // 需求:每次调用 add,都返回加 1 的数字(初始值为 0)
        // 1. 使用之前的方式来实现
        function add() {
            return ++add.count; // 给 add 函数对象指定了一个自定义的属性 count, 用于共享数据
        }
        add.count = 0;
        console.log(add()); //1
        console.log(add()); //2
        console.log(add()); //3

        // 2. 使用立即执行函数来实现
        var rs = (function() {
            var count = 0;
            // 在立即执行函数中声明了一个变量
            return function() {
                return ++count;
            };
        })();
        console.log(rs()); //1
        console.log(rs()); //2
        console.log(rs()); //3
    </script>

2、现有如下程序,看看发生了什么问题,如何解决

<script>
    function fn() {
        var arr = [];
        for (var i = 0; i < 5; i++) {
            arr[i] = function() {
                return i;
            }
        }
        return arr;
    }
    var f = fn();
    console.log(f);
    console.log(f[0]());
    console.log(f[1]());
</script>

使用立即执行函数

  <script>
        function fun() {
            var arr = [];
            for (var i = 0; i < 5; i++) {
                (function(n) {
                    arr[n] = function() {
                        return n;
                    }
                })(i);
            }
            return arr;
        }
        f = fun();
        console.log(f);
        console.log(f[0]());
        console.log(f[1]());
        console.log(f[4]());
    </script>

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值