作用域和作用域链

作用域

作用域就是变量和函数的可访问范围,控制着变量和函数的可见性与生命周期。

作用域分为 静态作用域 和 动态作用域

作用域的另外理解可点击这里查看

静态作用域

静态作用域还称为词法作用域:词法作用域是指在词法分析阶段就确定了,不会改变。

在词法作用域中:变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定

词法分析的详细信息可点击这里查看

动态作用域

动态作用域是在运行时根据程序的流程信息来动态确定的,而不是在写代码时进行静态确定的。

动态作用域并不关心作用域和函数是如何声明以及在何处声明的,只关心它们在何处调用。

js采用的静态作用域

js所采用的的作用域模型是词法作用域

下文中所谈的作用域也都是默认指得是js所采用的的“静态作用域”。 静态作用域根据代码的执行环境又分为:全局作用域、局部作用域(函数作用域)、块作用域

在ECMAScript 5(包括ECMAScript 5)之前的版本中,作用域只有全局作用域和局部作用域,不存在块级作用域;ECMAScript 6引入了let和const关键字,利用let和const可以形成块级作用域。

全局作用域

在代码中任何地方都能访问到的对象拥有全局作用域。全局作用域的变量是全局对象的属性,不论在什么函数中都可以直接访问,而不需要通过全局对象,但加上全局对象,可以提供搜索效率。

  • 没有用var声明的变量(除去函数的参数)都具有全局作用域,成为全局变量,所以声明局部变量必须要用var。
  • 最外层函数体外声明的变量也具有全局作用域
  • window的所有属性都具有全局作用域

局部作用域

局部作用域里面的变量的优先级高于全局变量。

  • 函数体内用var声明的变量具有局部作用域,成为局部变量
  • 函数的参数也具有局部作用域
var a=3; // 全局变量  
function fn(b){ // 局部变量  
 c=2; // 全局变量  
 var d=5; // 局部变量  
 function subFn(){  
    var e=d; // 父函数的局部变量对子函数可见  
    for(var i=0;i<3;i++){  
      console.write(i);  
    }  
    alert(i);// 3, 在for循环内声明,循环外function内仍然可见,没有块作用域  
 }  
}  
alert(c); //2, 在function内声明但不带var修饰,仍然是全局变量  

块作用域

使用let和const关键字声明的变量,会在形成块级作用域。

if (true) {
   // 'if' 条件语句块不会创建一个新的作用域
   // name 在全局作用域中,因为通过 'var' 关键字定义
   var name = 'Hammad';
   // likes 在局部(本地)作用域中,因为通过 'let' 关键字定义
   let likes = 'Coding';
   // skills 在局部(本地)作用域中,因为通过 'const' 关键字定义
   const skills = 'JavaScript and PHP';
}
console.log(name); // logs 'Hammad'
console.log(likes); // Uncaught ReferenceError: likes is not defined
console.log(skills); // Uncaught ReferenceError: skills is not defined

作用域链

当多个作用域之间发生嵌套时,如果在当前作用域里面无法找到某个变量,引擎就会在外层作用域中继续查找,直到找到该变量或抵达最外层作用域(即全局作用域)为止。这种查找变量的方式就是根根据作用域链进行查找的。

JavaScript 中每个函数都都表示为一个函数对象(函数实例),而函数对象都有一个仅供 JavaScript 引擎使用的[[scope]] 属性。函数在进行语法分析和预解析,将它的[[scope]] 属性指向函数定义时作用域中的所有对象集合。这个集合被称为函数的作用域链(scope chain),包含函数定义时作用域中所有可访问的数据。

function add(num1, num2) {
  var sum = num1 + num2;
  return sum;
}

当定义 add 函数后,其作用域链就创建了。函数所在的全局作用域的全局对象被放置到 add 函数作用域链([[scope]] 属性)中。我们可以从下图中看到作用域链的第一个对象保存的是全局对象,全局对象中保存了诸如 this , window , document 以及全局对象中的 add 函数,也就是他自己。这也就是我们可以在全局作用域下的函数中访问 window(this),访问全局变量,访问函数自身的原因。
在这里插入图片描述

上下文和作用域

作用域(scope)和上下文(context)是两个不同的概念:

  • 作用域:指变量的可访问性
  • 上下文:是指this在同一作用域内的值

我们也可以使用call()、apply()、bind()、箭头函数等改变上下文。在浏览器中在全局作用域(scope)中上下文中始终是Window对象。在Node.js中在全局作用域(scope)中上下文中始终是Global 对象。

var name = "windowsName";
function a() {
    var name = "Cherry";
    console.log(this.name);  // windowsName
    console.log("inner:" + this);// inner: Window
}
a();
console.log("outer:" + this) // outer: Window

执行上下文和作用域

执行上下文:js引擎在执行代码是所做的一个准备工作,即为这段代码生成对应的执行上下文。
js代码在执行时,就是根据代码的执行来对生成的执行上下文进行赋值操作。

执行上下文的详细信息请点击这里查看

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值