js高级程序设计笔记4--函数表达式及闭包
来源:互联网 发布:my sql条件触发器 编辑:程序博客网 时间:2024/05/28 04:54
函数表达式
函数声明的一个重要特性就是函数声明提升,即在执行代码之前会先读取函数声明。
函数表达式:
语法形式
var functionName = function(arg0,arg1,arg2){ //函数体}
函数表达式在使用之前必须先赋值。
sayHi();//错误,函数体不存在var sayHi = function(){ alert("Hi!");}
递归
function factorial(num){ if(num<=1) return 1; else return num * factorial(num-1);}var anotherfac = factorial;factorial = null;alert(antoherfac(4));//出错
arguments.callee是一个指向正在执行的函数的指针。因此可以用它来解决问题。(严格模式下不能通过脚本访问arguments.callee)
function factorial(num){ if(num<=1) return 1; else return num * arguments.callee(num-1);}
也可以使用命名函数来解决。
var facorial = (function f(num){ if(num<=1) return 1; else return num * f(num-1);});
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数。
但某个函数第一次被调用时,会创建一个执行环境(execution context)及相应的作用域链,并把作用域链赋值给一个特殊的内部属性([Scope])。然后this,arguments和其他命名参数的值来初始化函数的活动对象(activation object)。但在作用域链中,外部函数的活动对象始终处于第二位。以此类推直至作为作用域链终点的>全局执行环境。
后台的每个执行环境都有一个表示变量的对象—变量对象,全局环境的变量对象始终存在,而局部环境的变量对象只在函数执行的过程中存在。(闭包的情况不同)
作用域链本质上是一个指向变量对象的指针列表。它只引用但不实际包含变量对象。
在另一个函数内部定义的函数将包含函数(即外部函数)的活动对象添加到它的作用域链中。
注:由于闭包会携带包含它的函数打的作用域链,因此会比其它函数占用更多的内存。过度使用可能导致内存占用过多。
闭包只能取得包含函数中任何变量的最后一个值。
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(){ return i; }; } return result; }
结果是每个函数都会返回10.因为他们引用的都是同一个变量i,函数返回时i的值是10.可以通过创建另一个匿名函数强制让闭包的行为符合预期。
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(num){ return function(){ return num; }; }(i); } return result; }
匿名函数的执行环境具有全局环境,其this对象指向window。
var name = "windows";var object = { name:"my object", getNameFunc:function(){ return function(){ return this.name; }; }}alert(object.getNameFunc()());//windows(非严格模式下)
每个函数再被调用时,其活动对象都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时只会搜索到其活动对象为止,因此永远不可能直接访问到外部函数的这两个变量。可以把外部作用域中的this对象保存在一个闭包能够访问到的变量里。就可以让闭包访问该对象了。
var name = "windows";var object = { name:"my object", getNameFunc:function(){ var that = this; return function(){ return that.name; }; }}alert(object.getNameFunc()());//my object
内存泄漏
由于IE9之前的版本对JScript对象和COM对象使用不同的垃圾收集例程。因此闭包在IE的这些版本会导致一些问题。具体说,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素无法被销毁。
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); };}
由于匿名函数保存了一个对assignHandler()的活动对象的引用,element的引用数至少是1,因此它占用的内存就永远不会被回收。可以通过以下程序改正。
function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ alert(id); }; element = null;}
模仿块级作用域
javascript没有块级作用域的概念。也就说在快级作用域中定义的变量,实际上是在包含函数中而非语句中创建的。
function outputNumbers(count){ for (var i=0; i < count; i++){ alert(i); } alert(i); //count }
即从他定义开始就可以在函数内部随处访问他。及时错误的重新声明一个变量,也不会改变他的值。
function outputNumbers(count){ for (var i=0; i < count; i++){ alert(i); } var i; //variable re-declared alert(i); //count }
js不会管是否多次声明了同一个变量,它对后续的声明视而不见,不过它会执行后续声明中的变量初始化。匿名函数可以用来模仿块级作用域并避免这个问题。语法如下
(function(){ //这里是快级作用域})(); function outputNumbers(count){ (function () { for (var i=0; i < count; i++){ alert(i); } })(); alert(i); //causes an error }
在匿名函数中执行的任何变量,都会在执行结束时被销毁。这种技术经常被用在函数外部,从而限制向全局函数中添加过多的变量和函数。
(function(){ var now = new Date(); if(now.getMonth()==0 && now.getDate()==1){ alert("happy new year"); }})();
这种做法可以减少闭包占用内存的问题。因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链了。
私有变量
js没有私有成员的概念。但是有私有变量,包括函数的参数,局部变量和在函数内部定义的其他函数。
特权方法:有权访问私有变量和私有函数的公有方法
静态私有变量:
var privatevariable = 10;function privateFunction(){ return false;}MyObject = function(){};MyObject.prototype.publicMethod = function(){ privatevariable++: retrun privateFunction();}
初始化未经声明的变量总会会创建一个全局变量。因此MyObject就是一个全局变量。严格模式下回出错。由于特权方法是在原型上定义的,因此所有实例都是用同一个函数。而这个特权方法,作为一个闭包,总是保存着对包含作用域的引用。
多查找作用域链中的一个层次,就会在一定程度上影响查找速度。而这正是使用闭包和私有变量的一个明显的不足之处。
模块模式
为单例创建私有变量和特权方法。js是以对象字面量的方式来创建单例对象的。
var singleton - { name:value, method:function(){ //这里是方法的代码 }}
模块模式通过为单例添加私有变量和特权方法能够使其得到增强。
var singleton = function(){ var privateVariable = 10; function privateFunction(){ return false; } return { publicProperty = true; publicMethod:function(){ privateVariable ++; return privateFunction(); } };}();
增强的模块模式
在返回对象之前加入对其增强的代码。这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些方法或属性加以增强的情况。
var singleton - { name:value, method:function(){ //这里是方法的代码 }}
模块模式通过为单例添加私有变量和特权方法能够使其得到增强。
var singleton = function(){ var privateVariable = 10; function privateFunction(){ return false; } var object = new CustomType(); object.publicProperty = true; object.publicMethod:function(){ privateVariable ++; return privateFunction(); } return object;}();
- js高级程序设计笔记4--函数表达式及闭包
- javascript高级程序设计第七章(函数表达式、闭包)笔记
- JavaScript高级程序设计(第2版) 学习笔记:(二)js函数作用域与闭包
- JavaScript高级程序设计之函数表达式之闭包之闭包与变量第7.2.1讲笔记
- 《JS高级程序设计》——函数#闭包#
- JS高级程序设计7-函数表达式
- JavaScript高级程序设计笔记-函数表达式
- JavaScript高级程序设计之函数表达式之闭包之关于 this 对象第7.2.2讲笔记
- JavaScript高级程序设计之函数表达式之闭包之内存泄漏第7.2.3讲笔记
- JS高级程序设计笔记(六)- 函数
- 学习《JS高级程序设计》(4)——闭包
- JS笔记:函数闭包及柯里化
- 《js高级程序设计》--函数
- 闭包《javascript高级程序设计》笔记
- js 高级程序设计笔记
- JS高级程序设计-笔记
- [Javascript 高级程序设计]学习心得记录10 js函数表达式
- 《JavaScript高级程序设计 第三版》学习笔记 (六) 函数与闭包详解
- Unity A*算法实现
- Android 圆形按钮实现
- IOS SWIFT CORE DATA 储存,查询,
- poj 1724 ROADS条件限制下的最短路径
- 前序遍历和中序遍历 重建树
- js高级程序设计笔记4--函数表达式及闭包
- 返回一个List里的全部排列
- mac root用户没有权限
- EDIT操作
- hdu5497 Inversion 树状数组 待补完!!!
- 梯度下降法详解
- 自定义控件三部曲之动画篇(一)——alpha、scale、translate、rotate、set的xml属性及用法
- <c:catch>标签的使用
- [pyQt_Error]QObject::killTimer: timers cannot be stopped from another thread