1、一条函数声明语句实际上声明了一个变量,并把一个函数对象赋值给它。
2、函数声明语句并非真正的语句,ECMAScript规范只是允许它们作为顶级语句。它们可以出现在全局代码里,或者内嵌在其他函数中,但它们不能出现在循环、条件判断,或者try/cache/finally以及with语句中。注意,此限制仅适用于以语句声明形式定义的函数。函数定义表达式可以出现在JavaScript代码的任何地方。
3、根据ECMAScript 3和非严格的ECMAScript5对函数调用的规定,调用上下文(this的值)是全局对象。然而,在严格模式下,调用上下文则是undefined。以函数形式调用的函数通常不使用this关键字。不过,“this”可以用来判断当前是否是严格模式。
//定义并调用一个函数来确定当前脚本运行时是否为严格模式
var strict = (function(){ return !this; }());
4、JavaScript,JScript,ECMAScript及对应浏览器的版本:
JavaScript | JScript | ECMAScript | Release date | Netscape Navigator | Firefox | IE | Opera | Safari | Chrome | ||
1.0 | 1.0 |
| March 1996 | 2.0 |
|
|
|
|
| ||
1.1 | 2.0 |
| August 1996 | 3.0 |
| 3.0- later versions, January 1997 |
|
|
| ||
1.2 |
|
| June 1997 |
|
|
|
|
|
| ||
1.3 | 3.0 | ECMA-262 1st edition/ ECMA-262 2nd edition | October 1998 | 4.06-4.7x |
| 4.0 -Oct 1997 |
|
|
| ||
1.4 | 4.0 |
|
|
|
|
|
|
|
| ||
| 5.0 |
| March 1999 |
|
| 5.0 |
|
|
| ||
| 5.1 |
|
|
|
| 5.01 |
|
|
| ||
1.5 | 5.5 | ECMA-262 3rd edition | November 2000 | 6.0 | 1.0 | 5.5-July 2000 | 6.0-11.0 | 3.0-5 | 1.0-10.0.666 | ||
| 5.6 | ECMA-262 3rd edition | October 2001 |
|
| 6.0 |
|
|
| ||
| 5.7 | ECMA-262 3rd edition + ECMA-327 (ES-CP) | November 2006 |
|
| 7 |
|
|
| ||
| 5.8 |
| March 2009 |
|
| 8 |
|
|
| ||
1.6 |
| 1.5 + Array extras + Array and String generics + E4X
| November 2005 |
|
|
|
|
|
| ||
1.7 |
| 1.6 + Pythonic generators + Iterators + let
| October 2006 |
| 2.0(Gecko 1.8.1) |
|
|
|
| ||
1.8 |
|
| June 2008 |
| 3.0(Gecko 1.9) |
|
|
|
| ||
1.8.1 |
|
|
|
| 3.5 |
|
|
|
| ||
1.8.2 |
| 1.8.1 + Minor updates | June 22, 2009 |
| 3.6 |
|
|
|
| ||
1.8.5 |
| 1.8.1 + ECMAScript 5 Compliance | July 27, 2010 |
| 4 | 9 |
|
|
| ||
2.0 (work in progress) |
| Harmony(work in progress) |
|
|
|
|
|
|
|
5、构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。然而如果构造函数显式地使用return有返回一个对象,那么调用表达式的值就是这个对象。如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。
6、可以接收任意个数的实参的函数称为“不定实参函数”(varargs function)。注意,不定实参函数的实参个数不能为零,arguments[]对象最适合的应用场景是在这样一类函数中,这类函数包含固定个数的命名和必需参数,以及随后个数不定的可选实参。
7、除了数组元素,实参对象还定义了callee和caller属性。在ECMAScript5严格模式中,对这两个属性的读写操作都会产生一个类型错误。而在非严格模式下,ECMAScript标准规范规定callee属性指代当前正在执行的函数。caller是非标准的,但大多数浏览器都实现了这个属性,它指代调用当前正在执行的函数的函数。通过caller属性可以访问调用栈。Callee属性在某些时候会非常有用,比如在匿名函数中通过callee来递归地调用自身。
var factorial = function(x){
if( x <= 1) return1;
return x *arguments.callee(x-1);
}
8、在函数中声明的变量在整个函数体内都是可见的(包括在嵌套的函数中),在函数的外部是不可见的。不在任何函数内声明的变量是全局变量,在整个JavaScript程序中都是可见的。在JavaScript中是无法声明只在一个代码块内可见的变量的,基于这个原因,我们常常简单地定义一个函数用做临时的命名空间,在这个命名空间内定义的变量都不会污染到全局命名空间。
function mymodule(){
//模块代码
//这个模块所使用的所有变量都是局部变量
//而不会污染全局命名空间
}
mymodule() //不要忘了还要调用这个函数
这段代码仅仅定义了一个单独的全局变量:名叫“mymodule”的函数。这样还是太麻烦,可以直接定义一个匿名函数,并在单个表达式中调用它:
(function(){ //mymodule()函数重写为匿名的函数表达式
//模块代码
}()); //结束函数定义并立即调用它
Function之前的左圆括号是必需的,因为如果不写这个左圆括号,JavaScript解释器会试图将关键字function解析为函数声明语句。使用圆括号JavaScript解释器才会正确地将其解析为函数定义表达式。
9、闭包是指函数变量可以被隐藏于作用域链之内,因此看起来是函数将变量“包裹”了起来。
10、函数定义时的作用域链到函数执行时依然有效。每次调用JavaScript函数的时候,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回的时候,就从作用域链中将这个绑定变量的对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当作垃圾回收掉。如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么它们也会和所指向的变量绑定对象一样当作垃圾回收。但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当作垃圾回收,并且它所指向的变量绑定对象也不会被当作垃圾回收。如果使用不慎,闭包很容易造成“循环引用”,当DOM对象和JavaScript对象之间存在循环引用时需要格外小心,在某些浏览器下会造成内存泄漏。
11、关于Function()构造函数有几点需要特别注意:
l Function()构造函数允许JavaScript在运行时动态地创建并编译函数。
l 每次调用Function()构造函数都会解析函数体,并创建新的函数对象。如果是在一个循环或者多次调用的函数中执行这个构造函数,执行效率会受影响。相比之下,循环中的嵌套函数和函数定义表达式则不会每次执行时都重新编译。
l 最后一点,也是关于Function()构造函数非常重要的一点,就是它所创建的函数并不是使用词法作用域,相反,函数体代码的编译总是会在顶层函数(也就是全局作用域)执行。
12、不完全函数是一种函数变换技巧,即把一次完整的函数调用拆成毒刺函数调用,每次传入的实参都是完整实参的一部分,每个拆分开的函数叫做不完全函数(partial function),每次函数调用叫做不完全调用(partial application),这种函数变换的特定是每次调用都返回一个函数,直到得到最终运行结果为止,举一个简单的例子,将对函数f(1,2,3,4,5,6)的调用修改为等价的f(1,2)(3,4)(5,6),后者包含三次调用,和每次调用相关的函数就是“不完全函数”。