概述
JavaScript函数是参数化的:函数的定义会包括一个称为形參的标识符列表,这些参数在函数题中像局部变量一样工作。
除了实参,每次调用还会拥有另一个值——本次调用的上下文——这就是this关键字的值
如果函数挂载载一个对象上,作为对象的一个属性,那就称它为对象的方法。当通过这个对象来调用函数时,该对象就是此次调用的上下文,也就是该函数的this值。用于初始化一个新创建的对象的函数称为构造函数
在JavaScript里,函数即对象,程序可以随意操控它们。
JavaScript的函数可以嵌套在其它函数中定义,这样它们就可以访问它们被定义时所处的所用于中的任何变量。这件意味着JavaScript构成一个闭包。
函数定义
函数使用function关键字来定义,他可以用在函数定义表达式或者函数声明语句。
函数表达式可以包含名称,这在递归地时候非常有效
var f = function fact(x) {
if(x<=1) return 1;
else retyrb x*fact(x-1);
}
以表达式方式定义的函数,函数名是可选的。
函数名称通常是动词或以动词为全追的数组。
有一些函数是用作内部函数或私有函数,这种函数通常以一条下划线为前缀。
函数声明式的函数可以在定义前调用,而函数定义表达式型的不可以。
没有返回值的函数有时候被称为过程
函数声明语句并非真正的语句,但ES规范允许它们作为顶级语句。它们可以出现在全局代码或其它函数中,但不能出现在循环、条件判断等语句中。该限制仅适用于以语句声明形式定义的函数。函数定义表达式可以出现在JavaScript代码的任何地方
函数调用
根据ES3和非严格的ES55函数调用规定,调用的上下文(this)是全局变量,但是在严格模式下,上下文为undefined
一个方法无非是个博存在一个对象的属性里的JavaScript函数。
函数表达式本身就是一个属性访问表达式,这意味着该函数被当作一个方法,而不是普通函数来调用
任何函数只要作为方法调用实际上都会传入一个隐式的实参——这个实参是一个对象,方法调用的母体就是这个对象。
当方法并不需要返回值时,最好直接返回this。如果在设计的API中一致采用这种方式(每个方法都返回this),使用API就可以进行链式调用风格的编程。
this是一个关键字,不是变量,不是属性名——JavaScript语法不允许给this赋值
和变量不同,关键字this没有作用域限制,嵌套的函数不会从嗲用它的函数中继承this。嵌套函数作为函数调用,其this不是全局对象就是undefined。如果想访问外部的this,需要保存到一个变量
如果函数或者方法之前带有关键字new,那么久构成构造函数调用。
若构造函数无形參,JavaScript构造函数调用的语法是允许省略实参列表和圆括号的。
构造函数调用创建一个新的空对象,这个对象继承自构造函数的prototype属性。构造函数试图初始化这个新创建的对象,并将这个对象用作其调用上下文,因此构造函数可以使用this关键字来引用这个新创建的对象。
构造函数通常不使用return关键字。如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。如果构造函数使用return语句但没有制定返回值,或者返回一个原始值,那么这时会将忽略返回值,同时使用这个新对象作为调用结果。
call()方法使用它自有的实参列表作为函数实参,apply()方法则要求参数以数组形式传入
函数的实参和形參
JavaScript中的函数定义并未制定函数形參类型,函数调用也未对传入的实参值做任何类型检查。实际上,JavaScript函数调用伸直不检查传入参数的个数。
可选实参应当放在实参列表的最后。当前面的实参修养掉过时,可以传进一个null作为占位符。
当调用函数的时候传入实参个数超过了定义函数时形參的个鹅湖上,没有办法直接获得未命名值的引用。arguments时指向实参对象的引用,而实参对象时一个类数组对象
这种函数可以接受任意个数的实参,被称为“不定实参函数”
不定实参函数的实参个数不能为0,arguments[]读写嘴适合的应用场景时在这样一类函数中,这类函数包括固定个数的命名和必须参数,以及随后个数不定的可选实参
在非严格模式下,当一个函数包含若干形參,实参对象的数组元素时函数形參所对应实参的别名,可以通过arguments进行修改
在非严格模式下,函数里的argumens仅仅是一个标识符,在严格模式下,变成了一个保留字。严格模式下无法使用arguments作为形參名或局部变量名,也不能给arguments赋值
在ES5严格模式下,对于callee和caller属性的读写操作都会产生类型错误。在非严格模式下,callee属性指代当前正在执行的函数
除非函数时一个只用一到两次,否则赢得添加实参类型检查逻辑,因为宁愿程序自传入非法值时报错,也不愿非法值导致程序执行时报错。
作为值的函数
在JavaScript中,函数不仅是一种语法,也是值。所以可以将函数复制给变量,存储在对象的属性火数组元素中,作为参数传入另一个参数。
当函数作为对象属性调用的时候,函数就被称为方法
当函数需要一个静态变量来在调用时保持某个值不变,最方便的方式就是给函数定义属性,而不是定义全局变量
uniqueInteger.couter = 0;
function uniqueInteger() {
return uniqueInteger.counter++;
}
P180有非常好的例子
作为命名空间的函数
在函数中声明的变量在整个函数题哪都是可见的(包括在其嵌套的函数内),在函数外部不可见。任何不在函数内声明的变量都是全局变量,在整个JavaScript程序中都是可见的。所以经常定义一个函数来作为临时的命名空间,避免变量污染全局空间
闭包
JavaScript也采用词法作用域,也就是说,函数的执行依赖于变量作用域买这个作用域是在函数定义是决定的,而不是在函数调用时决定的。
当一个函数嵌套了另外一个函数,外部函数将嵌套的函数对象作为返回值返回的时候往往会导致调用函数时闭包锁指向的作用域链和定义函数时的作用域链不一样,这就是闭包
闭包可以捕捉到局部变量(和参数),并一直保存下来,这样看起来就像这些变量绑定到了在其中定义它们的外部函数。
每次调用JavaScript函数的时候,都会为止创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回的时候,就从作用域链中将这个绑定变量的对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定会被删除。但如果函数定义了嵌套函数,并将它作为返回值返回或存储在某处的属性里,这是就会有一个外部引用指向这个嵌套的函数,他就不会被当成垃圾回收,并且他所知晓的变量绑定对象也不会被当作垃圾回收。
P185
不要将for循环移到定义闭包的函数内
关联到闭包的作用域链都是活动的,嵌套函数不会将作用域内的私有成员复制一份,也不会对所绑定的变量生成静态快照
每个函数调用都包含一个this值,如果闭包在外部函数里时无法访问this,除非外部函数将this转存为一个变量
绑定arguments的问题与之类似。arguments并不是一个关键字,但在调用每个函数都会自动升, ,由于闭包具有自己的arguments,所以闭包内无法直接访问外部的arguments
函数属性、方法和构造函数
每一个函数都包含不同的原型对象。当将函数用作构造函数的时候,新创建的对象会从原型对象上继承属性
在ES5点严格模式中,call()和apply()的第一个实参会变成this,哪怕传入的是null或undefined,而在非严格模式下,null和undefined会变为全局对象
传入apply()的参数数组可以是类数组对象也可以是真实数组
Function()构造函数创建的函数并非使用词法作用域。