zoukankan      html  css  js  c++  java
  • javascript函数的定义和调用(包括方法)

    函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。

    JavaScript 函数(函数的执行条件:case1:利用声明定义函数,那么只有在函数被调用的时候执行。case2:利用表达式定义,那么因为函数是一个表达式,因而马上执行。也就是说函数执行要么是调用,要么是程序运行到带有函数的表达式时,执行函数。)

    函数分为普通函数、方法、构造函数


    函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。

    实例

    <!DOCTYPE html>
    <html>
    <head>
    <script>
    function myFunction()
    {
    alert("Hello World!");
    }
    </script>
    </head>
    <body>
    <button onclick="myFunction()">Try it</button>
    </body>
    </html>

    JavaScript 函数定义


    JavaScript 使用关键字 function 定义函数。

    函数可以通过声明定义,也可以是一个表达式

    (一)函数声明 (声明定义)

    在之前的教程中,你已经了解了函数声明的语法 :

    function functionName(parameters) {
      执行的代码
    }

    实例

    function myFunction(a, b) {
        return a * b;
    }
     

    函数声明后不会立即执行,会在我们需要的时候调用到。可以在某事件发生时直接调用函数(比如当用户点击按钮时),并且可由 JavaScript 在任何位置进行调用。

    (二)函数表达式(表达式定义)

    JavaScript 函数可以通过一个表达式定义。

    函数表达式可以存储在变量中:

    实例

    var x = function (a, b) {return a * b};

    尝试一下 »

    在函数表达式存储在变量后,变量也可作为一个函数使用:

    实例

    var x = function (a, b) {return a * b};
    var z = x(4, 3);
    这里z的值为12.

    以上函数实际上是一个 匿名函数 (函数没有名称)。

    函数存储在变量中,不需要函数名称,通常通过变量名来调用。

    Note 上述函数以分号结尾,因为它是一个执行语句。
     
     

    (三)Function() 构造函数

    在以上实例中,我们了解到函数通过关键字 function 定义。

    函数同样可以通过内置的 JavaScript 函数构造器(Function())定义。

    实例

    var myFunction = new Function("a", "b", "return a * b");

    var x = myFunction(4, 3);

    尝试一下 »

    实际上,你不必使用构造函数。上面实例可以写成:

    实例

    var myFunction = function (a, b) {return a * b}

    var x = myFunction(4, 3);

    (四)自调用函数

    函数表达式可以 "自调用"。

    自调用表达式会自动调用。

    如果表达式后面紧跟 () ,则会自动调用。

    Y不能自调用声明的函数。

    通过添加括号,来说明它是一个函数表达式:

    实例

    (function () {
        var x = "Hello!!";      // 我将调用自己
    })();

    尝试一下 »

    以上函数实际上是一个 匿名自我调用的函数 (没有函数名)。

    函数的特点:

    (1)函数可作为一个值使用

    JavaScript 函数作为一个值使用:

    实例

    function myFunction(a, b) {
        return a * b;
    }

    var x = myFunction(4, 3);

    (2)JavaScript 函数可作为表达式使用:

    实例

    function myFunction(a, b) {
        return a * b;
    }

    var x = myFunction(4, 3) * 2;

    函数是对象

    在 JavaScript 中使用 typeof 操作符判断函数类型将返回 "function" 。

    但,JavaScript 函数描述为一个对象更加准确。

    JavaScript 函数有 属性 和 方法

    arguments.length 属性返回函数调用过程接收到的参数个数;

    toString() 方法将函数作为一个字符串返回:

    实例

    function myFunction(a, b) {
        return a * b;
    }

    var txt = myFunction.toString();

     具体代码:

    Note 函数定义作为对象的属性,称之为对象方法。                                                                (例一)
    函数如果用于创建新的对象,称之为对象的构造函数。                                                     (例二)

    在一个对象中绑定函数,称为这个对象的方法:

    在JavaScript中,对象的定义是这样的:

    var xiaoming = {
        name: '小明',
        birth: 1990
    };
    

    但是,如果我们给xiaoming绑定一个函数,就可以做更多的事情。比如,写个age()方法,返回xiaoming的年龄:

    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
    };
    
    xiaoming.age; // function xiaoming.age()
    xiaoming.age(); // 今年调用是25,明年调用就变成26了

    绑定到对象上的函数称为方法,和普通函数也没啥区别,但是它在内部使用了一个this关键字,这个东东是什么?

    JavaScript中的this

    是 JavaScript 语言的一个关键字。this是函数运行时,在函数体内部自动生成的一个对象,只能在函数体内部使用。

    在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaomingbirth属性

    让我们拆开写:

    function getAge() {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: getAge
    };
    
    xiaoming.age(); // 25, 正常结果
    getAge(); // NaN

    单独调用函数getAge()怎么返回了NaN请注意,我们已经进入到了JavaScript的一个大坑里。

    JavaScript的函数内部如果调用了this,那么这个this到底指向谁?

    答案是,视情况而定!

    如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。

    如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

    坑爹啊!

    更坑爹的是,如果这么写:

    var fn = xiaoming.age; // 先拿到xiaoming的age函数
    fn(); // NaN
    

    也是不行的!要保证this指向正确,必须用obj.xxx()的形式调用!

    由于这是一个巨大的设计错误,要想纠正可没那么简单。ECMA决定,在strict模式下让函数的this指向undefined,因此,在strict模式下,你会得到一个错误:

    'use strict';
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
    };
    
    var fn = xiaoming.age;
    fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined
    

    这个决定只是让错误及时暴露出来,并没有解决this应该指向的正确位置。

    有些时候,喜欢重构的你把方法重构了一下:

    'use strict';
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            function getAgeFromBirth() {
                var y = new Date().getFullYear();
                return y - this.birth;
            }
            return getAgeFromBirth();
        }
    };
    
    xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
    结果又报错了!原因是this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了!(在非strict模式下,它重新指向全局对象window!)
    修复的办法也不是没有,我们用一个that变量首先捕获this
    'use strict';
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            var that = this; // 在方法内部一开始就捕获this
            function getAgeFromBirth() {
                var y = new Date().getFullYear();
                return y - that.birth; // 用that而不是this
            }
            return getAgeFromBirth();
        }
    };
    
    xiaoming.age(); // 25
    

    var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。

    例:你可能会发现别人写的代码中有这么一句:var that = this;,这代表什么意思呢?
    在javascript中,this代表的是当前对象。
    var that=this就是将当前的this对象复制一份到that变量中。这样做有什么意义呢?

    $(‘#zhetenga’).click(function(){
    //this是被点击的#zhetenga
    var that = this;

    $(‘.zhetenga’).each(function(){

    //this是.zhetenga循环中当前的对象
    //that仍然是刚才被点击的#zhetenga
    });
    });
    可以看到,this对象在程序中随时会改变,而var that=this之后,that没改变之前仍然是指向当时的this,这样就不会出现找不到原来的对象。

     

    方法

    阅读: 141907

    在一个对象中绑定函数,称为这个对象的方法。

    在JavaScript中,对象的定义是这样的:

    var xiaoming = {
        name: '小明',
        birth: 1990
    };
    

    但是,如果我们给xiaoming绑定一个函数,就可以做更多的事情。比如,写个age()方法,返回xiaoming的年龄:

    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
    };
    
    xiaoming.age; // function xiaoming.age()
    xiaoming.age(); // 今年调用是25,明年调用就变成26了
    

    绑定到对象上的函数称为方法,和普通函数也没啥区别,但是它在内部使用了一个this关键字,这个东东是什么?

    在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。所以,this.birth可以拿到xiaomingbirth属性。

    让我们拆开写:

    function getAge() {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: getAge
    };
    
    xiaoming.age(); // 25, 正常结果
    getAge(); // NaN
    

    单独调用函数getAge()怎么返回了NaN请注意,我们已经进入到了JavaScript的一个大坑里。

    JavaScript的函数内部如果调用了this,那么这个this到底指向谁?

    答案是,视情况而定!

    如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。

    如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

    坑爹啊!

    更坑爹的是,如果这么写:

    var fn = xiaoming.age; // 先拿到xiaoming的age函数
    fn(); // NaN
    

    也是不行的!要保证this指向正确,必须用obj.xxx()的形式调用!

    由于这是一个巨大的设计错误,要想纠正可没那么简单。ECMA决定,在strict模式下让函数的this指向undefined,因此,在strict模式下,你会得到一个错误:

    'use strict';
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
    };
    
    var fn = xiaoming.age;
    fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined
    

    这个决定只是让错误及时暴露出来,并没有解决this应该指向的正确位置。

    有些时候,喜欢重构的你把方法重构了一下:

    'use strict';
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: function () {
            function getAgeFromBirth() {
                var y = new Date().getFullYear();
                return y - this.birth;
            }
            return getAgeFromBirth();
        }
    };
    
    xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
    

    结果又报错了!原因是this指针只在age方法的函数内指向xiaoming,在函数内部定义的函数,this又指向undefined了!(在非strict模式下,它重新指向全局对象window!)

    修复的办法也不是没有,我们用一个that变量首先捕获this

    apply修复getAge()调用:

    function getAge() {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: getAge
    };
    
    xiaoming.age(); // 25
    getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空
    

    JavaScript中的每一个Function对象都有一个apply()方法和一个call()方法,它们的语法分别为:

    /*apply()方法*/
    function.apply(thisObj[, argArray])
    
    /*call()方法*/
    function.call(thisObj[, arg1[, arg2[, [,...argN]]]]);

    ECMAScript规范给所有函数都定义了Call()与apply()两个方法,call与apply的第一个参数都是需要调用的函数对象,在函数体内这个参数就是this的值,剩余的参数是需要传递给函数的值,call与apply的不同就是call传的值可以是任意的,而apply传的剩余值必须为数组.

    它们各自的定义:

    apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。

    call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。

    它们的共同之处:

    都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象”。

    1. function person(firstname,lastname,age,eyecolor)     //函数用于创造person对象,称之为对象的构造函数;这里函数定义了person对象,因此称其为person的构造函数。
      1. {
        1. this.firstname=firstname;
        2. this.lastname=lastname;
        3. this.age=age;
        4. this.eyecolor=eyecolor;
        5. this.changeName=changeName;
        6. function changeName(name)                  //函数定义为对象的属性,称之为对象方法;这里ChageName定义了person的ChageName属性,称其为方法
        7.     {
        8.           this.lastname=name;
        9.      }
        10. }

    bind()

    bind方法,顾名思义,就是绑定的意思,到底是怎么绑定然后怎么用呢,下面就来说说我对这个方法的理解。

    语法

    fun.bind(this,arg1,arg2,...)

    bind()方法会创建一个新的函数,称为绑定函数,fun方法在this环境下调用

    该方法可传入两个参数,第一个参数作为this,第二个及以后的参数则作为函数的参数调用

    实例 

    1.创建绑定函数

     1 this.a = 1;
     2 var module = {
     3     a : 2,
     4     getA:function() {
     5     return this.a;    
     6     }
     7 };
     8 module.getA();//2
     9 
    10 var getA1 = module.getA;
    11 // getA在外部调用,此时的this指向了全局对象
    12 getA1();//1
    13 
    14 // 再把getA1方法绑定到module环境上
    15 var getA2 = getA1.bind(module);
    16 getA2();

     从上面的例子可以看出,为什么要创建绑定函数,就是当我们调用某些函数的时候是要在特定环境下才能调用到,所以我们就要把函数放在特定环境下,就是使用bind把函数绑定到特定的所需的环境下。

     

    函数分为几种类型

    (一)一般函数,只利用函数进行操作,无参、无返回值。

    (二)调用带参数的函数

    在调用函数时,您可以向其传递值,这些值被称为参数。

    这些参数可以在函数中使用。

    您可以发送任意多的参数,由逗号 (,) 分隔:

    myFunction(argument1,argument2)

    当您声明函数时,请把参数作为变量来声明:

    function myFunction(var1,var2)
    {
    代码
    }

    变量和参数必须以一致的顺序出现。第一个变量就是第一个被传递的参数的给定的值,以此类推。

    实例

    <button onclick="myFunction('Harry Potter','Wizard')">Try it</button>

    <script>
    function myFunction(name,job)
    {
    alert("Welcome " + name + ", the " + job);
    }
    </script>


    尝试一下 »

    上面的函数在按钮被点击时会提示 "Welcome Harry Potter, the Wizard"。

    (三)带有返回值的函数

    有时,我们会希望函数将值返回调用它的地方

    通过使用 return 语句就可以实现。

    在使用 return 语句时,函数会停止执行,并返回指定的值。

    语法

                          function myFunction()
                         {
                                 var x=5;
                                 return x;
                         }

                      上面的函数会返回值 5。

    注意: 整个 JavaScript 并不会停止执行,仅仅是函数。JavaScript 将继续执行代码,从调用函数的地方。

    函数调用将被返回值取代:

             1.        var myVar=myFunction();

                      myVar 变量的值是 5,也就是函数 "myFunction()" 所返回的值。

    即使不把它保存为变量,您也可以使用返回值:

             2.      document.getElementById("demo").innerHTML=myFunction();

            "demo" 元素的 innerHTML 将成为 5,也就是函数 "myFunction()" 所返回的值。

    您可以使返回值基于传递到函数中的参数:

    实例

    计算两个数字的乘积,并返回结果:

    function myFunction(a,b)
    {
    return a*b;
    }

    document.getElementById("demo").innerHTML=myFunction(4,3);

    "demo" 元素的 innerHTML 将是:

    12
     

                 在您仅仅希望退出函数时 ,也可使用 return 语句。返回值是可选的:

             function myFunction(a,b)
             {
                   if (a>b)
                  {
                            return;
                  }
                   x=a+b
             }

    如果 a 大于 b,则上面的代码将退出函数,并不会计算 a 和 b 的总和。

    调用函数 

    (一)this关键字

    一般而言,在Javascript中,this指向函数执行时的当前对象

    1.普通函数(全局函数)

    2.函数作为方法调用(对象的方法)

    在 JavaScript 中你可以将函数定义为对象的方法。

    以下实例创建了一个对象 (myObject), 对象有两个属性 (firstName 和 lastName), 及一个方法 (fullName):

    实例

    var myObject = {
        firstName:"John",
        lastName: "Doe",
        fullName: function () {
            return this.firstName + " " + this.lastName;
        }
    }
    myObject.fullName();         // 返回 "John Doe"

    fullName 方法是一个函数。函数属于对象。 myObject 是函数的所有者。

    this对象,拥有 JavaScript 代码。实例中 this 的值为 myObject 对象

    具体代码如下:

    chageName 方法是一个函数。函数属于对象。 person 是函数的所有者。

    this对象,拥有 JavaScript 代码。实例中 this 的值为 person对象。

    函数作为对象方法调用,会使得 this 的值成为对象本身。

    3.

    使用构造函数调用函数

    如果函数调用前使用了 new 关键字, 则是调用了构造函数。

    这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象:

    实例

    // 构造函数:
    function myFunction(arg1, arg2) {
        this.firstName = arg1;
        this.lastName  = arg2;
    }

    // This creates a new object
    var x = new myFunction("John","Doe");
    x.firstName;                             // 返回 "John"

    尝试一下 »

    构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。

    Note 构造函数中 this 关键字没有任何的值。
    this 的值在函数调用时实例化对象(new object)时创建。

    (二)

    1.常规调用

        function myFunction(a, b) {

            return a * b;
         }
       myFunction(10, 2);           // myFunction(10, 2) 返回 20

    2.函数定义方式为表达式,通过变量进行调用。

    var abs = function (x) {

        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    };
    

    调用函数时,按顺序传入参数即可:

    abs(10); // 返回10
    abs(-9); // 返回9

    由于JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数:
    abs(10, 'blablabla'); // 返回10
    abs(-9, 'haha', 'hehe', null); // 返回9
    

    传入的参数比定义的少也没有问题:

    abs(); // 返回NaN

    此时abs(x)函数的参数x将收到undefined,计算结果为NaN

    //typeof 和throw的利用

    要避免收到undefined,可以对参数进行检查:

    function abs(x) {
        if (typeof x !== 'number') {
            throw 'Not a number';
        }
        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }

    arguments的用法
    arguments它是一个类似于数组的东东,如果把它看作一个数组的话,那么它的值为所有调用它所在的函数的所有参数值,以下面的代码为例:

    function abs()
    {
    for(var i=0;i<arguments.length;i++) //arguments在abs这个函数里;arguments它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。
     alert(arguments[i]);                              所以,当执行abs('wo','shi',6,'zhonguo','ren')此时arguments的值相当于['wo','shi',6,'zhonguo','ren'
    }                                                 当执行abs('hello',88,99,100)时,arguments的值为[‘hello’,88,99,100]
    abs('wo','shi',6,'zhonguo','ren'); //调用函数,括号里的值为调用函数的参数值;
    abs('hello',88,99,100); //同上

    通过上述例子,我们可以把arguments看做一个厉害的角色,凡是调用了我的,我把你们的值全部存储在我的库中;

    那么我们到底用arguments做什么呢?

    实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:

    // foo(a[, b], c)
    // 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
    function foo(a, b, c) {
        if (arguments.length === 2) {
            // 实际拿到的参数是a和b,c为undefined
            c = b; // 把b赋给c
            b = null; // b变为默认值
        }
        // ...
    }

    要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。

    rest参数

    由于JavaScript函数允许接收任意个参数,于是我们就不得不用arguments来获取所有参数:

    function foo(a, b) {
        var i, rest = [];
        if (arguments.length > 2) {
            for (i = 2; i<arguments.length; i++) {
                rest.push(arguments[i]);
            }
        }
        console.log('a = ' + a);
        console.log('b = ' + b);
        console.log(rest);
    }

    为了获取除了已定义参数ab之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的rest参数,有没有更好的方法?

    ES6标准引入了rest参数,上面的函数可以改写为:

         function foo(a,b,...rest){

             console.log('a = ' + a);

        console.log('b = ' + b);
        console.log(rest);
    }
    
      foo(1, 2, 3, 4, 5);
        // 结果:
       // a = 1
      // b = 2
     // Array [ 3, 4, 5 ]
    
     foo(1);
     // 结果:
     // a = 1
     // b = undefined
     // Array []

    rest参数只能写在最后,前面用...标识,从运行结果可知,传入的参数先绑定ab,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。

    如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

    return

    如果要在被调用函数中返回一个结果,那么必须在被调用函数中用return语句;

    如果把return语句拆成两行:

    function foo() {
        return
            { name: 'foo' };
    }
    
    foo(); // undefined
    

    要小心了,由于JavaScript引擎在行末自动添加分号的机制,上面的代码实际上变成了:

    function foo() {
        return; // 自动添加了分号,相当于return undefined;
            { name: 'foo' }; // 这行语句已经没法执行到了
    }
    

    所以正确的多行写法是:

    function foo() {
        return { // 这里不会自动加分号,因为{表示语句尚未结束
            name: 'foo'
        };
    }

     
  • 相关阅读:
    Web Designer Intern
    Internship UI/UX Web Designer
    HTML / CSS Frontend Software Engineer Internship
    CSS 07 文本
    CSS 06 背景
    CSS 05 尺寸大小
    CSS 04 注释
    CSS 03 选择器
    Why Ancient Greeks are Always Nude
    C#表示空字符
  • 原文地址:https://www.cnblogs.com/yyn120804/p/6391916.html
Copyright © 2011-2022 走看看