JavaScript之函数(上)
在编程语言中,无论是面向过程的C,兼备面过程和对象的c++,还是面向对象的编程语言,如java,.net,php等,函数均扮演着重要的角色。当然,在面向对象编程语言JavaScript中(严格来说,JS属于弱面向对象编程语言),函数(function)更扮演着极其重要的角色和占有极其重要的地位。在本篇文章中,不论述什么是JS,JS解决什么问题等之类问题,而是重点阐述JS中的函数(function)。
一 JavaScript函数
(一)何为函数
关于函数的定义,我们先从两个角度来思考:数学角度和编程语言角度。
1.数学角度:在数学领域,关于“函数”二字,再熟悉不过,如三角函数,反三角函数,幂函数,对数函数,指数函数,微积分函数等;
2.编程角度:在编程领域,大家最熟悉且最先接触的应该是"Main函数"了,除此外,如日期函数(Date),数学函数(Math)等,当然除了内置函数外,还包括用户自定义函数;
综合1,2点,可以将函数定义如下:
函数是解决某类问题的集合,是某类问题的高度抽象,它具有一定的通用性和复用性。
(二)定义函数
在Javascript中,存在三种经典的函数定义方式:函数声明式,函数表达式和函数构造式
1.函数声明式
//定义两个数相加函数
function AddNum(num1, num2) {
return num1 + num2;
}
注意:函数声明式,不能用匿名函数,如下方式定义错误的
function (num1, num2) {
return num1 + num2;
}
2.函数表达式
//定义两个数相加函数
var AddFun=function AddNum(num1, num2) {
return num1 + num2;
}
注意:函数表达式一般用匿名函数,因为调用时,不用函数名,因此,如上调用也可写成如下:
var AddFun = function(num1, num2) {
return num1 + num2;
}
3.函数构造式
var sum = new Function('num1', 'num2', 'return num1 + num2')
console.log(sum(10,20));//
(三)函数调用
在JavaScript中,函数的调用采用“函数名(参数)”的格式来进行调用。
需要注意的是,JavaScript函数调用与后端语言函数调用(如java,.net等)存在细微差别,即JavaScript没有函数重载,参数的参数个数,由实参决定,而不是由形参决定。
1.声明式调用
调用方式一:一般调用
//定义两个数相加函数
function AddNum(num1, num2) {
return num1 + num2;
} console.log(Add(10,20));//
调用方式二:自调用
(function AddNum(num1, num2) {
console.log(num1 + num2);
})(10,20);//
注意:自调用一般用匿名函数,因为在调用时,不需要函数名,因此,也可写成如下方式:
(function (num1, num2) {
return num1 + num2;
})(10, 20);//
2.表达式调用
//定义两个数相加函数
var AddFun = function (num1, num2){
return num1 + num2;
} console.log(AddFun(10, 20));//
二 函数变量
在JavaScript编程语言中,变量的定义是通过var关键字来定义的(若变量不通过var定义,则为全局变量,但不推荐这么做),与其他编程语言一样,变量也分为两大类,即局部变量和全局变量。
(1)局部变量:作用域为其所在的函数;
(2)全局变量:作用域为整个过程;
(3)变量作用域:JS中的变量作用域是通过this指针,从当前的作用域开始,从当前作用域由内向外查找,直到找到位置,这里分为几个逻辑:
a.从当前作用域由内向外查找,若找到,就停止查找,否则,继续查找,直到查到window全局作用域为止;
b.当内部作用域变量名与外部作用域变量名相同时,内部作用域的覆盖外部作用域。
我们来看一个例子:
var dateTime='2018-09-16';
function GetUserInfo(){
var age=120;
var name="Alan_beijing";
function Say(){
var name="老王";
var address="shanghai";
console.log(address+"-"+name+"-"+age+"-"+dateTime);//shanghai-老王-2018-06-05
}
return Say();
} GetUserInfo();//shanghai-老王-120-2018-09-16
来分析一下变量及其作用域:
如上图,有4个作用域,当函数执行如下语句时,发生如下过程:
console.log(address+"-"+name+"-"+age+"-"+dateTime);
a.js当前this环境作用域为4作用域;
b.this指针寻找变量:addresss,name,age,dateTime,从当前作用域向外作用域逐层寻找,直到寻找到变量为止,若寻找到最外层作用域任然没找到,则会出错,提示该变量未声明;
c.当内外层变量相同时,内层变量覆盖外层变量,如4作用域的name覆盖3作用域的name;
三 函数声明式定义存在的问题
在js中,存在声明提前问题,看看如下例子。
var globleName="Alan_beijing";
function Say(){
console.log(localName); // undefined,不报错,是因为变量声明提前
var localName="Alan";
console.log(localName);// Alan
}
看过如上代码,你可能会问,函数执行到console.log(localName); 时,应该报错,因为localName未定义。
如果在后端语言,如java,.net中,可能会报错,但是在js中,却不会,不报错的原因是:在js中存在声明提前。
如上代码相当于如下代码:
var globleName="Alan_beijing";
function Say(){
var localName;
console.log(localName);
localName="Alan";
console.log(localName);
}
四 函数几大关键点
1.匿名函数
匿名函数,顾名思义,就是没名字的的函数,我们来看看如下两个例子:
函数表达式
//定义两个数相加函数
var AddFun=function (num1, num2) {
return num1 + num2;
}
立即执行函数
(function AddNum(num1, num2) {
console.log(num1 + num2);
})(10,20);//
从如上,不难看出,匿名函数主要用域函数表达式和立即执行函数。
2.闭包
闭包的根源在于变量的作用域问题。
我们先来考虑这样一个问题,假设在面向对象编程语言中,某个方法的变量被定义为私有变量,其他函数要获取访问该变量,.net怎么处理?
方法一:构造函数
方法二:单例模式
同样地,在js中,同样存在外部函数调用内部函数变量问题,js运用的技术就叫做闭包。
所谓闭包,就是将不可访问的变量作为函数返回值的形式返回来,从而实现函数外部访问函数内部变量目的。
//闭包
function GetName() {
var name = "Alan_beijing";
var age = function () {
var age = 30;
return age;
}
return name + age;
}
3.js多态问题(重载问题)
在面向对象编程语言,如.net中,实现多态的方式大致有如下:
a.接口
b.抽象类
c.虚方法
d.方法重载
然而,在js中,没有面向对象之说(OO),那么js是如何实现多态的呢?根据方法实际传递的参数来决定。
//重载
function SetUserInfo(userName, age, address, tel, sex) {
console.log(arguments.length);//
} SetUserInfo('Alan_beijing',44,'china-shanghai','xxxx');
从如上可以看出,传递多少个参数,就接收多个参数,如果在现象对象编程语言中实现该功能,至少需要写一堆代码,这也是体现js强大之一。
4.递归
来看看一个递归阶乘函数
//递归
function factorial(num) {
if (num < 1) {
return 1;
} else {
return num * arguments.callee(num-1);
}
}
如果是.net,我们一般会这样写
//递归
function factorial(num) {
if (num < 1) {
return 1;
} else {
return num * factorial(num-1);
}
}
然而,这样写,却会存在异常情况
var factorial1 = factorial;
factorial = null;//将factorial变量设置为null
console.log(factorial1(4));//出错
5.原型和原型链
面向对象编程语言的显著特征之一是面向对象,然而,在js中,没有对象,那么js是如何面向对象的功能的呢(封装,继承,多态)?当然是通过原型和原型链来实现的。
大家都比较怕原型和原型链,其实很简单,它的功能相当于面向对象的继承,主要解决继承和复用。
介于篇幅有限,余下的内容,将在下篇文章阐述.....
五 参考文献
【01】JavaScript 高级程序设计(第三版) (美)Nicholas C.Zakas 著 李松峰 曹力 译
【02】JavaScript 权威指南 (第6版) David Flanagan 著
JavaScript之函数(上)的更多相关文章
- 把多个JavaScript函数绑定到onload事件处理函数上
为了让函数只在页面加载完毕后才得到执行,我们会把函数绑定到onload事件上: window.onload = userFunction 但如果有两个函数:firstFunction() 和 seco ...
- 理解 JavaScript 回调函数并使用
JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...
- 5种 JavaScript 调用函数的方法
一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下,许多那样的代码是我写的).JavaScript拥有函数式编程的特性 ...
- JavaScript调用函数的方法
摘要:这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助! 一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正 ...
- [转]javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")
javascript eval函数解析json数据时为什么 加上圆括号?为什么要 eval这里要添加 “("("+data+")");//”呢? 原因在于: ...
- javascript篇-----函数作用域,函数作用域链和声明提前
在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于 ...
- JavaScript 常用函数总结
javascript函数: ·常规函数 ·数组函数 ·日期函数 ·数学函数 ·字符串函数 .cookie函数 1.常规函数 javascript常规函数包括以下9个函数: (1)alert ...
- (转)Javascript匿名函数的写法、传参、递归
(原)http://www.veryhuo.com/a/view/37529.html (转)javascript匿名函数的写法.传参和递归 javascript匿名函数的写法.传参和递归 http: ...
- (转)javascript匿名函数的写法、传参和递归
(原)http://www.veryhuo.com/a/view/37529.html (转)javascript匿名函数的写法.传参和递归 http://www.veryhuo.com 2011-0 ...
随机推荐
- 实现ueditor的自动上传word中的……
UEditor的配置和使用(单独图片与文件上传) Word图片上传控件发布-Xproer.WordPaster ueditor 图片粘贴上传,实现图文粘贴,图片自动上传 打开工程: 文档的上传. 运行 ...
- jmeter+ant+jenkins接口自动化环境搭建
一.准备 1.安装jdk --->点击查看安装教程 2.安装jmeter ,官网下载jmeter解压,配置jmeter环境: JMETER_HOME (解压jdk路径) Path (;% ...
- prim算法和克鲁斯卡尔算法
Prim 设图G=(V,E)是一个具有n个顶点的连通网,其生成树的顶点集合为U.首先把v0放入U,再在所有的u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树,并把该边的v加入U集合 ...
- 在注册表中查看Windows10系统激活密钥的方法
1 2 3 4 5 6 7 分步阅读 百度经验:jingyan.baidu.com 激活Windows10系统(非自己使用激活密钥激活的系统)以后,我们不一定清楚激活密钥是什么.如果想查看自己电脑 ...
- 怎么取cxgrid某一列的合计值
怎么取cxgrid某一列的合计值 1.cxGrid1DBTableView1->optionsview->Footer 设为True 2.cxGrid1DBTableView1-> ...
- 架构(三)MongoDB安装配置以及集群搭建
一 安装 1.1 下载MongoDB 我个人不太喜欢用wget url, 之前出现过wget下载的包有问题的情况 https://fastdl.mongodb.org/linux/mongodb-li ...
- 关于 Block 中捕获 self 的分析
问题 最近遇到一个已经使用了weak-strong dance的block依旧强引用了self的情况,好在block没被VC持有只是延迟释放,但这里的关键是用了weak_self的blcok理应不会强 ...
- PYTHON黑帽编程 4.1 SNIFFER(嗅探器)之数据捕获--补充
荒废了一个多月了,重新捡起来,手生了不少.发现在<4.1下>的文章里没有 提到pcap库,实在是不应该. 在网络数据分析的工具中,tcpdump绝对是大名鼎鼎,tcpdump底层是libp ...
- 大叔学ML第三:多项式回归
目录 基本形式 小试牛刀 再试牛刀 调用类库 基本形式 上文中,大叔说道了线性回归,线性回归是个非常直观又简单的模型,但是很多时候,数据的分布并不是线性的,如: 如果我们想用高次多项式拟合上面的数据应 ...
- 1分钟快速制作漂亮的H5本地记事本
大家好,以前给大家分享过一个五步骤制作精美的HTML5时钟的文章,点击回顾<五步教你制作漂亮精致的HTML时钟>,还有<一分钟教你如何实现唯美的文字描边>:今天给大家分享一个用 ...