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
,因为它的工作方式与 let
和 const
声明不同。 The declaration is hoisted but the variable is not initialised before it reaches the let myVar
line.。
到目前为止,我一直保持简单,但制作变量需要三个步骤
-
声明,让 JavaScript 引擎知道变量
初始化 使变量可用
assignment 给它一个值。
这就是为什么变量myVar
在let myVar
初始化它之前实际上不能被使用。这也将有助于揭开错误消息的神秘面纱:
console.log(myVar);
let myVar = "hello";
const
存在相同的行为。这就是 temporal deadzone is - 在“正式”声明之前尝试使用 let
或 const
定义的变量。
这将解释为什么您的第二个 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基础知识-时间死区,提升或关闭[重复]的主要内容,如果未能解决你的问题,请参考以下文章