函数就是一组执行某些动作的一堆程序语句。一个函数可能有一些输入参数(在方法体内使用)并且执行完成之后返回一个值。
函数在JavaScript里面是对象,JavaScript里面几乎所有的东西都是对象。
作为一个对象,JavaScript的函数拥有属性和其他的函数(也就是方法)。
让我们来看一个Javascript中典型的函数定义。
函数可以有返回语句 return 这个语句是可选的。不过函数都会返回一个值,如果方法体中没有返回语句,那么方法会返回undefined(未定义)。
JavaScript 函数可以是匿名的,意思是说函数定义的时候你可以省略掉函数名。不过,函数必须被存储在一个变量里,像下面这样:
定义一个函数是以关键字 function 开头,后面跟着函数名然后括号里加入0个或多个参数)。 然后实际的函数代码(JavaScript程序语句)包含在一对大括号里 { }。
匿名函数
上面的语法也称为函数表达式。你可以把变量addNumbers当作函数名然后按照如下方式调用该函数。
函数表达式会很方便当你想要将一个函数作为参数传递给另一个函数时。让我们试着用一个简单的例子来理解这个。
我首先创建了两个匿名函数。第一个返回两个数的和,第二个返回两个数的积。这相当的简单,没有什么值得骄傲的。接着,我定义了一个函数calculate,它的第一个参数是函数类型,后面两个参数是数值类型。
我可以通过传递任何函数作为第一个参数来调用函数calculate
将函数通过参数形式传递是不是很简单。 这种方式在AJAX调用场景中被大量使用,比如你传入一个回调函数,当AJAX调用完成后用来处理成功或失败结果。
使用更多参数
JavaScript 在处理传递或接收函数参数时非常灵活。我们来看下操作”函数参数“的几种方式。
丢失的参数
调用一个函数可以传递比预期更多或更少的参数。如果你调用一个方法,少传递了一个参数,那么没传递的那个参数的值会被设为undefined。
参数对象
所有的Javascript函数都有一个特殊的对象 arguments 它是一个参数数组,在函数调用过程中被传递。 这个对象可以用来访问参数列表中的单独项,也可以获取参数传递至函数过程中的参数总个数。
这个函数假设没有参数传递进来,就像我说的,在Javascript函数调用中,你可以传递任意数量的参数。因此我也可以这样调用方法:
所有的参数都可以在 arguments 对象数组中找到, 可以使用 arguments.length 属性获取传递参数的个数。
默认参数
你是 C++ 或者 C# 程序猿吗? 你见过有默认参数的函数吗? 可能见过! ECMAScript 6 把这个特性加入了Javascript,因此你就可以定义一个默认参数的函数。
这个函数礼貌的向我的博客访问者问好,它接收一个 name 和 profession 参数,然后显示一条欢迎信息. 第二个参数接收一个默认值(如果没有传递或者传递了一个undefined)。
函数嵌套
一个函数内部可以包含内部函数. 内部函数又再次可以包含内部函数。来看下代码.
wakeUpAndCode 这个函数包含两个内部函数 wakeUp 和 code. 当调用 wakeUpAndCode 后, 开始执行方法体. 外部方法只有两条执行语句, 分别是对 wakeUp 和 code方法的调用 . 调用 wakeUp 函数会在控制台输出字符 “I just woke up” . 调用 code 函数会在控制台输出字符 “I am ready to code now” 。
内部函数可以访问所有外部函数的变量和参数。 但是内部函数是函数内一种私有类型的实现,它不能被它所在的函数之外的函数访问。
“ 自执行函数表达式 ” (IIFE, 读作"iffy" 好吧随你怎么叫)
IIFE (即时执行函数)是一个声明完成马上执行的匿名函数,它长这样:
你只需要创建一个匿名函数,在方法定义结尾处加一对圆括号,然后把所有的代码再通过圆括号括起来. 最外层的括号里会把所有内容转化成表达式,因为JavaScript的括号里不能写程序语句. 函数定义后面的一对括号可以让函数立即执行.
任何在自执行函数体内定义的变量都是局部有效的,并且不能被任何此作用域之外的代码访问或改变.
看下面的代码. 这个函数不需要被调用就会自动执行.
IIFE 是一个很好的在代码段中创建局部作用域的方法. 这么做的好处是可以保护你的变量和函数被应用程序中的其他部分复写掉。
构造函数
一个函数可以作为构造函数使用,并且可以使用构造函数来创建新的对象. 这个特性使Javascript更加面向对象. 使用构造函数的优势是你可以创建很多预定义对象和方法. 如果你把构造函数与其他语言的类和对象关联起来,那么你就对了。
我们来建立一个 Programmer 函数,它有函数构造器,并且有属性和方法. 你可以把它当作一个类如果你使用其他语言.
这个函数接收三个参数,并使用三个属性和四个方法来创建一个Programmer对象。上面的代码不用说了吧,很简单的。我可以使用下面的代码创建很多programmer对象。
当然也可以使用普通的字面语法来创建具有相同属性和方法的对象, 但我们要多次编写重复代码,这是一种很不好的编程实践。 如果你知道编程原则中的 DRY(Don't repeat yourself,不要重复造轮子?),你就会同意我的观点了。构造函数可以让你定义一次对象,然后再任何时候实例化他们.
注意!
要记得使用 new 关键字来创建新的函数对象。 如果你忘记使用 new 关键字创建了一个对象像这样
它会把所有的属性方法都添加的全局 window 对象中,这是非常可怕的。这就是为什么要明确使用 ‘this’ 关键字防止变量添加到全局 window 对象中。使用 new 设置当前上下文到刚刚创建的对象中。
不过, 有个方法可以解决这个问题 . 你可以改变你的构造函数的实现方式,让它的内容对象是范围安全的,然后再创建新对象, 那么你就可以愉快地忽略 new 关键字了。查看下面修改后的构造函数代码,已经移除了一些不必要的内容
if 条件判断当前的 this 对象是否是 Programmer 对象的一个实例。如果不是,就创建一个新的 Programmer 对象并且返回直接调用构造函数所调用的内容(指定this的指向并重新返回,有点递归的影子)。
注意:如果不使用 strict模式的话,这种方法就不能创建新对象。Strict模式将严格遵守执行标准,如果你编写一些不安全的代码,这么做会抛出异常。要启用 strict(严格) 方式, 只需要在代码前添加 ‘use strict’ 字符。 一般来讲,在代码中使用 strict 是比较好的。