块级私有上下文

之前已经总结过:

  • 全局执行上下文:全局对象GO-->变量提升-->代码执行
  • 函数的执行会形成函数私有上下文:-->变量对象AO-->初始化作用域链-->初始化this-->初始化arguments-->形参赋值-->变量提升-->代码执行

此外
除“函数和对象”的大括号外[例如:判断体/循环体/代码块...],如果大括号中出现了let/const/function/class等关键词声明变量,则当前大括号会产生一个块级私有上下文
它的上级上下文是所处的环境(也就是创建这个块级作用域的上下文);
var不产,也不受块级上下文的影响

代码块:

{
}

判断体:

if(1) {

}

循环体:

for(let i = 0; i<6; i++) {

}

通过一段代码来详解一下:

console.log(a)
console.log(b)
var a = 12
var b = 13
if (1 == 1) {
  console.log(a)
  console.log(b)
  var a = 100
  let b = 200
  console.log(a)
  console.log(b)
}
console.log(a)
console.log(b)
image.png

1、全局代码执行,会有一个全局执行环境栈EC(G)
2、变量提升:
代码第三行和第八行 都是var 声明的变量,要变量提升
但是规定不允许重复声明,所以只有一个全局变量a
存储在GO(图中为了省事,GO和VO(G)写一起了)中

GO:
a
3、全局代码执行:
执行到第一行:a只声明,没有定义,所以输出undefined
4、执行到第二行:正常情况下会报错代码不往下执行,这里先忽略报错,看一下往下执行会是什么样子
5、代码执行到第三行:a被赋值为12
6、代码执行到第四行:通过let关键字,声明一个变量b,值为13
7、此时GO中存的是:
a :12
VO(G)中存的是:
b :13
8、代码执行到五行遇到判断体了;
除“函数和对象”的大括号外[例如:判断体/循环体/代码块...],如果大括号中出现了let/const/function/class等关键词声明变量,则当前大括号会产生一个块级私有上下文
它的上级上下文是所处的环境(也就是创建这个块级作用域的上下文);
var不产,也不受块级上下文的影响

所以此时会产生一个块级私有上下文,暂取名为EC(B)

块级私有上下文中的代码正式执行之前,会做以下操作:
@1、初始化作用域链:
(块级私有上下文不初始化this,不初始化arguments,不会形参赋值)
@2、变量提升:特殊:var不受块级上下文影响,所以这里的变量提升只有function会处理,所以这个代码块中不存在变量提升
@3、代码执行:

 {
     console.log(a) // 不受块级私有上下文影响,找的是上上下文的a,上级上下文中(也就是全局)a=12,所以输出值是12
     console.log(b) // 正常代码这里是会报错的,代码不会往下执行了,忽略,假设代码可以往下执行
     var a = 100 // 全局代码执行的时候,var a已经声明过了,所以这里不会再重复声明,全局a重新赋值为100。此时GO中寸的是:a : 100
     let b = 200  // let关键字声明变量b,属于私有变量,存在AO(B)中,值是200
     console.log(a) // 块级上下文没有变量a,网上找,a=100,输出100
     console.log(b) // 私有变量,输出200
}

9、块级私有上下文执行完毕,执行最后两个:

console.log(a):全局a已经在块级私有上下文中被改为100,所以输出100
console.log(b):全局b值是 13,所以输出13

image.png

再看一个例子,这个和上边的还有所不同

console.log(foo)
if(1==1) {
  console.log(foo)
  function foo() {}
  foo = 1
  console.log(foo)
}
console.log(foo)
image.png

这段代码在老版本和新版本浏览器中执行结果是不同的

老版本浏览:不支持块级上下文,不支持ES6语法
1、全局代码执行之前,变量提升
@1、创建一个堆内存0x000,用来存放函数代码字符串等
@2、function foo --> 0x000
2、代码执行
console.log(foo) :输出函数foo
if(1==1) {
console.log(foo):输出函数foo
function foo() {}
foo = 1 :foo重新赋值为1
console.log(foo) :输出1
}
console.log(foo) :输出1

新版本浏览:支持块级上下文,支持ES6语法
1、全局代码执行
2、执行之前会进行变量提升
3、遇到判断体(不管条件是否成立)/循环体/代码块中如果有function,只会声明,不定义。
所以此时 全局变量对象中会有个变量 foo,但是没有值
4、代码执行:所以第行代码

console.log(foo) // undefined

5、除“函数和对象”的大括号外[例如:判断体/循环体/代码块...],如果大括号中出现了let/const/function/class等关键词声明变量,则当前大括号会产生一个块级私有上下文
它的上级上下文是所处的环境(也就是创建这个块级作用域的上下文);
var不产,也不受块级上下文的影响
6、代码执行到if(1===1)条件成立,判断体中又有function,所以会形成块级私有上下文:自定义为EC(Block)
7、

if(1==1) {
  console.log(foo)
  function foo() {}
  foo = 1
  console.log(foo) 
}

8、块级上下文中的代码执行执行还要做一些操作:
初始化作用域链:
变量提升:
function foo-->创建堆内存0x001
(foo是私有变量)
9、代码执行:

 console.log(foo) // 函数foo
  function foo() {} // 变量提升阶段已经执行过,不再执行这一行代码,但是这里会有个特殊处理:@1、会把这行代码之前的所有操作同步给全局一份,此时全局的foo指向的就是堆内存0x001。@2、断开和全局的联系,也就是这行代码以后对foo的操作和全局没关系了
  foo = 1 //  私有变量foo 重新赋值为1
  console.log(foo)  // 1

10、最后一行:
console.log(foo):函数foo

如果对于以上有疑惑,可以再加几行代码来测验

console.log(foo)
if(1==1) {
  console.log(foo)
  foo = 100
  function foo() {} // 这行代码之前 foo显示指向一个函数,又被被赋值为100,这个值也会同步到全局,所以最后一行输出全局的foo是100
  foo = 1
  foo = 200
  console.log(foo)
}
console.log(foo)
image.png

练习题

f = function() {return true}
g = function() {return false};
(function(){
  if(g() && [] == ![]) {
    f = function () {return false}
    function g() {return true}
  }
})()

解析

/**
 * EC(G)
 *      VO(G)/GO
 *              f --> 0x001 [[scope]]:EC(G)
 *              g --> 0x002 [[scope]]:EC(G)
 * 变量提升:--
 */
f = function() {return true}
g = function() {return false};
// 自执行函数执行,形成块级私有上下文EC(AN)
(function(){
  /**
   * EC(AN)
   * 作用域链:EC(AN),EC(G)
   * 形参赋值:--
   * 变量提升:遇到判断体,不管条件是否成立,都会变量提升。
   * function只声明不定义
   * function g
   * 执行判断条件:if(g() && [] == ![]) 
   * 执行g()的时候报错:g is not a function,因为g只声明了没定义
   */
  if(g() && [] == ![]) {
    f = function () {return false}
    function g() {return true}
  }
})()

注意:如果第二行代码不加分号会报错:3.js:65 Uncaught TypeError: (intermediate value)(...) is not a function

**一般来说,“(”、“[”、“/”、“+”、“-”,都会在上一行代码不加分号的情况下,与上一行代码相接,“++”、“--”在上下两行都不加分号的情况下,与下一行代码相接,如遇上了return才会在改行末尾加上分号。:https://blog.csdn.net/KamyoChae/article/details/81198460
**
·````

f = function() {return true}
g = function() {return false};
(function(){
if(g() && [] == ![]) {
f = function () {return false}
function g() {return true}
}
})()



你可能感兴趣的:(块级私有上下文)