Skip to content

Latest commit

 

History

History
788 lines (521 loc) · 12.5 KB

index.mdx

File metadata and controls

788 lines (521 loc) · 12.5 KB

import { CodeSurferLayout } from 'code-surfer'; import { Appear } from 'mdx-deck'; export { nightOwlFull as theme } from 'code-surfer/themes';

JavaScript 执行上下文和闭包


var value = 'global value';
function alertValue() {
  alert(value);
  var value = 'local value';
  alert(value);
}
alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();

为什么第四行代码alert(value)会弹出undefined呢?


var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);
}

alertValue();

重要概念

  • 执行上下文
  • 作用域
  • 作用域链
  • var变量、函数提升
  • 怎么查找到变量?
  • 最后,讲讲闭包

执行上下文

execution context

有哪些执行上下文?

  • 全局
  • 函数(又称之为本地)
  • 块(block)
  • eval

var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);

  function inner() {
    alert(value);
  }

  inner();
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);

  function inner() {
    alert(value);
  }

  inner();
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);

  function inner() {
    alert(value);
  }

  inner();
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);

  function inner() {
    alert(value);
  }

  inner();
}

alertValue();

var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);

  function inner() {
    alert(value);
  }

  inner();
}

alertValue();
var value = 'global value';

function alertValue() {
  alert(value);

  var value = 'local value';

  alert(value);

  function inner() {
    alert(value);
  }

  inner();
}

alertValue();

  • 红色的区域是全局执行上下文
  • 只能有一个全局执行上下文
  • 两个黄色框是两个函数执行上下文
  • 只要调用一次函数,就创建了一个函数执行上下文
  • 所以,可以有无数个函数执行上下文

JS 解释器是怎么执行一段代码的?

两阶段:

  • 阶段一:创建阶段。创建的是执行上下文。
    • 创建作用域链
    • 创建 var 变量、内部函数、函数入参
    • 准备this
  • 阶段二:一行一行执行代码。

var 变量、函数提升

JS 解释器执行代码的过程,会带来一个很让人费解的现象:

可以在 var 变量、函数定义之前使用 var 变量和函数;

在 var 变量之前使用 var 变量,变量值是 undefined。


ES6 看不惯 var 变量提升

letconst就横空出世啦!

通过letconst定义的变量不参与到创建阶段。


alert(value);

let value = '123';
alert(value);

let value = '123';

ES6 的新东西:块作用域

使用**{}**就可以定义一个块作用域。

  • var 变量是跨块级作用域的。
  • let, const 变量只能在块作用域中使用。

{
  let value = 0;
  console.log(value);
}
console.log(value);
{
  let value = 0;
  console.log(value);
}
console.log(value);
{
  let value = 0;
  console.log(value);
}
console.log(value);
{
  let value = 0;
  console.log(value);
}
console.log(value);

{
  var value = 0;
  console.log(value);
}
console.log(value);
{
  var value = 0;
  console.log(value);
}
console.log(value);
{
  var value = 0;
  console.log(value);
}
console.log(value);
{
  var value = 0;
  console.log(value);
}
console.log(value);

ifforwhiledo这些带有**{}**的语句都会创建块作用域。


执行上下文之间是什么关系?

如果从词法上看代码之间是嵌套关系,则相对应的执行上下文就是链接关系。
子执行上下文的代码可以访问到父执行上下文的变量、函数等。
新名词:词法作用域 (lexture scope)。
执行上下文栈 execution context stack

执行上下文中有什么东西?

执行上下文就是一个 JavaScript 对象,其中有三个最重要的属性:

  • scopeChain - 作用域链
  • 包含自身的variableObject和所有父执行上下文中的variableObject
  • variableObject - 变量对象:包括函数入参、内部变量、内部函数定义
  • this

作用域约等于 variableObject


作用域链长什么样?

作用域链类似链表的一个结构:


为什么要有作用域链?

为了在执行代码时,查找到变量。

怎么查找到变量?

沿着作用域链从自身作用域往上查找,一直到全局作用域。

窥探一下 Chrome 浏览器是如何创建作用域链的?

alertValueinner函数为例。

**console.dir(fn)**会输出更详细的函数信息,包括一些解释器信息。


console.dir(alertValue)

展开 global scope,发现:


console.dir(inner)


console.dir(inner)


小结

Chrome 在创建函数时,会将当前执行上下文的作用域链与这个函数实例进行绑定。

这样,在调用这个函数时,在“创建阶段”,就很容易构建出作用域链。

这种在创建函数时绑定父执行上下文的作用域的行为,称之为“Closure”。也就是所谓的“闭包”。


闭包

第一个定义:按照 Chrome 的说法,在创建函数时绑定父执行上下文的作用域的行为。


闭包

第二个定义:按照 MDN 的说法,闭包是函数和声明该函数的词法环境的组合。

这个环境包括了这个闭包创建时所能访问的所有局部变量。


闭包

第三个定义:闭包是一种能够在函数声明过程中将环境信息与所属函数绑定在一起的数据结构。

它是基于函数声明的文本位置的,因此也被称为围绕函数定义的 静态作用域词法作用域

闭包本质论

从本质上讲,闭包就是函数继承而来的作用域。这类似于对象方法时如何访问其继承的实例变量的,它们都具有其父类型的引用。

是对变量的引用


应用所学的知识思考一个问题。


for (var i = 0; i < 100; i++) {
  setTimeout(() => {
    console.log(i);
  }, 25);
}
for (var i = 0; i < 100; i++) {
  setTimeout(() => {
    console.log(i);
  }, 25);
}
for (let i = 0; i < 100; i++) {
  setTimeout(() => {
    console.log(i);
  }, 25);
}
for (let i = 0; i < 100; i++) {
  setTimeout(() => {
    console.log(i);
  }, 25);
}

为什么呢?:sunglasses:


谢谢!!!!

👏👏👏

🎉🎉🎉