JS高程 -- chapter( 函数表达式 )

本文详细解析了JavaScript中的闭包概念,包括闭包如何保存变量、作用域链的工作原理,以及如何利用闭包解决定时器中的变量泄漏问题。同时,介绍了递归函数的实现方式,并解释了具名函数表达式如何确保递归过程的正确执行。
摘要由CSDN通过智能技术生成

递归


var factorial = (function f(n){
	if(n<=1){
		return 1;
	}else{
		return n*f(n-1);
	}
})

上面这段代码使用具名函数表达式来创建递归函数,保证 factorial 变量即使指向别的对象也能正确执行递归。

( ) 中是什么,它就返回什么,若是函数,则其命名在全局是无法访问的,只有赋值给一个变量才能访问( 参考立即执行函数 )

 

闭包


闭包 是指有权访问另一个函数作用域中变量的函数

作用域链细节:

  1. 函数 创建 的时候,会创建一个执行环境( 执行上下文 ),以及确定作用域链,创建 变量 对象
  2. 函数 执行 的时候, 变量 对象转换为 活动 对象arguments 对象和函数内声明的 变量 的赋值,初始化 活动 对象
  3. 作用域链中,当前函数的 活动 对象 处于链上的最前端,然后依次是上一级函数的 活动对象,… 最后直到全局执行环境

当函数执行完毕时,函数中的变量都会被销毁,只保留全局作用域的 活动对象,但是由于闭包函数的作用域链上拥有对其链上一系列函数的 活动 对象的引用,所以这些函数的 活动 对象 不会被销毁,会被保留在内存中

 

闭包与变量

闭包保存的是整个 活动 对象,而不是某个变量

for(var i=0; i<5; i++){
	setTimeout(function(){
		console.log(i);
	},1000*i);
}

这道经典的面试题,其会每秒打印一个 5,原因就是 其实 定时器里的函数就是一个闭包,它会在同步代码执行完毕之后执行,其作用域链中保存了当前函数环境的 活动对象,其中 i 的值在当前函数执行结束之后变为了 5,然后定时器闭包函数开始执行,然后就会每秒打印一个 5

 
想要获得 0, 1, 2, 3, 4 这种打印结果,就得要定时器函数能够记住当前 i,可以使用闭包解决( 函数的参数都是值传递的 )

for(var i=0; i<5; i++){
	setTimeout(function(i){
		return function(){
			console.log(i);
		}
	}(i),1000*i);
}

 

关于 this

this 指向是在函数执行的时候才确定的,所以使用闭包的时候 可能出现问题,只要没有显示的调用者,或者使用 apply, call, bind 指定调用者,则 this 都会指向全局对象

 

模仿块级作用域


ES6 之前,js 是没有块级作用域的,这意味着在 if..else、for、while 等语句中声明的变量会成为当前函数或者全局的变量,即在这些代码块之外的地方,也能访问到在块中定义的变量

 

变量提升

JS 会在函数执行的时候将函数声明,变量声明提升到函数的最顶部先执行( 使用 var 声明 ),函数优先,如果遇到相同的名字,则会忽略后一个,但是如果在声明的地方有赋值操作,赋值操作还是会进行,只不过声明被忽略

 
 
可以使用匿名函数来模仿块级作用域

(function(){
	// 这里的 a 不会被外界访问到
	var a = 1
})()

函数表达式后面可以跟圆括号,可以使用圆括号将匿名函数体包裹起来转换成函数表达式
(function(){ }) // => 函数表达式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值