Javascript 高级程序设计笔记 (cha7 匿名函数)
匿名函数就是没有名字的函数, 又叫拉姆达Lamda 函数。
回忆一下函数定义的两种形式 1function functionName(arg0, arg1, arg2){ //body}
2
var functionName = function(arg0, ,arg1){ //body};
区别是前者在代码执行前就会加载到作用域, 而后者则直到执行这行才会。 那么导致的现象是, 如果是后者那么就必须定义在前面, 调用在后面。
1 递归
下面是个简单的递归函数的例子 注意的一件事情, 用arguments.callee() 这样可以避免因为函数名字赋值改变导致的错误。 比如recur 可以赋值给另外一个, 然后recur =0; 这样另外一个名字其实是无法调用成功的。 因为函数内部和recur绑定了。
function recur(num){ if (num <0 || num == 0) return 1; else return num + arguments.callee(num-1);}alert(recur(6));
2 闭包
- 要解决什么问题
- 如何实现, 例子。
参考阮一峰的笔记, 觉得很有条理。
2.1 变量的作用域
变量的作用域, 无非两种, 一种是全局变量, 一种是局部变量。 javascript 语言的特殊的地方, 函数的内部是可以直接访问全局变量的。 - 对照java, java 肯定是不可以的, 只可以访问函数自己的, 不能访问外面的变量的, 除非是static 变量, 那都是可以的。
反过来, 从函数的外部是不能访问函数内部的变量的。 除非- 你使用的是全局变量, javascript 有一个特性就是如果在函数内部定义没有加var, 那么就会认为是一个全局变量, 显然函数内可以访问, 函数外也可以访问。
问题来了, 如何实现函数外部访问函数内部呢,
-》 可以考虑在函数内部的返回值中, 返回另外一个函数, 这个函数当然可以访问先前函数的变量。 那么你在全局访问这个函数, 也就实现了访问先前函数的变量这一目的。 看代码
function f1(){ var n=999; var n2=12; nAdd = function(){n++} function f2()( alert(n); ) return f2;}var result = f1();result(); //999nAdd();result(); //1000
2.2 闭包的定义
简单来说, 闭包就是函数内部可以访问到其他函数变量的函数。 本质上说, 这是将函数内部和外部链接起来的一座桥梁。
2.3 闭包的用途
两个主要用途, 一个是可以访问其他的函数变量, 第二个是可以把这些变量的值保存在内存里。 也就是说可以后面继续访问, 而不会直接释放掉。
同样是上面这个例子。 为什第二次等于1000了。
因为f2 被赋值给了result这个全局变量, 所以f2 需要存在内存里面, 而f2 是依赖于f1, 所以f1 也需要保存在内存里。 如同书上说的作用域就保存在内存里了。
2.4 可能的风险
首先, 既然内存保留这么多东西就会消耗比较多的内存。 这点要注意。 可以少用闭包, 或者把闭包牵扯到的函数作用域不需要的变量删除, 如何删除, 是置为空么?
其次, 闭包有可能暴露出去函数的set 方法, 这样就会修改父类函数中变量的值。
2.5 两个例子
var name ="The window";var object = { name: "My object", getNameFunc: function(){ return function(){ return this.name; } }}alert(object.getNameFunc()()); //THe window
var name ="The window";var object = { name: "My object", getNameFunc: function(){ var that = this; return function(){ return that.name; } }}alert(object.getNameFunc()());
3 模仿块级作用域
作用: 就是在函数外, 你如果定义了变量那就是全局变量, 很容易导致冲突。 而JS 又没有块级作用域,所以以下方式就是为了模拟块级作用域。
例子
(function(){ var now = new Date(); if(now.getMonth()==0 && now.gethour()==1){ alert("Today is year's first day. "); } var hi = "hi"; alert(hi); alert(now);})();
4 私有变量
如何构造私有变量呢
第一个 在构造函数里, 这里面只有publicFun才能访问其他两个私有变量。 原来构造函数中的这个方法如果没有this 是无法访问的呢。
function MyObject(){ var privateVar = 10; function privateFun(){ return false; } this.publicFun = function(){ privateVar++; return privateFun(); }}// not understand why var obj = new MyObject();// alert(obj.privateFun()); //error// alert(obj.privateVar); //erroralert(obj.publicFun());
第二个例子,
function Person(name){ this.setName = function(name){ value = name; } this.getName = function(){ return value; }}var person = new Person();person.setName("greg");alert(person.getName()); //gregperson.setName("roy");alert(person.getName()); //royvar person2 = new Person();person2.setName("lily");alert(person2.getName()); //lilyalert(person.getName()); //lily
奇怪的是, 为什么value 也没有定义或者声明就是可以用的而且是存在的 哈哈。 注意person person2 都是lily 就是说是share的一个,。 静态私有。 说错了, 这个其实不是共享的, 每个实例都是自己的, 自己刚才写的不对, 如下。
function Person(name){ this.setName = function(value){ name = value; } this.getName = function(){ return name; }}var person = new Person();person.setName("greg");alert(person.getName()); //gregperson.setName("roy");alert(person.getName()); //royvar person2 = new Person();person2.setName("lily");alert(person2.getName()); //lilyalert(person.getName()); //greg
以下例子是变量是共享的也就是static 变量;
要对比之前的例子, 这个呢因为原型增加了代码复用, 但是实例没有私有变量了。 前面那个则不同, 是有的。
(function(){ var name =""; Person = function(value){ name = value; }; Person.prototype.getName = function(){ return name; }; Person.prototype.setName = function(value){ name = value; } })();var person1 = new Person("Nick");alert(person1.getName());person1.setName("Greg");alert(person1.getName());var person2 = new Person("Lily");alert(person2.getName());alert(person1.getName());
5 模块模式
5.1 单例模式
单例模式, 是说只有一个实例的对象。 java中, 每次初始化都返回同一个对象就是单例, 作用是为了构造一个全局唯一的对象。
JS中的单例, 一般是以对象字面量来创建。 比如var singleton={ name: value; method: function(){ //method body }}
首先如果是全局变量自然到处是可以访问的, 然后唯一, 那这个调用没有构造函数, 哪里有别的地方可以调用呢, 所以就是唯一了。
5.2 增强
//not testvar singleton = function(){ var priviatevar = 10; function privateFunc(){ return false; } return { name: value, publicFunc: function(){ privateVariable++; return privateFunc(); } };}();
效果显然是一样的是一个对象字面量。 return的那个。 然后呢, 有些地方增强了, 比如有一个私有函数, 一个私有变量。
这种模式对单例进行初始化, 并且需要维护其私有变量比较有用。 比如下面的例子。
function BaseComponent(){}function OtherComponent(){}var application = function(){ var component = new Array(); //init component.push(new BaseComponent()); return { getComponentCount:function(){ return component.length; }, registration: function(object){ component.push(object); } };}(); // do not miss ();application.registration(new OtherComponent());alert(application.getComponentCount());
注意var 定义的分号不要漏了。
5.3 继续增强
单例是没有问题的, 只要函数字面量的初始化, 没有声明这个构造函数, 自然只有一个, 那么如果希望返回的这个单例还能从属于某个类型呢。 如下:
function BaseComponent(){}function OtherComponent(){}var application = function(){ var component = new Array(); //init component.push(new BaseComponent()); var object = new BaseComponent(); object.getComponentCount = function(){ return component.length; }; object.registration = function(obj){ component.push(obj); }; return object;}();alert(application instanceof BaseComponent); //trueapplication.registration(new OtherComponent());alert(application.getComponentCount());alert( typeof application == BaseComponent);//only object, is not specific. so it is false.
自己这里用错了, 应该是instanceof 而不是typeof。 typeof 是object string 等基本类型, 如果是对象具体类型应该用前者。