关键字function用来定义函数。定义函数有两种方法
函数声明语句通常出现在JavaScript代码的最顶层,也可以嵌套在其他函数体内。但在嵌套时,函数声明只能出现在所嵌套函数的顶部。也就是说函数定义不能出现在if语句、while语句后者其他语句中。
(1)都创建了相同的新函数对象
(2)函数声明语句中的函数名是一个变量名,变量指向函数对象。函数定义表达式并未声明一个变量,如果一个函数定义表达式包含名称,函数的局部作用域将会包含一个绑定到函数对象的名称。所以名称存在函数体中,并指代该函数本身,也就是说函数的名称将成为函数内部的一个局部变量。【注】函数定义表达式特别适合用来定义那些只会用到一次的函数
(3)函数声明语句中的函数被显式地“提前”到了脚本或函数顶部。因此它们在整个脚本和函数内都是可见的。但以函数表达式定义函数则不同,想要调用此定义的函数,必须要引用它,而要使用一个表达式方式定义的函数之前,必须要把他赋值给一个变量,前面说过:变量的声明提前了,但给变量赋值是不会提前的,所以,以表达式方式定义的函数在定义之前无法调用。如下代码:
【注】如果构造函数没有形参,JavaScript构造函数调用的语法是允许省略实参列表和圆括号的。所以凡是没有形参的构造函数调用都可以省略圆括号。
this是 一个关键字,不是变量,也不是属性名。JavaScript的语法不允许给this赋值。和变量不同,关键字this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this。对此我们用实例说明
综上所知:
(1)如果嵌套函数作为方法调用,其this的值指向调用它的对象。
(2)如果嵌套函数做为函数调用,其this值不是全局对象(非严格模式下)就是undefined(严格模式下)。
(3)如果想访问外部函数的this的值,需要将this的值保存在一个变量里,这个变量和内部函数都同在一个作用域内。通常使用变量self来保存this。
当有一段JavaScript模块代码,这段代码将要用在不同的JavaScript程序中(对于客户端JavaScript来讲通常是用在各种各样的网页中)。假如这段代码定义了一个用以存储中间计算结果的变量。如此就出现一个问题,当模块代码放在不同的程序中时,你无法得知这个变量是否已经建好,如果已经存在这个变量,那么将会和代码发生冲突。解决办法就是将代码放入一个函数内,然后调用这个函数。这样全局变量就变成了函数内的局部变量。用匿名函数来定义,用法如下
这种定义匿名函数并立即在单个表达式中调用它的写法很常见,如代码检测中是否出现了一个bug,如果出现这个bug,就返回一个带补丁的函数的版本!
length到没什么可说的,最主要是要属函数的arguments的属性了,在函数体内,arguments.length表示传入函数的实参的 个数,以此来模拟函数重载。请看下面代码
上述代码为求一个数的阶乘,毫无疑问没有错误。现在进行一点小改动,如下
上述很明显fact2变量指向两个函数,当要求调用fact2(5)时,先执行 第一个 factorial函数,当执行到 return x * factorial(x - 1); 时,这时执行的就是 第二个 factorial函数,所以此时打印出0。很显然这不是我们想要的结果,我们需要的是求阶乘即执行的函数接下来还是它本身也就是第一个,所以这个时候callee()方法就派上了用场:用于调用自身。所以上述代码这样修改即可
【注】arguments还有一个长得相似callee的属性就是caller,而在非严格模式下,ECMAScript标准规范规定callee属性指代当前正在执行的函数。caller是非标准的但大多数浏览器都 实现了这个属性,它指代当前正在执行的函数的函数。通过caller属性可以访问调用栈。而通过callee来进行递归调用自身,因为它保存了当前执行方法的地址,而不会出差错。
每个函数都包含一个prototype属性,这个属性指向一个对象的引用,这个对象叫做原型对象。每一个函数都包含不同的原型对象。当将函数用做构造函数的时候,新创建的对象会从原型对象上继承属性。有关原型对象前面已讲,请参考原型、继承这一讲
这两种方法可以用来间接地调用函数,两个方法都允许显式指定调用所需的this的值,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。两个方法都可以指定调用的实参。call()方法使用它自有的实参列表作为函数的实参,apply()方法则要求以数组的形式传入参数。在ECMAScript5的严格模式中,call()和apply()的第一个实参都会变为this的值,哪怕传入的实参是原始值甚至是null或undifined。在ECMAScript3和非严格模式中,传入的null和undefined都会被全局对象代替,而其他原始值则会被相应的包装对象所替代。
bind()是在ECMAScript5中新增的方法,但在ECMASript3中可以轻易模拟bind(),从名字可以看出,这个方法的主要作用就是将函数绑定至某个对象上。
上述将函数f绑定至对象o上,当在函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数。调用新的函数将会把原始的函数f()当做o的方法来调用。传入新函数的任何实参都将传入原始函数。上述中 f.bind(o); 则此时函数f()中的this即为o,此时this.x=1,绑定后返回新的函数g,再调用函数g(2),此时函数f()即为其参数,所以打印出3。
根据上述代码你觉得会打印出多少呢?我们一句一句分析:
同理进行分析