JavaScript高级程序设计-第三版(函数表达式)

本文详细解析JavaScript中的函数表达式,包括递归、闭包、私有变量等高级概念,探讨其工作原理及应用场景,如闭包如何访问外部变量,私有变量的实现方式,以及如何避免内存泄漏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

七、函数表达式

  • 函数声明
    • 函数声明提升
    • 全局范围可访问
  • 函数表达式
    • 按顺序执行,不会进行提升
    • 可以是命名的,也可以是匿名的
      • 命名
        • var factorial=function f(){};
      • 匿名
        • 又称为Lamada函数
        • var factorial=function (){};
          • 函数表达式是匿名的
          • 将匿名函数赋值给一个变量

7.1 递归

  • 命名的函数表达式
    • 函数表达式有个名称
    • ECMAScript 5严格模式下arguments.callee属性无法访问
var factorial=(function f(num){
	if(num<=1){
		return 1;
	}else{
		return num*f(num-1);
	}
});

7.2 闭包

       有权访问另一个函数作用域(一般是外部函数的作用域)中的变量的函数

  • 外部函数将内部函数作为对象返回,内部函数拥有外部函数的活动对象
    • 活动对象
             未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。所以活动对象实际就是变量对象在真正执行时的另一种形式
  • 外部函数的作用域链在外部函数执行完毕后销毁,但其变量对象被闭包所引用,所以还会一直保存在内存中直至闭包不再引用

7.2.1 闭包与变量

function createFunction(){
	var result=new Array();
	for(var i=0;i<10;i++){
		result[i]=function(){
			return i;
		};
	}
	//函数数组,函数在执行时先访问本身的函数作用域
	//再访问外部函数的变量对象,该对象是同一份
	return result;
}
  • 闭包拥有外部函数的活动对象,而活动对象是引用类型,随着外部函数的执行会发生变化,而闭包引用的是最终的活动对象
function createFunction(){
	var result=new Array();
	for(var i=0;i<10;i++){
		result[i]=function(num){
			return function(){
				return num;
			};
		}(i);
	}
	return result;
}
  • 声明函数后立即执行,并返回执行结果,而执行结果是一个访问外部函数num变量的闭包
    • 外部函数每次会重新声明并创建,所以闭包中引用的外部函数的变量对象不是同一份

7.2.2 关于this对象

  • 每个函数被调用时,其活动对象会自动获得两个特殊变量,this和arguments
  • 函数在搜索这两个变量时,只会在活动对象中搜索
var name="The Window";
var object={
	name:"My Object",
	getNameFunc:function(){
		return function(){
			return this.name;
		};
	}
};
alert(object.getNameFunc()());//"The Window"
  • object.getNameFunc()得到的是匿名函数
  • 匿名函数调用时,执行环境是全局的,其活动对象为全局变量对象

var name="The Window";
var object={
	name:"My Object",
	getNameFunc:function(){
		var that=this;
		return function(){
			return that.name;
		};
	}
};
alert(object.getNameFunc()());//"My Object"
  • object.getNameFunc()执行并返回匿名函数
    • 执行过程中,其作用域为object,所以this指向object
  • 匿名函数内部会返回that对象的name属性,由于是that而不是特殊的this,所以会搜索外部函数的变量对象

var name="The Window";
var object={
	name:"My Object",
	getNameFunc:function(){
		return this.name;
	}
};
object.getNameFunc();//"My Object"
(object.getNameFunc)();//"My Object"
//函数表达式的值是函数本身
(object.getNameFunc=object.getNameFunc)();//"The Window"

7.2.3 内存泄漏

  • 循环引用
    • 闭包引用外部函数的变量对象,而外部函数的变量对象会引用闭包
function assignHandler(){
	var element= doucment.getElementById("someElement");
	element.onclick=function(){
		alert(element.id);
	};
}
  • 消除循环引用
    • 值复制,使得闭包不直接引用element
      • 但闭包引用的是外部函数的整个活动对象
    • 消除外部函数中的变量对闭包的引用
function assignHandler(){
	var element= doucment.getElementById("someElement");
	var id=element.id
	element.onclick=function(){
		alert(id);
	};
	element=null;
}

7.3 模仿块级作用域

(function (){
	//块级作用域
})();
  • 使用括号包裹函数声明,则会将函数声明看作是函数表达式
    • 不加括号,function会被看作是函数声明的开始
  • 函数声明后面无法加括号直接进行调用
  • 函数表达式立即调用,执行后立即销毁,模仿块级作用域

7.4 私有变量

  • 私有变量
           所有对象的属性都是公有的,只有函数中的参数、局部变量和内部定义的其他函数只能在函数内部访问
  • 特权方法
           闭包能访问外部函数的变量对象,若将闭包公开则外部就可以通过闭包访问函数内部的私有变量
  • 闭包公开的方式之一
    • 作为构造函数的实例属性
      • 闭包(特权方法)不能复用
      • 私有变量是构造函数的局部变量
        • 实例属性
function Person(name){
	this.getName=function(){
		return name;
	};
	this.setName=function(value){
		name=value;
	};
}
var person=new Person("Nicholas");
alert(person.getName()); //"Nicholas"

7.4.1 静态私有变量

  • 闭包公开的方式之二
    • 作为构造函数的原型属性,而构造函数创建出全局对象
    • 私有变量是模仿块级作用域中的局部变量
      • 变量要私有,则不能作为构造函数的属性
      • 私有变量属于块级作用域,存在于变量对象中,由所有实例共享,相当于静态变量
      • 虽然块级作用域执行完毕后会销毁,但由于闭包的引用,所以变量对象还保留
      • 构造方法是未声明直接初始化的
               为声明直接初始化的变量在非严格模式下会被当成全局变量,所以在外界能访问构造函数
(function (){
	var name="";
	Person=function(value){
		name=value;
	};
	Person.prototype.getName=function(){
		return name;
	};
	Person.prototype.setName=function(value){
		name=value;
	};
})();
var person=new Person("Nicholas");
alert(person.getName()); //"Nicholas"

7.4.2 模块模式

  • 以上创建私有变量的方式是针对自定义类型的
  • 模块模式针对的是单例对象,不需要识别类型
  • 单例对象
           以对象字面量的方式创建
  • 闭包公开的方式之二
    • 作为函数返回值将闭包(特权方法)公开
      • 函数返回值是以对象字面量创建的,为Object类型
    • 私有变量是模仿块级作用域中的局部变量
      • 由于是单例对象,所以也不存在静态变量还是实例属性的区别
var singleton=function(){
	var privateVariable=10;
	function privateFunction(){
		return false;
	}
	return {
		publicProperty:true,
		publicMethod:function(){
			privateVariable++;
			return privateFunction();
		}
	};
};

7.4.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;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值