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'
    };
}

 

 
posted @ 2017-02-12 21:42  ccfyyn  阅读(9105)  评论(0编辑  收藏  举报