函数表达式
一、函数表达式定义
函数的方式有两种:一种是函数声明,另一种是函数表达式函数声明语法格式如下:
function functionName(arg0,arg1,arg2){
//函数体
}
关于函数声明,有一个重要的特征就是函数声明提升,意思是在执行代码之前会先读取函数声明
函数表达式语法格式如下:
var functionName=function(arg0,arg1,arg2){
//函数体
}
二、递归
递归函数是一个函数通过名字调用自身情况构成的经典的递归函数
function factorial(num){
if(num<=1){
return 1
}else{
return num*factorial(num-1)
}
}
console.log(factorial(3))
但是下列代码会导致它出现问题
var anotherFactial=factorial;
factorial=null;
console.log(anotherFactial(4))
此时解决的方法有两个
//方法一
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1)}}//但是严格模式下不能通过脚本访问arguments.callee,故可以使用方法二更加保险
//方法二:
var factorial=(function f(num){if(num<=1){
return 1;
}else{return num*f(num-1)
}
}
)
三、闭包
闭包是指有权访问另一个函数作用域的变量的函数,常见的创建闭包的常见方式,就是在一个函数内部创建另有一个函数
function createComparisionFunction(propertyName){
return function(object1,object2){
var value1=object1[propertyName];
var value2=object2[propertyName];
if(value1<value2){
return -1
}else if(value1>value2){
return 1
}else{
return 0
}
}
}
闭包的执行过程:某个函数被调用时,会创建一个执行环境及相应的作用链域。然后使用arguments和其他命名参数的值来初始化函数的活动对象,但在作用域中,外部函数活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位…知道作用链域终点的全局执行环境。
下面来讨论一下函数执行完毕后闭包域其他普通函数的不同之处
普通函数:函数作用域及其所有变量都会在函数执行结束后被销毁
闭包:函数作用域会一直在内存中保存到闭包不存在为止
3.1、闭包与变量
闭包只能取得包含函数中任何变量的最后一个值闭包保存着的是整个变量对象,而不是某个特殊的函数
function createFunctions(){
var result=new Array()
for(var i=0;i<10;i++){
result[i]=function(){
return i
}
}
return result
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
console.log(funcs[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
}
var funcs = createFunctions();
for (var i=0; i < funcs.length; i++){
console.log(funcs[i]());//0,1,2,3,4,5,6,7,8,9 }
3.2、关于this对象
在闭包中,匿名函数的执行环境具有全局性,因此其this对象通常指向window
var name="The Window";
var object={
name:"My Object",
getNameFunc:function(){
return function(){
return this.name;
}
}
}
console.log(object.getNameFunc()())//"The window"
为什么匿名函数没有取得其包含作用域(或外部作用域)的this对象呢
因为每个函数在被调用的时候都会自动取得两个特殊的变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量
但是,将该对象的引用保存到另一个闭包能访问的变量中
var name="The Window";
var object={name:"My Object",
getNameFunc:function(){
var that=this;
return function(){
return that.name;
}
}
}
console.log(object.getNameFunc()())//"The window"
3.3、内存泄漏
四、模仿块级作用域
(function(){
//这里是块级作用域
})();
但是注意不能这样做:
function(){
//这里是块级作用域
}();//出错
这是因为js将function关键字当作一个函数声明的开始,而函数声明后面不可以跟圆括号
然而,函数表达式后面可以跟圆括号,要将函数声明转换成函数表达式,只要给它加上一对圆括号或者改为函数表达式
(function(){
})()
var fun=function(){
}()
function outputNumbers(count){
(function(){
for(var i=0;i<count;i++){
console.log(i)//0,1,2,3
}
})();
console.log(i)//error
}
outputNumbers(4)
五、私有变量
我们把有权访问私有变量和私有方法的公有方法称为特权方法
有两种方法在对象上创建特权方法:第一种是在构造函数中定义特权方法,
function myObject(){
var privateVaeriable=10;
function privateFunction(){
return false;
}
this.publicMethod=function(){
privateVaeriable++;
return privateFunction();
}
}
5.1、静态私有变量
实例都会创建同样一组新方法,故通过静态私有变量来解决:
(function(){
var privateFunction=10;
function privateFunction(){
return false;
}
MyObject=function(){//通过函数表达式来定义构造函数,因此MyObject成为了一个全局函数,同样初始化未声明的变量,总会创建一个全局变量,MyObject就成了一个全局变量,能够在私有作用域之外被访问
}
MyObject.prototype.publicMethod=function(){
privateVariable++;
return privateFunction()
}
})
这个模式与前面在构造函数中的主要区别:私有变量和函数是由实例共享的,由于特权方法是在原型上定义的,因此所有的实例使用同一个函数
(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("Nicholas");
var person2=new Person("Michael");
console.log(person1.getName());//"Nicholas"
person1.setName("Greg");
console.log(person1.getName())//"Greg"
console.log(person2.getName())//"Greg"
但是原型方法由所有实例公用,在一个实例上调用setName()会影响所有实例。结果就是所有的实例都会返回相同值
所以延伸出下面的模块模式
5.2、模块模式
为单例创建变量和特权方法
var singleton=function(){
//私有变量和私有函数
var privateVariable=10;
function privateFunction(){
return false;
}
//特权/共有方法和属性
return {
publicProperty:true,
publicMethod:function(){
privateVariable++;
return privateFunction()
}
}
}();
这种模式在需要对单例进行某些初始化,同时也需要维护某私有变量是非常有用的
简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能访问这些私有数据的方法,就可以使用模块模式
5.3、增强的模块模式
在返回对象之前加入对其增强的代码,这种增强的模块模式适合哪些单例必须是某种类型,同时还必须添加某些属性和方法对其加以增强的情况
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
}()
上一篇: 浅谈Android动画(二) 逐帧动画