深入理解 JavaScript 中的函数
JavaScript函数也具有这些特性,但它们不仅仅是常规函数。JavaScript函数是对象。你可以查看我曾经写的关于JavaScript对象的文章,里面我提到几乎JavaScript中的所有一切都是对象。
作为对象,JavaScript函数可能会有属性和其他函数(方法)。让我们来看看JavaScript中的一个典型的函数定义。
function myNotSoGreatFunc(visitor) {
console.log("Welcome to Code Morning Mr. " + visitor);
}
没错。上面的函数不涉及什么宏伟大业,因为它仅是对博客访问者表示了欢迎。但它展示了JavaScript函数的样子。函数定义从关键字function
开始,然后是函数名,空的或有参数的括号。实际的函数代码(JavaScript语句)被封装在一对花括号内{ }。对于函数而言,return
语句是可选的。JavaScript函数总是会返回一个值。当function
主体中没有return
语句时,那么function
返回undefined。
下面的代码调用传递visitor name作为参数的函数。
myNotSoGreatFunc("Bob Martin");
// Output:
// Welcome to Code Morning Mr. Bob Martin.
到现在为止,我们了解了函数非常基本的特征。现在,我们将对JavaScript函数的一些高级概念一探究竟。
匿名函数
JavaScript函数可以是匿名的。这意味着你可以从函数声明中省略函数名。但是,函数必须存储在变量中。
var addNumbers = function (x, y) { return x + y; }
上述语法被也被称为函数表达式。你可以把变量addNumbers
当作函数名,以及像下面这样调用该函数。
var sum = addNumbers(2, 3);
当你想传递一个函数作为参数给另一个函数时,函数表达式就非常方便了。让我们用一个简单的例子来试着了解这一点。
var add = function (first, second) { return first + second };
var multiply = function (first, second) { return first * second }; function calculate(fun, a, b) {
return fun(a, b);
}
首先我已经创建了两个匿名函数。第一个返回两个数的加法运算,第二个返回两个数的乘法运算。相当简单,没有什么可值得炫耀的地方。然后,我定义函数calculate
,这个函数接受函数作为第一个参数后跟两个参数接受两个数字。
我可以通过传递任意函数作为第一个参数来调用函数calculate。
var sum = calculate(add, 2, 3); // sum = 5
var multiplication = calculate(multiply, 2, 3); // multiplication = 6
你可以看到将函数作为参数传递是多么容易。这种模式在AJAX中大量使用,当你在AJAX调用完成后,传递回调函数处理成功或失败的场景时。
关于参数的更多内容
JavaScript是非常灵活的,当涉及到传递或访问函数参数的时候。让我们看一下函数参数可以被操纵的方式。
缺少参数
调用函数时,函数的参数数量可以比要求的更少或更多。如果你调用的函数的参数比声明的少,那么缺少的参数被设置为undefined。
function callMe(a, b, c) {
console.log("c is " + typeof c);
} callMe("Code", "Morning");
// Output: "c is undefined"
callMe("Learn", "JavaScript", "Functions");
// Output: "c is string"
Arguments对象
所有的JavaScript函数有一个特殊的对象,叫做arguments
,它是在函数调用过程中传递的参数数组。该对象可以被用来访问单个参数或获得传递到函数的参数总数。
function callMe() {
var i;
for (i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
console.log("Total arguments passed: " + arguments.length);
}
此函数假设没有传递任何参数,但就像我说的,你可以传递任何数量的参数到JavaScript函数。我可以像这样调用这个函数:
callMe("Code", "Morning", "Mr. Programmer");
// Output":
// Code
// Morning
// Mr. Programmer
// Total arguments passed: 3
每个参数可以从arguments
对象作为一个数组项被访问。被传递给函数的arguments
的总数可从arguments.length属性获得。
默认参数
你是C ++或C#程序员吗?你见过使用默认参数的函数吗?也许你会回答yes! ECMAScript 6带来了JavaScript的这一特性,就是你可以定义带有默认参数的函数。
function greetMyVisitors(name, profession = "The cool programmer") {
alert("Welcome Mr. " + name + ", " + profession);
}
该函数有礼貌地地迎接了博客访问者。它有两个参数name
和profession
,并在消息框中显示一个欢迎消息。如果在调用过程中没有参数(或“undefined”)传递,那么第二个参数取用默认值。
greetMyVisitors("Justin Bieber", "The singer");
// Shows the message "Welcome Mr. Justin Bieber, The singer" greetMyVisitors("Bob Martin");
// Shows the message "Welcome Mr. Bob Martin, The cool programmer" greetMyVisitors("John Papa", undefined);
// Shows the message "Welcome Mr. John Papa, The cool programmer"
嵌套函数
函数可以在它的内部包含一个或多个函数。内部函数可能会在内部再次包含函数。让我们来看看以下操作。
function wakeUpAndCode() {
function wakeUp() {
console.log("I just woke up");
} function code() {
console.log("I am ready to code now");
} wakeUp();
code();
} wakeUpAndCode(); // Output:
// I just woke up
// I am ready to code now
函数wakeUpAndCode
包含两个内部函数wakeUp
和code。当调用wakeUpAndCode时,函数主体开始执行函数主体。在外部函数中只有两个可执行语句,调用wakeUp
和code
的方法。调用wakeUp
将执行内部wakeUp
函数,这将写入string
“I just woke up”到控制台。调用code
将会写入“I am ready to code now”string
到控制台。
内部函数可以访问所有外部函数的变量和参数。内部函数是函数内部某种private
实现,并且不能从外部函数以外被调用。内部函数的使用生成了JavaScript闭包,这个我将另起一篇文章讨论。
立即执行函数表达式(IIFE,发音iffy)
IIFE是被立即调用执行的匿名函数表达式。IIFE看上去像这样:
(function() {
// Your awesome code here
}());
所有你要做的就是创建一个匿名函数,在函数定义后马上放一对圆括号以调用函数,最后将所有代码封装在另一对圆括号中。最外层的括号将它里面的所有一切转变成一个表达式,因为括号不能包含JavaScript语句。函数定义后面的圆括号则立即调用函数。
IIFE块中定义的任何变量或函数对块而言是本地的,并且不能被这个范围以外的任何代码改变。
看看IIFE的这个例子。此函数没有调用也会自动执行。
(function() {
console.log("I run on my own.");
}());
只需在plunker中复制并粘贴代码,看看在浏览器控制台中的输出。如果你不知道去哪里找浏览器控制台,那么只要在浏览器窗口中按下F12就会出现开发者工具。跳转console选项卡以查看console.log语句的所有输出。
IIFE是一个在代码中创建局部范围的很好方法。它们可以帮助你保护变量和函数,以避免被应用程序的其他部分更改或覆盖。JavaScript中IIFE的其他优势?它们是如何解决全局范围污染问题的?欢迎点击查看我关于立即执行函数表达式的文章。
构造函数
函数可以充当构造器的角色,并且可以使用构造函数来创建新的对象。这是使JavaScript面向对象的特点之一。使用构造函数的好处是,你将能够通过预定义的属性和方法,创造尽可能多的对象。如果你由此关联到其他语言中的类和对象,那么你做的对。
让我们创建一个带有一些属性和方法的构造函数Programmer
。你可以假设它在你最喜欢的语言中是一个类。
function Programmer(name, company, expertise) {
this.name = name;
this.company = company;
this.expertise = expertise; this.writeCode = function() {
console.log("Writing some public static thing..");
} this.makeSkypeCall = function() {
console.log("Making skype call..");
} this.doSalsa = function() {
console.log("I'm a programmer, I can only do Gangnam style..");
} this.canWriteJavaScript = function() {
return expertise === "JavaScript";
}
}
函数有三个参数,并创建了一个具有三个属性和四种方法的对象。我不认为上面的代码需要任何解释。此外,我可以创建任意数量程序员对象。
var javaProgrammer = new Programmer("Mohit Srivastava", "Infosys", "Java");
var dotnetProgrammer = new Programmer("Atul Mishra", "Prowareness", ".NET");
虽然也可以创建一个使用对象文本语法带有相同属性和方法的对象,但我们需要多次编写相同的代码,这可不是什么伟大的实践。如果你知道编程DRY原则,那么你就不会不赞同我。构造函数使得可以一次定义对象,并创建真正的实例,无论什么时候你想要。
警告!
始终使用new关键字来从构造器创建新的对象。忘记了new
而像这个创建一个实例->
var jsProgrammer = Programmer("Douglas Crockford", "Yahoo", "JavaScript")
最终将添加所有属性和方法到全局的window
对象,哇哦,这将是太可怕了。原因是,除非明确指定,否则“this”指向全局的window
对象。使用new
设置“this”上下文到被创建的当前对象。
然而,有一种变通方法可以来克服这个问题。你可以改变构造函数的实现以使域安全,然后在创建新的对象时,你就可以愉快地忽略new
关键字了。请参见以下修改了的构造函数代码。为了便于查看,我已删除了一些方法。
function Programmer(name, company, expertise) {
if(!(this instanceof Programmer)) {
return new Programmer(name, company, expertise);
} this.name = name;
this.company = company;
this.expertise = expertise; this.writeCode = function() {
console.log("Writing some public static thing..");
}
}
if
条件检查了this
对象是否是Programmer的一个实例。如果不是,它会创建一个新的Programmer
对象,并通过再次调用构造器返回相同的内容。
注意:你无法在不使用’new’关键字的情况下,在Strict
模式下从构造器创建一个新的对象。Strict
模式强制一些编码准则,并且在你写的东西不安全的情况下会抛出错误。要启用Strict
模式,你只需要添加在你的代码开头添加字符串 ‘use strict
’。在Strict模式下运行代码是一个良好的实践。
'use strict'
function doSomething() { ... }
....
....
在这篇文章中,我几乎已经涵盖了有关函数的所有内容。函数被认为是JavaScript中的一等公民。理解函数可能是最重要的事情,如果你想掌握JavaScript的话。
欢迎各位指正。
深入理解 JavaScript 中的函数的更多相关文章
- 如何理解JavaScript中的函数
转: 如何理解JavaScript中的函数 JS中的函数简介 JS中的函数是一种通过调用来完成具体业务的一段代码块.最核心的目的是将可重复执行的操作进行封装,然后供调用方无限制的调用. JS中的函数的 ...
- 深入理解JavaScript中的函数操作——《JavaScript忍者秘籍》总结
匿名函数 对于什么是匿名函数,这里就不做过多介绍了.我们需要知道的是,对于JavaScript而言,匿名函数是一个很重要且具有逻辑性的特性.通常,匿名函数的使用情况是:创建一个供以后使用的函数.简单的 ...
- 如何理解Javascript中的函数(Function)
Function类型 首先得知道,每个函数都是Function类型的实例,所以函数本身是对象. 示例1: function sum (num1, num2){ return sum1 + sum2; ...
- 深入理解javascript中的立即执行函数(function(){…})()
投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...
- 理解javascript中的回调函数(callback)【转】
在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...
- 深入理解javascript中的立即执行函数
这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包住业务代码,使用jquery时比较常见,需要的朋友可以 ...
- 理解JavaScript中的回调函数
理解回调函数,首先要知道在JavaScript中,函数也是对象,它可以赋值给变量,也可以作为参数传递给另一个函数.比如: var add=function(a,b){ console.log(a+b) ...
- 深入理解JavaScript中创建对象模式的演变(原型)
深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...
- 深入理解JavaScript中的属性和特性
深入理解JavaScript中的属性和特性 JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaSc ...
随机推荐
- OpenID 配置步骤
允许客户端基于授权服务器执行的身份验证来验证最终用户的身份,以及以可互操作和类似REST的方式获取关于最终用户的基本配置文件信息. 创建一个MVC客户端 1.新建一个ASP.NET Core MVC应 ...
- 位图(bitmap)—— C语言实现
高级数据结构及应用 -- 使用 bitmap 进行字符串去重 位图应当具备的置一,清零,以及判断三大功能: #define BITS_PER_WORD 32 #define MASK 0x1f #de ...
- 机器学习: K-means 聚类
今天介绍机器学习里常见的一种无监督聚类算法,K-means.我们先来考虑在一个高维空间的一组数据集,S={x1,x2,...,xN}" role="presentation&quo ...
- JavaScript Dom基础-9-Dom查找方法; 设置DOM元素的样式; innerHTML属性的应用; className属性的应用; DOM元素上添加删除获取属性;
JavaScript Dom基础 学习目标 1.掌握基本的Dom查找方法 domcument.getElementById() Domcument.getElementBy TagName() 2.掌 ...
- Python之路,第二十篇:Python入门与基础20
python3 面向对象4 supper 函数 supper(type, obj) 返回绑定超类的实例(要求obj必须为type类型的实例) supper() 返回绑定的超类的实例,等同于(cl ...
- centos7 启动mysql
密码无法登录问题: 在my.cnf 中加一句 skip-grant-tables : 重启mysql服务: mysql -uroot -p: USE mysql ; 进入后,修改密码 .UPDA ...
- java-方法重写和方法重载的区别
1.方法重载: - 英文:Overload - 可以改变返回值类型,只看参数列表. - 本类中出现的方法名一样,参数列表不同的方法,与返回值类型无关. 2.方法重写: - 英文:Override - ...
- Linux下安装Blender
Blender在Windows下,可以在官方直接下载免安装的版本,下载解压缩就能用. 在Linux下稍微麻烦一点点. 如下3步安装的blender不一定是最新版本,且安装完成后发现设置中文会变为方块. ...
- (16)模型层Models - ORM的使用
需求:通过orm创建user表 先配置settings文件夹 连接数据库和配置数据库 Django的模块有两种 1.mysqlDB django内置的模块,只能在python2.X版本下用 2.py ...
- AC自动机自我理解和模板
给出长度为m的文本 查询 n个单词出现的次数 用kmp 复杂度 n*m*(单词平均长度) 用字典树 复杂度 m*每次字典树遍历的平均深度) AC自动机 复杂度 m (思路可以理解为kmp+字典树 ) ...