JavaScript之函数(上)

       在编程语言中,不管是面向过程的C,兼备面过程和对象的c++,仍是面向对象的编程语言,如java,.net,php等,函数均扮演着重要的角色。固然,在面向对象编程语言JavaScript中(严格来讲,JS属于弱面向对象编程语言),函数(function)更扮演着极其重要的角色和占有极其重要的地位。在本篇文章中,不论述什么是JS,JS解决什么问题等之类问题,而是重点阐述JS中的函数(function)。php

一  JavaScript函数java

(一)何为函数c++

关于函数的定义,咱们先从两个角度来思考:数学角度和编程语言角度。编程

1.数学角度:在数学领域,关于“函数”二字,再熟悉不过,如三角函数,反三角函数,幂函数,对数函数,指数函数,微积分函数等;后端

2.编程角度:在编程领域,你们最熟悉且最早接触的应该是"Main函数"了,除此外,如日期函数(Date),数学函数(Math)等,固然除了内置函数外,还包括用户自定义函数;闭包

      综合1,2点,能够将函数定义以下:编程语言

函数是解决某类问题的集合,是某类问题的高度抽象,它具备必定的通用性和复用性。

(二)定义函数函数

在Javascript中,存在三种经典的函数定义方式:函数声明式,函数表达式和函数构造式this

1.函数声明式spa

1 //定义两个数相加函数
2     function AddNum(num1, num2) {
3         return num1 + num2;
4     }

注意:函数声明式,不能用匿名函数,以下方式定义错误的

1 function (num1, num2) {
2         return num1 + num2;
3     }

2.函数表达式

1  //定义两个数相加函数
2     var AddFun=function AddNum(num1, num2) {
3         return num1 + num2;
4     }

注意:函数表达式通常用匿名函数,由于调用时,不用函数名,所以,如上调用也可写成以下:

1 var AddFun = function(num1, num2) {
2         return num1 + num2;
3     }

3.函数构造式

1 var sum = new Function('num1', 'num2', 'return num1 + num2')
2  console.log(sum(10,20));//30

 (三)函数调用

 在JavaScript中,函数的调用采用“函数名(参数)”的格式来进行调用。

须要注意的是,JavaScript函数调用与后端语言函数调用(如java,.net等)存在细微差异,即JavaScript没有函数重载,参数的参数个数,由实参决定,而不是由形参决定。

1.声明式调用

 调用方式一:通常调用

1 //定义两个数相加函数
2 function AddNum(num1, num2) {
3     return num1 + num2;
4 }
5 
6 
7 console.log(Add(10,20));//30

调用方式二:自调用

1 (function AddNum(num1, num2) {
2       console.log(num1 + num2);
3   })(10,20);//30

注意:自调用通常用匿名函数,由于在调用时,不须要函数名,所以,也可写成以下方式:

1  (function (num1, num2) {
2         return num1 + num2;
3     })(10, 20);//30

2.表达式调用

1 //定义两个数相加函数
2  var AddFun = function (num1, num2){
3            return num1 + num2;
4  }
5      
6  console.log(AddFun(10, 20));//30

二 函数变量

在JavaScript编程语言中,变量的定义是经过var关键字来定义的(若变量不经过var定义,则为全局变量,但不推荐这么作),与其余编程语言同样,变量也分为两大类,即局部变量和全局变量。

(1)局部变量:做用域为其所在的函数;

(2)全局变量:做用域为整个过程;

(3)变量做用域:JS中的变量做用域是经过this指针,从当前的做用域开始,从当前做用域由内向外查找,直到找到位置,这里分为几个逻辑:

a.从当前做用域由内向外查找,若找到,就中止查找,不然,继续查找,直到查到window全局做用域为止;

b.当内部做用域变量名与外部做用域变量名相同时,内部做用域的覆盖外部做用域。

咱们来看一个例子:

 1 var dateTime='2018-09-16';
 2 function GetUserInfo(){
 3     var age=120;
 4     var name="Alan_beijing";
 5     function Say(){
 6        var name="老王";
 7        var address="shanghai";
 8        console.log(address+"-"+name+"-"+age+"-"+dateTime);//shanghai-老王-2018-06-05
 9     }
10    return Say();
11 }
12 
13 
14 GetUserInfo();//shanghai-老王-120-2018-09-16

来分析一下变量及其做用域:

如上图,有4个做用域,当函数执行以下语句时,发生以下过程:

1 console.log(address+"-"+name+"-"+age+"-"+dateTime);

a.js当前this环境做用域为4做用域;

b.this指针寻找变量:addresss,name,age,dateTime,从当前做用域向外做用域逐层寻找,直到寻找到变量为止,若寻找到最外层做用域任然没找到,则会出错,提示该变量未声明;

c.当内外层变量相同时,内层变量覆盖外层变量,如4做用域的name覆盖3做用域的name;

 

三   函数声明式定义存在的问题

 在js中,存在声明提早问题,看看以下例子。

1 var globleName="Alan_beijing";
2 function Say(){
3    console.log(localName);  // undefined,不报错,是由于变量声明提早
4    var localName="Alan";
5    console.log(localName);// Alan
6 }

看过如上代码,你可能会问,函数执行到console.log(localName); 时,应该报错,由于localName未定义。

若是在后端语言,如java,.net中,可能会报错,可是在js中,却不会,不报错的缘由是:在js中存在声明提早。

如上代码至关于以下代码:

1 var globleName="Alan_beijing";
2 function Say(){
3    var localName;
4    console.log(localName);
5    localName="Alan";
6    console.log(localName);
7 }

 

四  函数几大关键点

1.匿名函数

匿名函数,顾名思义,就是没名字的的函数,咱们来看看以下两个例子:

函数表达式

1 //定义两个数相加函数
2     var AddFun=function (num1, num2) {
3         return num1 + num2;
4     }

当即执行函数

(function AddNum(num1, num2) {
      console.log(num1 + num2);
   })(10,20);//30

从如上,不难看出,匿名函数主要用域函数表达式和当即执行函数。

2.闭包

闭包的根源在于变量的做用域问题。

咱们先来考虑这样一个问题,假设在面向对象编程语言中,某个方法的变量被定义为私有变量,其余函数要获取访问该变量,.net怎么处理?

方法一:构造函数

方法二:单例模式

一样地,在js中,一样存在外部函数调用内部函数变量问题,js运用的技术就叫作闭包。

所谓闭包,就是将不可访问的变量做为函数返回值的形式返回来,从而实现函数外部访问函数内部变量目的。

1 //闭包
2     function GetName() {
3         var name = "Alan_beijing";
4         var age = function () {
5             var age = 30;
6             return age;
7         }
8         return name + age;
9     }

3.js多态问题(重载问题)

在面向对象编程语言,如.net中,实现多态的方式大体有以下:

a.接口

b.抽象类

c.虚方法

d.方法重载

然而,在js中,没有面向对象之说(OO),那么js是如何实现多态的呢?根据方法实际传递的参数来决定。

1  //重载
2 function SetUserInfo(userName, age, address, tel, sex) {
3     console.log(arguments.length);//4
4 }
5 
6 SetUserInfo('Alan_beijing',44,'china-shanghai','xxxx');

从如上能够看出,传递多少个参数,就接收多个参数,若是在现象对象编程语言中实现该功能,至少须要写一堆代码,这也是体现js强大之一。

4.递归

来看看一个递归阶乘函数

1 //递归
2     function factorial(num) {
3         if (num < 1) {
4             return 1;
5         } else {
6             return num * arguments.callee(num-1);
7         }
8     }

若是是.net,咱们通常会这样写

1 //递归
2     function factorial(num) {
3         if (num < 1) {
4             return 1;
5         } else {
6             return num * factorial(num-1);
7         }
8     }

然而,这样写,却会存在异常状况

1  var factorial1 = factorial;
2     factorial = null;//将factorial变量设置为null
3     console.log(factorial1(4));//出错

 5.原型和原型链

面向对象编程语言的显著特征之一是面向对象,然而,在js中,没有对象,那么js是如何面向对象的功能的呢(封装,继承,多态)?固然是经过原型和原型链来实现的。

你们都比较怕原型和原型链,其实很简单,它的功能至关于面向对象的继承,主要解决继承和复用。

介于篇幅有限,余下的内容,将在下篇文章阐述.....

五  参考文献

【01】JavaScript 高级程序设计(第三版)   (美)Nicholas C.Zakas 著       李松峰   曹力  译

【02】JavaScript 权威指南 (第6版)    David  Flanagan 著

相关文章
相关标签/搜索