JS高阶

复习一下JS高阶–1

1.执行环境与作用域**

1.1执行环境

  讲解作用域之前先聊聊JS中的执行环境。执行环境定义了变量或函数能够访问的数据,为此,每个执行环境都关联着一个“隐藏的”变量对象,环境中定义的所有变量和函数都保存在这个变量对象中,虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

	var a = 1
	function add(num) { // 将传进的数字加 2
	var b = num + 2
	}

  这段代码的执行环境就是window,window是全局执行环境。
  在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都作为window对象的属性和方法。

而 定义的a和函数add就是变量对象。

  执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数也随之销毁。全局执行环境window直到应用程序退出(比如关闭网页或浏览器)时才会被销毁。

  了解了“执行环境”和“变量对象”,我们对示例稍作改动,在add()函数内部嵌套一个用于打印变量的output()函数:

	var a = 1
	function add2(num) { // 将传进去的数字加 2
	var b = num + 2
	function output(c) { // 打印变量 a, b, c
	console.log(a, b, c)
	}
	output(b+2) // 调用时将 b+2 的值传入 output() 函数
	}
	add2(a) // 1, 3, 5

  除了全局执行环境,函数也有自己的执行环境。执行一个函数中的代码时,函数的环境就会被推入一个环境栈中(PS:有同学不知道啥是“栈”,对于栈,目前先记住“先入后出”就可以了)。

而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

1.2作用域与作用域链

  简单地说,作用域可以理解为「标识符」以及「标识符所能访问到的范围」(PS:标识符是什么?所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。)。
  深入地说,作用域与我们上面铺垫所说的“执行环境”以及“变量对象”是什么关系呢?当代码在一个「执行环境」中执行时,会创建「变量对象」的一个「作用域链」。乍一看可能有点绕,没关系,我们看图说话。比如当代码执行到上面示例中最里层的output()函数时,作用域链是这个样子的:
在这里插入图片描述
  由此,标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯(最外层是window对象),直至找到标识符为止(如果找不到标识符,通常会导致错误发生)。
所以概括来说,作用域链的作用,是确保对执行环境中变量和函数的有序访问。

1.3作用域的类型

1.全局作用域
  Web浏览器下可简单理解为window对象,所有最外层的变量和函数都作为window对象的属性和方法,且它们可以在任何代码位置被访问到。全局作用域处于作用域链的最末端(最外层)。
2.局部作用域(函数作用域)
  局部作用域是在函数执行时被临时创建的作用域。在局部作用域中创建的变量会在函数执行完毕后自动释放。
3.ES5没有块级作用域(ES6新增块级作用域)
  先说什么是块级作用域:任何一对花括号 {} 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的。
那为什么说ES5中是没有块级作用域的呢?来看示例:

	if (true) {
	var a = 100
	}
	console.log(a) // 100

虽然变量a在if语句的一对花括号中,但花括号外依然可以访问a。

1.4 ES6块级作用域

  我们再来看一个由于ES5中没有块级作用域而导致的问题,我们使用变量i进行循环计数:

	var str = 'hello'
	for (var i = 0; i < str.length; i++) {
	console.log(str[i])
	}
	console.log(i) // 5

  在这种场景下,用来计数的循环变量i泄露为全局变量。我们只想用变量i来控制循环,但是循环结束后,它并没有消失,而是泄露成了全局变量。
  变量的声明应该距离使用的地方越近越好,并且应最大程度地避免向外层作用域泄露,我们确实需要块级作用域。
  ES6的let和const实际上为JavaScript新增了块级作用域。
  let命令用来声明变量。它的用法类似于var,但是let所声明的变量,只在let命令所在的代码块内可以访问。我们用let改写上面的示例

	const str = 'hello'
	for (let i = 0; i < str.length; i++) {
	console.log(str[i])
	}
	console.log(i) // Uncaught ReferenceError: i is not defined

  循环变量i使用let声明后,仅在if的语句块内有效,不会再泄露为全局变量了。const的作用域与let命令相同:只在声明所在的块级作用域内有效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值