javascript基础知识-时间死区,提升或关闭[重复]

Posted

技术标签:

【中文标题】javascript基础知识-时间死区,提升或关闭[重复]【英文标题】:javascript fundamentals - temporal dead zone, hoisting or closure [duplicate] 【发布时间】:2018-10-23 10:09:15 【问题描述】:

为什么这段代码有效

const btn = document.getElementById("btn");

btn.onclick = function() 
  printMe(obj);
;

function printMe(person) 
  console.log(person.firstName, person.lastName);


const obj = 
  firstName: "John",
  lastName: "Wick"
;
<button id="btn">Click me!</button>

和/但这不是(我知道的时间死区)

printMe(obj);

function printMe(person) 
  console.log(person.firstName, person.lastName);


const obj = 
  firstName: "John",
  lastName: "Wick"
;

这和吊装有关系吗? 请推荐有关此主题的进一步阅读。

【问题讨论】:

嗯,它与提升非常切线相关。基本上,问题是您在obj 存在之前调用printMe,而在第一个示例中,您只会在单击按钮时调用该函数,这将在创建obj 之后。提升仅占printMe 存在,即使您在第二个 sn-p 中调用它之后定义了该函数。 “obj 被创建后会是什么”怎么回事? 您附加点击处理程序,然后创建对象。在完成这两个操作之前,用户不可能单击按钮,因此当他们这样做时,对象已创建,因此不会有任何问题。我正在起草一个更好的解释作为答案。 @d_oram - 怎么会这样? - 因为您不太可能在脚本运行完成之前单击该按钮。因此,脚本将完成,将对象放入内存。然后,最终,按钮将被按下。 printMe(obj); 替换为setTimeout(() => printMe(obj));。这与第一个示例的工作原因相同:您正在延迟对 printMe 的调用,直到对象 obj 被定义之后。 【参考方案1】:

首先,让我们快速检查一下吊装。这是一个简单的例子

sayHello();

function sayHello()  
  console.log("hello");

这是因为function sayHello()提升。本质上,它将被拉到文件的顶部,因此即使您在“之前”调用它,它仍然可以工作。 javascript 引擎基本上会做出如下的有效执行:

function sayHello()  
  console.log("hello");


sayHello();

因此,提升与在其他任何操作之前移动定义有关。

提升也适用于变量,但仅适用于定义

console.log(x, typeof x)

var x = "hello";

在这种情况下,它可能不像你最初期望的那样工作,但正如我所说,定义被提升了,但没有赋值。这是正在运行的有效代码:

var x;

console.log(x, typeof x);

x = "hello";

所以,这就是提升是什么以及它是如何工作的基础知识。还缺少一个难题来完全解释您的第二个 sn-p - 我确实故意使用了 var,因为它的工作方式与 letconst 声明不同。 The declaration is hoisted but the variable is not initialised before it reaches the let myVar line.。

到目前为止,我一直保持简单,但制作变量需要三个步骤

    声明,让 JavaScript 引擎知道变量 初始化 使变量可用 assignment 给它一个值。

这就是为什么变量myVarlet myVar 初始化它之前实际上不能被使用。这也将有助于揭开错误消息的神秘面纱:

console.log(myVar);

let myVar = "hello";

const 存在相同的行为。这就是 temporal deadzone is - 在“正式”声明之前尝试使用 letconst 定义的变量。

这将解释为什么您的第二个 sn-p 不起作用。我已经把相关的执行步骤放了:

printMe(obj); //2. printMe() is called which already exists due to hoisting. The code 
              // tries to pass in obj which is in a temporal dead zone, which leads to 
              // ReferenceError citing that reason

function printMe(person)  // 1. the function is hoisted, making it available to be called
  console.log(person.firstName, person.lastName);


const obj =  // 3. the definition of obj ends the temporal dead zone, so it can be used 
              //but this line is never reached.
  firstName: "John",
  lastName: "Wick"
;

至于您的第一个 sn-p,情况有所不同 - 函数 printMe() 仅在按下按钮时调用,然后才将 obj 传递给它,所以当用户可以点击时它,obj 将被定义并超出时间死区。如果我们简化并去掉事件处理程序的附加,有效的执行如下

function printMe(person)  //hoisted at the top
  console.log(person.firstName, person.lastName);

// obj exists in a temporal dead zone

const btn = document.getElementById("btn");

btn.onclick = function()  //the click handler is DEFINED but only when 
// it's executed will try to resolve either printMe() or obj
  printMe(obj);
;

const obj =  //end of the temporal deadzone for obj
  firstName: "John",
  lastName: "Wick"
;

btn.click(); // a user clicks -> both printMe and obj are available, so there is no ReferenceError
<button id="btn">Click me!</button>

【讨论】:

let and const are "hoisted" as well - 这就是你所说的“JavaScript 引擎知道 myVar 存在”的原因。 我在最初的版本中实际上有一个类似的句子,但后来修改它以避免一些混乱。如果您认为这是一个好主意,我会将其添加回来。 只需说“这两个在定义之前没有初始化”(而不是“它们没有被提升”)。顺便说一句,我也会用“声明”这个词来表示被提升的东西。 是的,就是最后一个例子! @Bergi 该死的,我现在明白你为什么反对了。不知何故,在编辑let and const are hoisted but differently 并转到let and const are not hoisted the same way 时,我最终得到了句子let and const are not hoisted。哎呀!无论如何,我决定在变量的生命周期中添加更多内容,因为它有助于解释错误消息,否则会有点神秘。【参考方案2】:

声明被提升,分配没有。因此,在第二个代码中,函数被提升和定义,同时调用 printMe(obj) 调用声明但 undefined 或而不是 unintialized 引用 obj 因此将导致 ReferenceError

在第一个示例中,您直到稍后(单击按钮)才调用函数,在此期间,所有内容都按预期声明和定义。

更多阅读:https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch4.md#chicken-or-the-egg

【讨论】:

以上是关于javascript基础知识-时间死区,提升或关闭[重复]的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript面试题总结系列

varlet 和 const 的区别以及暂时性死区

varlet 和 const 的区别以及暂时性死区

什么叫死区?设计电路时为什么要有死区?

变频器死区时间怎样测量

定义变量命令