1.8 JS-秒懂上下文、作用域、作用域链、变量提升

·  阅读 275

作用域&作用域链

作用域定义

  • MDN上说,作用域就是当前值和表达式在其中 "可见" 或可被访问到的上下文。

  • w3school上说,作用域指的是您有权访问的变量集合。

两个权威网站上对作用域的解释虽然不一样,但表达的意思差不多。

作用域分类

变量有三种作用域类型:全局作用域、局部作用域、es6块级作用域。(在 JavaScript 中,对象和函数也是变量。)

  • 在函数外面定义的变量、非“严格模式”下未定义直接赋值的变量、window对象的属性都具有全局作用域;

  • 局部作用域又称函数作用域,即函数内部定义的变量只拥有函数内部的局部作用域,函数参数也是函数内的局部变量,拥有局部作用域。

  • 块级作用域是指在非函数的{}里用let定义的变量只拥有{}内部的块级作用域。

不同作用域变量的有效期

JavaScript 变量的有效期始于其被创建时。

局部变量会在函数完成时被删除。

全局变量会在您关闭页面是被删除。

作用域链

作用域链会把作用域连接起来,作用域链是对作用域中的变量进行访问,是访问的规则。如果在函数A里声明了一个函数B,那么在B创建的时候就会引用A的作用域,这样就组成了所谓的函数作用域链。当在自身作用域内找不到该变量的时候,会沿着作用域链逐步向上查找,若在全局作用域内部仍找不到该变量,则会抛出异常。

如何运用作用域链的知识进行性能优化?

作用域链越深,读写速度就会越慢,查找全局变量更慢,所以在编写代码的时候应:

尽量少用全局变量,应尽可能使用局部变量。

如果一个跨作用域的变量被引用了一次以上,应该把它先存储为局部变量再使用。

上下文(执行上下文)

当执行 JS 代码时,会产生三种执行上下文

  • 全局执行上下文
  • 函数执行上下文
  • eval 执行上下文

每个执行上下文中都有三个重要的属性

  • 变量对象(VO),包含变量、函数声明和函数的形参
  • 作用域链(JS 采用词法作用域,也就是说变量的作用域是在定义时就决定了)
  • this

变量提升

JS 变量的三阶段「创建create、初始化initialize 和赋值assign」

  • 创建:为变量a开辟内存空间
  • 初始化:a=undefined
  • 赋值:a=1

简单来说,变量提升是一种把创建/初始化/赋值中的某一阶段的变量移动到作用域最前面的机制。(js中对象和函数也是变量)

举例来说,

var a = 1;
console.log(a);// 1
console.log(b);// undefined 
var b=2;
复制代码

当a、b被声明时,同时被提升到了作用域的顶端,所以相当于:

var a=undefined;
var b=undefind;
a = 1;
console.log(a);
console.log(b);
b=1;
复制代码

因此,打印出的是undefined。 当

my();// 1
function my(){
    var b = 1;
    console.log(b);
}
复制代码

此处会打印出1是因为:在js中,当函数被声明时他就被提到了作用域的顶端,而且是整个函数都被提升了,因此,my()函数执行无误。

let、const、var、function分别提升了哪一阶段的变量?

let 的「创建」过程被提升了,但是初始化没有提升。(很多人把这种情况叫做let的暂存性死区)

const 的「创建」过程被提升了,但是初始化没有提升。

var 的「创建」和「初始化」都被提升了。

function 的「创建」「初始化」和「赋值」都被提升了。

分类:
前端