详解JavaScript函数


Posted in Javascript onDecember 01, 2015

      函数是一组可以随时随地运行的语句,函数作为ECMAScript的核心是很重要的。函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。也就是函数是定义一次但却可以调用或执行任意多次的一段JavaScript代码。函数有时会有参数,即函数被调用时指定了值的局部变量。函数常常使用这些参数来计算一个返回值,这个值也成为函数调用表达式的值。
一、函数声明
       函数对于任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方,任何时候调用执行。JS中的函数使用function关键字来声明,后跟一组参数以及函数体。
       函数的基本语法是这样的:

<span style="font-size:18px;">function functionName(arg0, arg1, ... argN) { 
 statements 
}</span>

       ECMAScript规定的函数声明方式有三种:
(1)普通函数声明

<span style="font-size:18px;">function box(num1,num2){ 
 return num1+num2; 
}</span>

 (2)使用变量初始化什声明函数

<span style="font-size:18px;">var box=function(num1,num2){ 
 return num1+num2; 
}</span>

(3)使用Function构造函数声明

<span style="font-size:18px;">vax box=new Function('num1','num2','num1+num2');</span> 
 
二、函数的类型及函数的调用
 ECMAScript语法规定了
 (1)无参数的函数:函数的声明的时候没有参数,调用函数的时候直接使用即可。
function box(){ 
 document.write("我是中国人!"); 
} 
box();//函数调用

运行的结果为:我是中国人!
(2)带参数的函数:函数的声明的时候同时定义了参数变量,参数可以是多个。

function box(name,age) { 
 document.write("你的姓名是:"+name+"你的年龄是:"+age); 
} 
box("张三","24");//函数调用

运行的结果为:你的姓名是:张三
                       你的年龄是:24
(3)带有返回值的函数
       带参数和无参数的函数,都没有定义返回值,而是调用后直接执行的,实际上,任何函数都可以通过return语句跟后面的要返回的值来实现返回值
1)、无参数的函数

function box(){ 
 return "我是中国人!"; 
} 
document.write(box());

同上面的输出结果:我是中国人!
2)、带参数的函数

function box(name,age){ 
 return "你的姓名是:"+name+"<br/>"+"你的年龄是:"+age; 
} 
document.write(box("张三","24"));//函数调用 
document.write("<hr/>"); 
var demo=box("李四","23");//也可以重新赋值新的函数 
document.write(demo);

运行的结果为:

详解JavaScript函数

 (4)作为值的函数(比较特殊)
首先我们来看一个函数作为常规的变量的例子:

function box(sum,num){ 
 return sum+num;//这里传递的是函数的返回值和普通的变量一样 
} 
function sum(num){ 
 return num+10; 
} 
var result=box(sum(10),10); 
document.write("result="+result);

页面的输出结果为:result=30
下面则传递的是函数,仔细和上面的区分:

function box(sum,num){ 
 return sum(num);//这里传递的是函数 
} 
function sum(num){ 
 return num+10; 
} 
var result=box(sum,10); 
document.write("result="+result);

页面的输出结果为:result=20
三、函数的内部属性
       在函数内部,有两个特殊的对象:arguments对象和this对象。arguments对象是类数组对象,包含着传入函数中的所有参数,主要用途是保存函数参数,主要的属性有length,这个属性是动态的判断函数有多少个参数。但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
 (1)arguments对象的length属性
       JS函数不介意传递进来多少参数,也不会因为参数不统一而错误。实际上,函数体内可以通过arguments对象来
接收传递进来的参数。
       我们先来看一个我们在函数传递参数遇到的问题:函数声明时并不知道要定义多少个参数,在调用函数却出现多
出的或不足的问题。

function box(){ 
 return arguments[0]+"|"+arguments[1]; 
} 
document.write(box(1,2,3,4,5,6));

输出的结果为:1|2。因此输出的显然与我们想要做的不符,那么怎么解决呢?
有了arguments对象的length属性我们就能可以得到参数的数量,避免上面的错误出现。

function box(){ 
 return arguments.length; 
} 
document.write(box(1,2,3,4,5,6));

输出:6
       我们还可以利用length属性来智能的判断有多少参数,然后把参数进行合理的应用,比如,实现一个加法运算,将所有传进来的数字累加,而数字的个数又不确定。

function box(){ 
 var sum=0; 
 if(arguments.length==0) 
 { 
 return sum; 
 } 
 for(var i=0;i<arguments.length;i++) 
 { 
 sum=sum+arguments[i]; 
 } 
 return sum;//返回累加结果 
} 
document.write(box(1,2,3,4,5,6));

       输出:21
(2)arguments对象的callee属性
       还是来说问题:对于递归的问题我们很熟悉了,JS中也不例外

function box(num){ 
 if(num<=1) 
 { 
 return 1; 
 } 
 else 
 { 
 return num*box(num-1);//递归 
 } 
} 
document.write(box(4));

       输出:24
       对于阶乘函数一般要用到递归算法,所以函数内部一定对调用自身,如果函数名不改变是没有问题的,但一旦改变函数名,内部的自身调用需要逐一修改。为了解决这个问题,可以使用arguments.callee来代替。

function box(num){ 
 if(num<=1) 
 { 
 return 1; 
 } 
 else 
 { 
 return num*arguments.callee(num-1)//递归 
 } 
} 
document.write(box(4));

       输出:24
(3)this对象
       函数内部另一个特殊的对象时this,其行为与Java和C#中的this大致相似,换句话说,this引用的是函数据以行操作的对象,或者说函数调用语句所处的那个作用域。当在全局作用域中调用函数时,this对象引用的就是window(window是一个对象,是JavaScript中最大的对象,是最外围的对象)。

var color="红色";//这里的color是全局变量,并且这个变量是window的属性 
document.write(window.color+"<br/>"); 
document.write(this.color+"<br/>"); 
var box={ 
 color:"蓝色",//这里的color是box下的属性,是局部变量 
 sayColor:function(){ 
 return this.color;//此时的this只能是box中的color 
 } 
}; 
document.write(box.sayColor()+"<br/>");//局部的 
document.write(this.color);//全局的

       运行的结果为:

详解JavaScript函数

四、函数属性和方法
(1)JavaScript中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。其中,length属性表示函数希望接受的命名参数的个数。

function box(num1,num2){ 
 return num1+num2; 
} 
document.write(box.length);

输出的结果;2
       对于prototype属性,它是保存所有实例方法的真正所在,也就是原型。这个属性我们先不做过多的介绍。prototype属性下有两个方法:apply()和call(),每个函数都包含这两个非继承而来的方法。这两个方法的用途都在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

function box(num1,num2){ 
 return num1+num2; 
} 
function sayBox(num1,num2){ 
 return box.apply(this,[num1,num2]);//this表示作用域,这里是window,[]表示box所需的参数 
} 
function sayBox2(num1,num2){ 
 return box.apply(this,arguments);//arguments对象表示box所需的参数 
} 
document.write(sayBox(10,10)+"<br/>"); 
document.write(sayBox2(10,10));

       输出的结果为:20
                                20
(2)call()方法和apply()方法延伸
       call()方法和apply()方法相同,它们的区别仅仅在于接收参数的方式不同。对于call()方法而言,第一个参数作用域,没有变化,变化的只是其余参数都是直接传递给函数的。

function box(num1,num2){ 
 return num1+num2; 
} 
function callBox(num1,num2){ 
 return box.call(this,num1,num2);//区别apply()方法 
} 
document.write(callBox(10,10));

       输出的结果为:20
       call()方法和apply()方法真正的作用是扩展函数赖以运行的作用域

var color="红色";//全局变量 
var box={ 
 color:"蓝色",//局部变量 
}; 
function sayColor(){ 
 return this.color; 
} 
document.write(sayColor()+"<br/>");//作用域在Window 
document.write(sayColor.call(this)+"<br/>");//作用域在Window下 
document.write(sayColor.call(window)+"<br/>");//作用域在Window下 
document.write(sayColor.call(box));//作用域在box下,对象冒充

        输出的结果为:

详解JavaScript函数

       使用call()方法或者apply()方法来扩充作用域的最大好处就是对象不需要与方法发生任何耦合关系。也就是说,box对象和sayColor()方法之间不会有多余的关联操作,比如;box.sayColor=sayColor;
五、ECMAScript闭包
       ECMAScrip最易让人误解的一点是,它支持闭包。闭包,指的是词法表示包括不被计算的变量的函数,就是说,函数可以使用函数之外定义的变量。
       其实我在前面的博文已经使用到了闭包,比如在轻松学习JavaScript七:JavaScript的流程控制语句中使用的变量time就是全局变量,函数myFunction()使用这个全局变量,并不是函数本身定义的。还是看一下那个实例吧:

var time=new Date().getHours(); 
document.write("当前北京时间:"+time); 
function myFunction() 
{ 
 var x=""; 
 if (time<20) 
 { 
 x="Good day"; 
 } 
 document.getElementById("demo").innerHTML=x; 
}

(1)简单的闭包实例
       在ECMAScript中使用全局变量是一个简单的闭包实例。请思考下面这段代码输出的结果是什么:

var sMessage = "hello world"; 
function sayHelloWorld() { 
 document.write(sMessage); 
} 
sayHelloWorld();

       在上面这段代码中,脚本被载入内存后,并没有为函数sayHelloWorld()计算变量sMessage的值。该数捕 sMessage的值只是为了以后的使用,也就是说,解释程序知道在调用该函数时要检查sMessage的值。sMessage将在函数调用sayHelloWorld()是在(最后一行)被赋值,显示消息"hello world"。
(2)复杂的闭包实例
       在一个函数中定义另一个会使闭包变得更加复杂。例如:

var iBaseNum = 10;//全局变量 
function addNum(iNum1, iNum2) { 
 function doAdd() { 
 return iNum1 + iNum2 + iBaseNum; 
 } 
 return doAdd(); 
} 
document.write(addNum(10,10));

       这里,函数addNum()包括函数doAdd()(闭包)。内部函数是一个闭包,因为它将获取外部函数的参iNum1和iNum2以及全局变量iBaseNum的值。 addNum()的最后一步调用了doAdd(),把两个参数和全局变量相加,并返回它们的和。这里要掌握的重要概念是,doAdd()函数根本不接受参数,它使用的值是从执行环境中获取的,因此输出的结果为:30。
        可以看到,闭包是 ECMAScript 中非常强大多用的一部分,可用于执行复杂的计算。就像使用任何高级函数一样,使用闭包要小心,因为它们可能会变得非常复杂。

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
浅谈Javascript鼠标和滚轮事件
Jun 27 Javascript
javascript中attribute和property的区别详解
Jun 05 Javascript
jQuery实现的一个自定义Placeholder属性插件
Aug 11 Javascript
JSON字符串转JSON对象
Jul 31 Javascript
深入理解js中的加载事件
Feb 08 Javascript
JS中如何实现Laravel的route函数详解
Feb 12 Javascript
AngularJS路由切换实现方法分析
Mar 17 Javascript
ES6新特性之Object的变化分析
Mar 31 Javascript
详解使用React全家桶搭建一个后台管理系统
Nov 04 Javascript
echarts同一页面中四个图表切换的js数据交互方法示例
Jul 03 Javascript
在小程序中集成redux/immutable/thunk第三方库的方法
Aug 12 Javascript
js实现mp3录音通过websocket实时传送+简易波形图效果
Jun 12 Javascript
javascript定义类和类的实现实例详解
Dec 01 #Javascript
深入JavaScript高级程序设计之对象、数组(栈方法,队列方法,重排序方法,迭代方法)
Dec 01 #Javascript
js跨域请求数据的3种常用的方法
Dec 01 #Javascript
jQuery插件实现多级联动菜单效果
Dec 01 #Javascript
基于Jquery实现焦点图淡出淡入效果
Nov 30 #Javascript
轻松学习jQuery插件EasyUI EasyUI创建RSS Feed阅读器
Nov 30 #Javascript
轻松学习jQuery插件EasyUI EasyUI创建树形菜单
Nov 30 #Javascript
You might like
PHP中应该避免使用同名变量(拆分临时变量)
2015/04/03 PHP
php mysql数据库操作类(实例讲解)
2017/08/06 PHP
浅析PHP数据导出知识点
2018/02/17 PHP
用Javascript读取中文COOKIE的解决办法
2007/02/15 Javascript
EasySlider 基于jQuery功能强大简单易用的滑动门插件
2010/06/11 Javascript
字符串的replace方法应用浅析
2011/12/06 Javascript
js中eval详解
2012/03/30 Javascript
jQuery中prop()方法用法实例
2015/01/05 Javascript
JS组件中bootstrap multiselect两大组件较量
2016/01/26 Javascript
利用jQuery设计一个简单的web音乐播放器的实例分享
2016/03/08 Javascript
JavaScript闭包实例详解
2016/06/03 Javascript
jQuery判断是否存在滚动条的简单方法
2016/09/17 Javascript
JavaScript中的 attribute 和 jQuery中的 attr 方法浅析
2017/01/04 Javascript
js Date()日期函数浏览器兼容问题解决方法
2017/09/12 Javascript
手把手教你写一个微信小程序(推荐)
2018/10/17 Javascript
Vue+elementui 实现复杂表头和动态增加列的二维表格功能
2019/09/23 Javascript
vue自定义switch开关组件,实现样式可自行更改
2019/11/01 Javascript
Vue中函数防抖节流的理解及应用实现
2020/04/24 Javascript
python 解析XML python模块xml.dom解析xml实例代码
2014/02/07 Python
整理Python中的赋值运算符
2015/05/13 Python
flask入门之表单的实现
2018/07/18 Python
浅谈python3.6的tkinter运行问题
2019/02/22 Python
python3中rank函数的用法
2019/11/27 Python
Pyspark获取并处理RDD数据代码实例
2020/03/27 Python
如何用python处理excel表格
2020/06/09 Python
python使用scapy模块实现ping扫描的过程详解
2021/01/21 Python
css3旋转木马_动力节点Java学院整理
2017/07/12 HTML / CSS
利用 CSS3 实现的无缝轮播功能代码
2017/09/25 HTML / CSS
详解HTML5如何使用可选样式表为网站或应用添加黑暗模式
2020/04/07 HTML / CSS
德国圣伯纳德草药屋:Kräuterhaus Sanct Bernhard(有中文站)
2018/08/05 全球购物
Mio Skincare英国官网:身体紧致及孕期身体护理
2018/08/19 全球购物
蛋糕店的商业计划书范文
2014/01/27 职场文书
2014小学数学教研组工作总结
2014/12/06 职场文书
全国爱眼日活动总结
2015/02/27 职场文书
傲慢与偏见读书笔记
2015/06/29 职场文书
python scrapy简单模拟登录的代码分析
2021/07/21 Python