函数它只定义一次,但可以被多次的执行和调用。JavaScript函数是参数化的,函数的定义会包括形参和实参。形参相当于函数中定义的变量,实参是在运行函数调用时传入的参数。

  一、函数定义

    函数使用function关键字来定义。它可以用在函数定义表达式或者函数声明语句里。    

    1、函数声明语句

    使用function关键字,后跟一组参数及函数体。

    funcname是要声明的函数名称标识符。函数名称是函数声明语句必需的部分。

    圆括号其中可以包含由0个或者是多个用逗号隔开的标识符组成的列表,这些标识符是函数的参数名称,它们就像是函数体中的局部变量一样。

    花括号,包偏一条或者是多条javascript语句。这些语句构成函数体,一旦调用函数,就会执行这些语句。

    变量的重复声明是无用的,但是函数的重复声明会覆盖前面的声明(无论是变量还是函数声明)

    <!-- <script>
        语法:
        function funcname() {
            statement;
        } 
        调用:
        1、funcname(参数);
        2、把函数声明变成函数表达式在后面加上一对小括号
    </script> -->

    2、函数表达式

     以表达式的方式来定义函数,函数的名称是可选的。

     匿名函数是function关键字后面没有标识符的函数。通常而言,以表达式方式定义函数时都是不需要名称的,这样做的好处是让代码更加简洁。函数定义表达式特别适合用来定义那些只会使用一次的函数。

   <!-- <script>
        语法:
        let functionName = function (参数) {
            statement;
        }
     let functionName = function funcName(){
       statement;
     } 调用: 1、变量(参数); 2、直接在后面加上小括号 注意:函数表达式里的function后面如果有名字的话,在调用的时候不能用这个名字去调用 </script>
-->

    3、Function构造函数

    Function构造函数接收任意数据的参数,但最后一个参数始终都被看成是函数体,前面的参数则枚举出了新函数的参数。Function构造函数无法指定函数名称,它创建了一个匿名函数。不推荐使用。会导致两次代码的解析。

    <!-- <script>
        语法:
        var functionName=new function(){
            statement;
        }
    </script> -->

   二、函数参数 

     从函数外向函数内传入数据,在函数内可以接受到这些数据且能够使用它,这些数据就叫做参数。由于js是弱语言类型,所以js函数的参数与大多数其它语言参数有所不同,函数不介意传递进来的参数是什么类型,甚至是可以不传参。

     参数放在小括号内,可以放0个或者是多个,用逗号隔开。

     参数分为形参和实参。形参是形式上的参数,在函数声明的小括号里,形参实际上是由实参来决定的。在非严格模式下,函数中可以出现同名的形参且只能访问最后出现的该名称的形参。但在严格模式下会报错。

     实参是实际上的参数,放在了函数调用的小括号里,实参须与形参一一对应,在调用函数的时候,要把实参传够数量,如果有一个实参没有传,那它就是undefined。常常用逻辑或运算符给省略的参数设置一个合理的默认值

      js中的参数在内部用一个数组表示。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数。在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数.

      arguments对象:代表了所有实参的集合,它是一个类数组。这个集合中的每个数据都有一个自己对应的下标,集合中还有一个length,代表了实参的个数(函数的length属性显示形参的个数)它只能在函数内使用,在函数外是用不了的,如果函数外使用,会报错。arguments对象中的值永远与对应命名参数的值保持同步,arguments对象与命名参数并不是访问相同的内存空间,它们的内存空间独立,但是值相等。

     ECMAScript中所有函数的参数都是按值传递的。换句话说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。

    <script>
        function person(name, age) {
            //形参实际上就是在函数里声明的变量,变量的初始值是undefined.在函数调用时,把实参传入进来,变成真实的值
            console.log(name, age); //davina 20
        }
        person('davina', 20);

        function add(x, x) {
            return x;
        }
        console.log(add(1, 2)); //2

        /* function add(x,x){
             'use strict'
             return x;
         }
         cosole.log(add(1,2));  //报错 */

        function fn(x, y) {
            console.log(x, y);  //1 undefined
        }
        fn(1);

        function add(x, y) {

            console.log(arguments[0], arguments[1], arguments[2], arguments.length);  //1 2 3 3
            return x + 1;
        }
        add(1, 2, 3);
        console.log(add.length);//2
    </script>
    <script>
        //传递一个基本类型值时,被传递的值会被赋给一个局部变量
        function add(num) {
            num += 10;
            return num;
        }
        let count = 10;
        let re = add(count);
        console.log(re, count);//20 10
        //变量作为参数传递给函数,在函数内部,参数num被加10,这一变化不会影响函数外面的值。

        //向参数传递引用类型值时
        function fn(obj) {
            obj.name = 'davina';
        }
        let person = new Object();
        fn(person);
        console.log(person.name); //davina
    //函数外部创建一个对象person,然后用fn来进行调用,person的值复制一份后传递给参数obj,使得obj的引用与person指向同一对象
    </script>

  三、函数调用

    只有函数被调用时才会执行,调用运算符是跟在任何一个函数值的表达式后的一对圆括号。圆括号内可以包括多个用逗号隔开的表达式,每个表达式产生一个参数值,每个参数值被赋予函数声明时定义的形参名。js的函数调用会出现两个额外的参数,arguments和this.argument是参数组,它并不是一个真实的数组但还是可以通过.lenght方法获得长度。函数调用分为以下4种:

    1、函数调用模式(函数名(参数 ))

      当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的,对于普通的函数调用来说,函数的返回值就是调用表达式的值。

    <script>
        let add = function (a, b) {
            // 'use strict';
            // console.log(this); //undefined

            alert(this);//Window
            
            return a + b;
        }
        let sum = add(3, 4);//7;
        console.log(sum);
    </script>

    使用函数调用模式调用函数时,在非严格模式下,this指向window,在严格模式下this指向undefined。

    2、方法调用模式  ( 对象.方法(参数) )

    当一个函数被保存为对象的一个属性时,我们称它为一个方法,当一个方法被调用时,this被绑定到该对象。如果调用表达式包含一个提取属性的动作,那么它就是被当做一个方法来调用。(简而言之方法调用就是用对象的方法调用,所以说方法对象一定要有宿主对象)。

    方法可以使用this访问自己所属的对象,所以它能从对象中取值或对对象进行修改,this到对象的绑定发生在调用的时候。通过this可取得它们所属对象的上下文的方法称之为公共方法。

    任何函数只要作为方法调用都会传入一个隐匿的实参,这个实参是一个对象,方法调用的母体就是这个对象。

    和变量不同,关键字this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this,如果嵌套函数作为方法调用,其this的指向是调用它的对象,如果嵌套函数作为函数调用,其this的指向就是全局对象(严格模式下就是undefined)。

    所以总结来看:方法调用模式不是独立的,需要宿主,而函数调用模式是独立的

           方法调用模式方法:obj.fn(),函数调用模式方法:fn();

           方法调用模式中,this指宿主,而函数调用模式中this指全局对象

    <script>
        let myObject = {
            value: 0,
            fn1: function () {
                console.log(this);//myObject
                return this;
            },
            fn2: function () {
                console.log(this);//myObject
                this.value = 1;
            },
            fn3:function(){
                function n(){
                    console.log(this);//window
                    return this;
                }
                return n();
            }
        }

        console.log(myObject.fn1().value);//0

        myObject.fn2();
        console.log(myObject.fn1().value);//1

        console.log(myObject.fn3());//window
    </script>

    3、构造器调用模式

      如果函数或者方法调用之前带有关键字new.那么它就构成构造函数调用。new是一个运算符,专门用来申请创建对象,创建出来的对象传递给构造函数的this,然后利用构造函数对其初始化。

      执行步骤:var p = new Person();

      如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内。如果构造函数没有形参,js构造函数调用的语法是允许省略实参列表和圆括号的。凡是没有形参的构造函数调用都可以省略圆括号。

      构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数休执行完毕时,它会显示返回,在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。

 <script>
        let o = {
            m: function () {
                return this;
            }
        }
     let obj = new o.m(); console.log(obj, obj === o);//{} false console.log(obj.constructor === o.m);//true </script>

    4、间接调用模式

     js中函数也是对象,函数对象也可以包含方法,call(),apply()t和bind()方法可以用来间接调用函数。

     这两个方法都允许显式指定调用所需的this的值,可以修改this的指向。call()方法使用它自有的实参列表作为函数的实参,apply()方法则要求以数组的形式传入参数。

     语法:call形式:函数名.call()   apply形式:函数名.apply()    bind形式:函数名.bind()

       call()和apply()的相同点:两个方法都使用了对象本身作为第一个参数,都是用来改变this的指向。

     call()和apply()的不同点:apply()第二个参数是数组;call()第二参数是参数列表。 在js的严格模式下,在调用函数时第一个参数会成为this的值,即使该参数不是一个对象,在非严格模式下,如果第一个参数的仠是null或者是undefined,它将使用全局对象替代。

     bind() :call()改过this指向后,会再执行函数,bind()改过this后,不执行函数,会返回一个绑定新this的函数。

    <script>
        let obj = {};//定义一个空对象
        function fn(x, y) {
            console.log(this);//obj
            console.log(x, y);//1,2
        }
        fn.apply(obj, [1, 2]);
        fn.call(obj, 1, 2);//直接调用
        let b = fn.bind(obj);//bind()不能调用函数
        b();//此时才调用
    </script> 

    四、函数返回值

    函数中的return语句用来返回函数调用后的返回值,阻止函数继续运行。它经常作为函数的最后一条出现,当return被执行时,函数立即返回不再执行余下的语句。如果函数里没有return,那这个函数的返回值结果就是undefined。它只能出现在函数体内,如是不是那就会报错。一个函数中可以有多个return语句。

<script>
    function fn(a, b) {
        return a + b;
        alert(1); //不会执行,因为放在了return后面
    }
    console.log(fn(2, 3));  //5

    function fn1(a, b) {
        let c = a + b;
    }
    console.log(fn1(4, 5));//undefined 函数里没有return
</script>

  return例子:点击按钮,在按钮后方放入相加的值

    <script>
        window.onload = function () {
            let btns = document.querySelectorAll("input[type=button]");
            let texts = document.querySelectorAll("input[type=text]");
            function add() {
                let result=0;
                for (var i = 0; i < arguments.length; i++) {
                    result += arguments[i];
                }
                return result;
            }
            btns[0].onclick=function(){
                texts[0].value=add(12,34,56,78);

            };
            btns[1].onclick=function(){
                texts[1].value=add(12,56,78);

            }
        }
    </script>
    <input type="button" value="按钮一">
    <input type="text">
    <input type="button" value="按钮二">
    <input type="text">

 

 

 

 

  

posted on 2019-11-18 20:30  人称小小贩  阅读(315)  评论(0编辑  收藏  举报