码迷,mamicode.com
首页 > 编程语言 > 详细

《javascript高级程序设计》笔记(七)

时间:2014-09-27 18:06:50      阅读:367      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   使用   ar   java   strong   

函数表达式

定义函数的方法:

函数声明:

function functionName(arg0, arg1, arg2){

     //函数体

}

Firefox、Safari、Chrome和Opera给函数定义了name属性,其值等于function关键字后面的标识符。

函数提升:执行代码前先读取函数声明。

 

使用函数表达式:

var functonName =  function (arg0, arg1, arg2){

     //函数体

}

创建的函数叫匿名函数,name属性为空字符串。

函数表达式在使用前必须先赋值。

一、递归

一个函数通过名字调用自身的情况下构成的。

            var anotherFactorial = factorial;
            factorial = null;
            alert(anotherFactorial(4));  //error!

 

调用anotherFactorial时,由于必须执行factorial,而factorial不是函数而出错。

 

arguements.callee是一个指向正在运行的函数的指针,可以用来实现对函数的递归调用。

严格模式下不能通过脚本访问arguements.callee,但可以通过命名函数表达式来实现。

二、闭包

闭包:有权访问另一个函数作用域里的变量的函数。

创建闭包最常见的方法是在一个函数内部再创建一个函数。

function compare(value1, value2){
       if  (value1 < value2){
           return  -1;
      }
       if  (value1 > value2){
           return  1;
      }
      else {
         return 0;
      }
}

 

当调用compare()时,会创建一个包含arguemnets,value1,value2的活动对象。后台的每个执行环境都有一个表示变量的对象——变量对象。全局环境的变量对象始终存在,compare()函数的局部环境的变量对象只在函执行的过程存在。创建compare()函数时,会预先创建一个包含全局变量对象的作用域链,它被保存在内部的[[Scope]]中。调用compare时,会为函数创建一个执行环境,通过复制函数的[[Scope]]属性的对象构建执行环境的作用域链。作用域链本质是一个指向变量对象的指针,只引用不实际包含变量对象。

bubuko.com,布布扣

 

 createComparisonFunction()函数在执行完毕以后,其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用它,匿名函数被销毁后, createComparisonFunction()的活动对象才会被销毁。

//创建函数
var compare = createComparisonFunction("name");
//调用函数
var result = compare({ name : "Nicholas"}, { name : "Greg"});
//解除对匿名函数的调用
compare = null;

 

 

 

bubuko.com,布布扣

1.闭包与变量

闭包只能取得包含函数中任意变量的最后一个值。闭包保存的是整个变量对象,

  function createFunctions(){
                var result = new Array();
                
                for (var i=0; i < 10; i++){
                    result[i] = function(){
                        return i;
                    };
                }
                
                return result;   
            }
            

 

每个函数的作用域链都保存着createFunctions()函数的活动对象,它们引用的是同一个变量i,当createFunction()函数返回时,变量i的值是10,每个函数都引用着保存变量i的同一个变量对象。

                for (var i=0; i < 10; i++){
                    result[i] = function(num){
                        return function(){
                            return num;
                        };
                    }(i);
                }

 

创建一个匿名函数,将立即执行该匿名函数的结果赋值给数组。由于函数参数按值传递,i变量的当值复制给num,在匿名函数内部又创建并返回一个访问num的闭包。

2.关于this对象

匿名函数的执行环境有全局性,其this对象通常指向window。

内部函数在搜索this和arguements时只会搜索到其活动对象为止,不可能直接访问外部函数的这两个变量。

 var name = "The Window";
        
        var object = {
            name : "My Object",
        
            getNameFunc : function(){
                return function(){
                    return this.name;
                };
            }
        };

 

 

把外部作用域的this对象保存在一个闭包能访问的变量里,就能让闭包访问该对象了。即使在函数返回后,that也引用着object。

getNameFunc : function(){
                    var that = this;
                    return function(){
                        return that.name;
                    };
                }

 

3.内存泄露

如果闭包的作用域链保存着一个HTML元素,该元素将无法销毁。

通过把element.id的一个副本存在一个变量,并且在闭包中引用该变量消除了循环引用。还有必要把element变量设置为null。

三、模仿块级作用域

在块语句中定义的变量是在包含函数中而非语句中创建的。

javascript中多次声明同一个变量,会对后续声明的视而不见。

私有作用域的匿名函数:

(function(){
      //块级作用域
})();

 

将函数声明包含在圆括号内,表示它实际是一个函数表达式,后面的另一对圆括号会立即调用这个函数。

 

function(){

}();   //出错

 

javascript把function关键字作为一个函数声明的开始,函数声明后面不能有圆括号。而函数表达式后面可以有圆括号。

只要临时要一些变量,就能使用私有作用域。

            function outputNumbers(count){
            
                (function () {
                    for (var i=0; i < count; i++){
                        alert(i);
                    }
                })();
                
                alert(i);   //出错
            }

 

 

在匿名函数定义的任何变量,在执行结束时被销毁。私有作用域能访问count是因为这个匿名函数是一个闭包,能访问包含作用域的所有变量。

这种技术经常用在全局作用域中被用在函数外部,限制向全局作用域添加过多变量和函数。

四、私有变量

任何在函数定义的变量,都可认为是私有变量。私有变量包括函数的参数、局部变量和函数内部定义的其他函数。

特权方法:有权访问私有变量和私有函数的公有方法。

在构造函数定义:

function MyObject() {

       //私有变量和私有函数
       var privateVariable = 10;
       
       function privateFunction() {
              return false;
       }

       //特权方法
       this.publicMethod = function () {
           privateVariable++;
           return privateFunction();
       }
}

 

特权方法作为闭包有权访问构造函数中的所有变量和函数。

 

            function Person(name){
            
                this.getName = function(){
                    return name;
                };
            
//特权方法
this.setName = function (value) { name = value; }; } var person = new Person("Nicholas"); alert(person.getName()); //"Nicholas" person.setName("Greg"); alert(person.getName()); //"Greg"

 

 

 

1.静态私有变量

通过私有作用域中定义私有变量或函数创建特权方法。

            (function(){
            
                var name = "";
                
                Person = function(value){                
                    name = value;                
                };
                
                Person.prototype.getName = function(){
                    return name;
                };
                
                Person.prototype.setName = function (value){
                    name = value;
                };
            })();

 

name成为静态的、由所有实例共享的属性。在一个实例上调用setName()会影响所有实例。创建一个Person实例或调用setName()都会赋予name实例一个新值。

2.模块模式

前面的模式用于自定义类型创建私有变量和特权方法的。

模块模式为单例创建私有变量和特权方法。

单例:只有一个实例的对象。

 

这种模式在需要对单例进行某些初始化,同时又需要维护其私有变量时是非常有用的。

            function BaseComponent(){
            }
            
            function OtherComponent(){
            }
        
            var application = function(){
            
                //私有变量和函数
                var components = new Array();
            
                //初始化
                components.push(new BaseComponent());
            
                //公共
                return {
                    getComponentCount : function(){
                        return components.length;
                    },
            
                    registerComponent : function(component){
                        if (typeof component == "object"){
                            components.push(component);
                        }
                    }
                };
            }();

            application.registerComponent(new OtherComponent());
            alert(application.getComponentCount());  //2

 

这里创建一个用来管理组件的对象。返回对象的getComponentCount方法和registerComponent方法都有权访问components的特权方法。

如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有变量数据的方法,可以用模块模式,这样创建的每个单例都是Object的实例,因为要用对象字面量来表示。

3.增强的模块模式

这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性和(或)方法对其加以增强的情况。

            var application = function(){
            
                //私有变量和函数
                var components = new Array();
            
                //初始化
                components.push(new BaseComponent());
            
                //创建application的一个局部副本
                var app = new BaseComponent();
            
                //公共接口
                app.getComponentCount = function(){
                    return components.length;
                };
            
                app.registerComponent = function(component){
                    if (typeof component == "object"){
                        components.push(component);
                    }
                };
            
                //返回这个副本
                return app;
            }();

 

《javascript高级程序设计》笔记(七)

标签:style   blog   http   color   io   使用   ar   java   strong   

原文地址:http://www.cnblogs.com/surahe/p/3994214.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!