f u n c t i o n N a m e ( a g r 0 , a r g 1 , a r g 2 ) { / / . . . } 二、函数表达式 v a r f u n c t i o n N a m e = f u n c t i o n ( a r g 0 , a r g 1 , a r g 2 ) { / / . . . } 这种形式是创建了一个 (有时也叫 )并将它赋值给变量 functionName 匿名函数 Lambda
) ; f u n c t i o n s a y H i ( ) { c o n s o l e . l o g ( " O K " ) ; } 不能这样写 s a y H i ( ) ; / / e r r o r 函数还不存在 v a r s a y H i = f u n c t i o n ( ) { c o n s o l e . l o g ( " O K " ) ; }
f a c t o r i a l ( n u m ) { i f ( n u m < = 1 ) { r e t u r n 1 ; } e l s e { r e t u r n n u m * f a c t o r i a l ( n u m - 1 ) ; } } 表面上看没什么问题,但是下面的代码会出错 v a r a n o t h e r F a c t o r i a l = f a c t o r i a l ; f a c t o r i a l = n u l l ; c o n s o l e . l o g ( a n o t h e r F a c t o r i a l ( 4 ) ) ; 以上代码把函数保存在变量 anotherFactorial 中,然后将 factorial 变量设置为 null,结果指向原始函数 的引用只剩下一个。而接下来调用 anotherFactorial() 时,由于必须执行 factorial(),所以就会报错
s . c a l l e e (一个指向正在执行的函数的指针) f u n c t i o n f a c t o r i a l ( n u m ) { i f ( n u m < = 1 ) { r e t u r n 1 ; } e l s e { r e t u r n n u m * a r g u m e n t s . c a l l e e ( n u m - 1 ) ; } } 但是在严格模式下( ),不能直接访问 arguments.callee ES5 strict mode 更好的做法,在严格和非严格模式都行得通 创建名为 f() 的命名函数表达式,即使把重新赋值 factorial,anotherFactorial 中函数名字 f 仍然有效 v a r f a c t o r i a l = ( f u n c t i o n f ( n u m ) { i f ( n u m < = 1 ) { r e t u r n 1 ; } e l s e { r e t u r n n u m * f ( n u m - 1 ) ; } } ) ;
n c r e a t e C o u n t F u n c t i o n ( n u m ) { r e t u r n f u n c t i o n ( ) { n u m + + ; c o n s o l e . l o g ( n u m ) ; } ; } / / 创建函数 v a r c o u n t _ a = c r e a t e C o u n t F u n c t i o n ( 0 ) ; v a r c o u n t _ b = c r e a t e C o u n t F u n c t i o n ( 1 0 ) ; / / 调用函数 f o r ( v a r i = 0 ; i < 3 ; i + + ) { c o u n t _ a ( ) ; c o u n t _ b ( ) ; }
r e a t e C o u n t F u n c t i o n ( n u m ) { r e t u r n f u n c t i o n ( ) { n u m + + ; / / 关键在这里,n u m 不是在内部定义的 / / 因此会将 c r e a t e C o u n t F u n c t i o n ( ) 函数的活动对象添加到它的作用域链中 / / 这样匿名函数就可以访问在 c r e a t e C o u n t F u n c t i o n ( ) 中定义的所有变量 c o n s o l e . l o g ( n u m ) ; } ; } v a r c o u n t _ a = c r e a t e C o u n t F u n c t i o n ( 0 ) ; v a r c o u n t _ b = c r e a t e C o u n t F u n c t i o n ( 1 0 ) ; f o r ( v a r i = 0 ; i < 3 ; i + + ) { c o u n t _ a ( ) ; / / 调用三次,输出保持了对同一个变量的引用,值会递增 n u m = > 1 , 2 , 3 c o u n t _ b ( ) ; } 内部匿名函数的作用域链中保持了对外部函数变量 num 的引用,在外部函数退出后,外部函数的活动 对象不会被销毁,仍然留在内存中,直到匿名函数被销毁 / / 解除对匿名函数的引用(以便释放内存) c o u n t _ a = n u l l ; c o u n t _ b = n u l l ;
i o n c r e a t e F u n c t i o n s ( ) { v a r r e s u l t = [ ] ; / / v a r r e s u l t = n e w A r r a y ( ) ; f o r ( v a r i = 0 ; i < 5 ; i + + ) { r e s u l t [ i ] = f u n c t i o n ( ) { c o n s o l e . l o g ( i ) ; } ; } r e t u r n r e s u l t ; } / / 创建函数数组 v a r f u n c t i o n L i s t = c r e a t e F u n c t i o n s ( ) ; / / 检查函数输出 f o r ( v a r i = 0 ; i < f u n c t i o n L i s t . l e n g t h ; i + + ) { f u n c t i o n L i s t [ i ] ( ) ; } 表面上看,返回的每个函数都应该返回自己的索引值,即索引值 0 的函数输出 0,以此类推 实际上每个函数都输出 5,每个函数的作用域链中都保存着 createFunctions() 函数的活动对象,它们引 用的都是同一个变量 i 当 createFunctions() 返回后,变量 i 的值是 5
o n c r e a t e F u n c t i o n s ( ) { v a r r e s u l t = [ ] ; / / v a r r e s u l t = n e w A r r a y ( ) ; f o r ( v a r i = 0 ; i < 5 ; i + + ) { r e s u l t [ i ] = f u n c t i o n ( n u m ) { r e t u r n f u n c t i o n ( ) { c o n s o l e . l o g ( n u m ) ; } ; } ( i ) ; } r e t u r n r e s u l t ; } v a r f u n c t i o n L i s t = c r e a t e F u n c t i o n s ( ) ; f o r ( v a r i = 0 ; i < f u n c t i o n L i s t . l e n g t h ; i + + ) { f u n c t i o n L i s t [ i ] ( ) ; } 在这个版本中,我们没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数 的结果赋值给数组。 匿名函数有一个参数 num,每次调用时传入了变量 i,由于参数是按照值传递的,所以 i 的当前值就复制 给了 num。 而在这个函数内部,又创建了一个访问 num 的闭包,这样一来,result 数组中的每个函数都有自己 num 变量的一个副本,可以输出不同的值
" g l o b a l " ; v a r o b j = { n a m e : " l o c a l " , g e t N a m e F u n c : f u n c t i o n ( ) { r e t u r n f u n c t i o n ( ) { r e t u r n t h i s . n a m e ; } } } c o n s o l e . l o g ( o b j . g e t N a m e F u n c ( ) ( ) ) ; / / " g l o b a l " this 对象是在运行时基于函数的执行环境绑定的:在全局函数中,this 等于 window 而当函数被作为某个对象的方法调用时,this 等于那个对象 匿名函数的执行环境具有全局性,因此其 this 通常指向 window 在通过 call() 或者 apply() 改变函数执行环境的情况下,this 就指向其他对象
= " g l o b a l " ; v a r o b j = { n a m e : " l o c a l " , g e t N a m e F u n c : f u n c t i o n ( ) { v a r t h a t = t h i s ; r e t u r n f u n c t i o n ( ) { r e t u r n t h a t . n a m e ; } } } c o n s o l e . l o g ( o b j . g e t N a m e F u n c ( ) ( ) ) ; / / " l o c a l " 在函数执行时,会自动获取两个特殊变量:this 和 arguments。 函数按照作用域链的顺序,首先在其活动对象搜索到了这两个变量,就停止往”上”搜索外部函数 先把 this 赋值给 that,闭包可以访问 that,that 也引用着 obj
e F u n c = f u n c t i o n ( ) { } ; s o m e F u n c < = = = = = > f u n c t i o n ( ) { } s o m e F u n c ( ) < = = = = = > f u n c t i o n ( ) { } ( ) / / 必须加上括号表示是一个函数表达式,而不是以关键字 f u n c t i o n 开头的函数声明 s o m e F u n c ( ) < = = = = = > ( f u n c t i o n ( ) { } ) ( ) ; 实例 ( f u n c t i o n ( ) { v a r n o w = n e w D a t e ( ) ; i f ( n o w . g e t M o n t h ( ) = = 0 & & n o w . g e t D a t e ( ) = = 1 ) { c o n s o l e . l o g ( " H a p p y n e w y e a r ! " ) ; } } ) ( ) ;
n M y O b j e c t ( ) { / / 私有变量和私有函数 v a r p r i v a t e V a r i a b l e = 1 0 ; f u n c t i o n p r i v a t e F u n c t i o n ( ) { r e t u r n f a l s e ; } / / 特权方法 t h i s . p u b l i c M e t h o d = f u n c t i o n ( ) { p r i v a t e V a r i a b l e + + ; r e t u r n p r i v a t e F u n c t i o n ( ) ; } }
在 Car 的每个实例中都不相同 f u n c t i o n C a r ( n a m e ) { / / 特权方法,外部只能通过它访问私有变量 n a m e t h i s . g e t N a m e = f u n c t i o n ( ) { r e t u r n n a m e ; } t h i s . s e t N a m e = f u n c t i o n ( v a l u e ) { n a m e = v a l u e ; } } v a r m y C a r = n e w C a r ( " B u m b l e b e e " ) ; m y C a r . g e t N a m e ( ) ; / / " B u m b l e b e e " m y C a r . s e t N a m e ( " I r o n h i d e " ) ; m y C a r . g e t N a m e ( ) ; / / " I r o n h i d e "
n ( ) { / / 私有变量和私有函数 v a r p r i v a t e V a r i a b l e = 1 0 ; f u n c t i o n p r i v a t e F u n c t i o n ( ) { r e t u r n f a l s e ; } / / 构造函数 M y O b j e c t = f u n c t i o n ( ) { } ; / / 公有/ 特权方法 M y O b j e c t . p r o t o t y p e . p u b l i c M e t h o d = f u n c t i o n ( ) { p r i v a t e V a r i a b l e + + ; r e t u r n p r i v a t e F u n c t i o n ( ) ; } } ) ( ) ; 公有方法是在原型(prototype)基础上定义的,体现了原型模式 MyObject 是全局变量,能在私有作用域之外被访问到 这个模式与在构造函数中定义特权方法的区别是私有变量和函数是由实例共享的。
o n ( ) { v a r n a m e = " " ; C a r = f u n c t i o n ( v a l u e ) { n a m e = v a l u e ; } ; C a r . p r o t o t y p e . g e t N a m e = f u n c t i o n ( ) { r e t u r n n a m e ; } ; C a r . p r o t o t y p e . s e t N a m e = f u n c t i o n ( v a l u e ) { n a m e = v a l u e ; } ; } ) ( ) ; v a r m y C a r = n e w C a r ( " B u m b l e b e e " ) ; m y C a r . g e t N a m e ( ) ; / / " B u m b l e b e e " m y C a r . s e t N a m e ( " I r o n h i d e " ) ; m y C a r . g e t N a m e ( ) ; / / " I r o n h i d e " v a r T o y = n e w C a r ( " O p t i m u s " ) ; t o y . g e t N a m e ( ) ; / / " O p t i m u s " m y C a r . g e t N a m e ( ) ; / / " O p t i m u s " toy 和 myCar 共享变量 name
u n c t i o n ( ) { / / 私有变量和函数 v a r a p p l i c a t i o n s = [ ] ; / / v a r a p p l i c a t i o n s = n e w A r r a y ; / / 初始化 a p p l i c a t i o n s . p u s h ( " b a s e " ) ; / / 公共 r e t u r n { g e t A p p l i c a t i o n s : f u n c t i o n ( ) { r e t u r n a p p l i c a t i o n s ; } , r e g i s t e r A p p l i c a t i o n : f u n c t i o n ( a p p ) { a p p l i c a t i o n s . p u s h ( a p p ) ; } } ; } ( ) ; c o p . g e t a p p l i c a t i o n s ( ) ; / / [ " b a s e " ] c o p . r e g i s t e r A p p l i c a t i o n ( " F C " ) ; c o p . g e t a p p l i c a t i o n s ( ) ; / / [ " b a s e " , " F C " ] 在 Web 应用中,经常需要使用一个单例来管理应用程序级的信息 例子中创建了一个用于管理应用的 cop 对象 applications 数组是私有变量,同时公开了 getApplications() 和 registerApplication() 两个方法用于查看 和注册新组件
P l a t f o r m ( ) { P l a t f o r m . p r o t o t y p e . c o m p a n y = " C h i n a C a c h e " ; } v a r c o p = f u n c t i o n ( ) { / / 私有变量和函数 v a r a p p l i c a t i o n s = [ ] ; / / v a r a p p l i c a t i o n s = n e w A r r a y ; / / 初始化 a p p l i c a t i o n s . p u s h ( " b a s e " ) ; / / 创建 c o p 的一个局部副本 v a r _ c o p = n e w P l a t f o r m ( ) ; / / 公共 _ c o p . g e t A p p l i c a t i o n s = f u n c t i o n ( ) { r e t u r n a p p l i c a t i o n s ; } ; _ c o p . r e g i s t e r A p p l i c a t i o n = f u n c t i o n ( a p p ) { a p p l i c a t i o n s . p u s h ( a p p ) ; } ; / / 返回这个副本 r e t u r n _ c o p ; } ( ) ; c o p . c o m p a n y ( ) ; / / " C h i n a C a c h e " c o p . g e t a p p l i c a t i o n s ( ) ; / / [ " b a s e " ] 在 Web 应用中,经常需要使用一个单例来管理应用程序级的信息 例子中创建了一个用于管理应用的 cop 对象 applications 数组是私有变量,同时公开了 getApplications() 和 registerApplication() 两个方法用于查看 和注册新组件