'Hoisted' JavaScript 变量
'Hoisted' JavaScript Variables
我不完全明白为什么下面的结尾显示 "hoisted"。
var x = 'set';
var y = function ()
{
// WHAT YOU DON'T SEE -> var x;
// is effectively "hoisted" to this line!
if (!x)
{
// You might expect the variable to be populated at this point...it is not
// though, so this block executes
var x = 'hoisted';
}
alert(x);
}
//... and this call causes an alert to display "hoisted"
y();
如有指点,将不胜感激。
变量声明提升到范围的顶部。所以你的代码等同于:
var x = 'set';
var y = function () {
var x;
if (!x) {
x = 'hoisted';
}
alert(x);
}
y();
当执行 y
时,var x
隐藏外部作用域 x
所以 y
函数内部 x
是 undefined
之后第一行声明。
Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.
因此,在您的情况下,JavaScript 知道 一个局部变量(不是在外部声明的变量) x
在函数的某处定义,但它不知道它的实际值,直到执行到赋值给 x
的赋值语句。 (声明在编译时处理,赋值在执行时完成) 直到赋值完成,将使用默认值undefined
。由于undefined
is falsy,条件
if (!x) {
满足,执行赋值语句。这就是为什么您会在警告框中看到 hoisted
。
假设您没有在函数内部声明 x
,
var x;
var y = function () {
if (!x) {
x = 'hoisted';
}
alert(x);
}
y();
alert(x);
这里,由于 x
没有在函数内的任何地方声明,在运行时,JavaScript 将在更高的范围内寻找 x
。在这种情况下,它会在函数外部找到它。因此,将使用 x
。由于您将 hoisted
分配给 x
,因此内部 alert
也会说 hoisted
并且在离开函数后, alert(x)
也会提醒 hoisted
。
this answer非常详细的解释了变量的不同作用域。在您的特定情况下,您可以使用对以下内容的引用:
this.x;
在函数外访问全局x变量。因为在函数内部你试图访问一个未定义的变量,所以使用 this
关键字你引用了函数外部的变量。
以及
的部分
if(!x)
这是真的,因为你正在测试:is false
和x
在那一点是undefined
因为不存在于函数范围内,而undefined
是考虑一个JS 中的错误值,了解更多信息 please take a look here.
In javascript console.log 在函数内部给出未定义的作为未传递参数的输出,但在函数外部它给出未定义的错误,因为在函数内部浏览器显式声明了变量。例如
console.log(x)
给出 VM1533:1 未捕获的引用错误:x 未定义而
function test(x) {
console.log(x)
}
test();
未定义。
这是因为函数test()被浏览器重写为:
function test(x) {
var x;
console.log(x)
}
另一个例子:-
var x =5 ;
function test(x) {
console.log(x)
}
test();
仍未定义,因为函数变为
function test(x) {
var x;
console.log(x)
}
下面示例中的警报将给出 undefined :-
var x =5;
function test() {
alert(x);
var x =10;
}
test();
上面的函数会变成:-
function test() {
var x;
alert(x);
x =10;
}
函数中javascript变量的作用域是函数级作用域,而不是块级作用域。例如
function varScope() {
for(var i = 0; i < 10; i++){
for(var j = 0; j < 5; j++){}
console.log("j is "+j)
}
console.log("i is "+i);
}
varScope();
将输出为:
j is 5
i is 10
函数又变成了:-
function varScope() {
var i;
var j;
for(i = 0; i < 10; i++){
for(j = 0; j < 5; j++){}
console.log("j is "+j)
}
console.log("i is "+i);
}
使用此关键字有助于在已提升的函数外部引用变量。
你的情况
this.x
更新:
从 ES2015 开始,使用 const 和 let 关键字使得变量不会被提升。
示例:在函数中提升全局变量
var x = "global variable hoisted";
function check_hoisting(){
alert(x); //undefined because of js hoisting
var x = "local variable";
}
check_hoisting();
示例:由于 let 关键字而未提升变量
let x = "global variable not hoisted";
function check_hoisting(){
alert(x);
var x = "local variable";
}
check_hoisting();
JavaScript 只提升声明,不提升初始化。
作为一名新程序员,无论我在这个问题或类似问题中阅读了多少答案,我都无法找到解决这个问题的方法。因此,我将我的解决方案分享给像我一样从绝望的搜索中来到这里的其他人(加上所有寻找修复的相关问题都已锁定并且 link 到这个问题)。所以这是对你问题的回答,像我这样的新手可以理解如何以及为什么要更改我们的代码来避免这个问题,并让变量 return 成为我们期望的值。我的问题是,在学习 javascript 时,我假设每次我想修改一个变量时,我都必须以 var
开头,例如:
var myVariable = 1;
...
var myVariable = myVariable + 3;
实际上,您应该只在第一次输入 var
(当您 declare/initialize 一个变量时)。此后的所有其他时间,您必须以变量名开始该行并删除 var
如:
var myVariable = 1;
...
myVariable = myVariable + 3;
起初我没有发现我的做法有问题,直到我开始使用更多功能,然后这些提升问题开始出现,我不明白为什么,我只是假设我不能'跨函数使用相同的变量名,或者我无法引用同一个函数之外的变量,或者我不得不使用一些奇怪的方法强制 creation/using 全局变量,比如 this.variable 或 window.variable,或其他奇怪的东西。
在我删除所有 var
除了每个变量的第一个位置之后,我的问题就消失了。
同样的事情也适用于您的代码。如果你改变这个:
var x = 'set';
var y = function ()
{
if (!x)
{
var x = 'hoisted';
}
alert(x);
}
y();
(将 var x = 'hoisted';
更改为 x = 'hoisted';
)为此:
var x = 'set';
var y = function ()
{
if (!x)
{
x = 'hoisted';
}
alert(x);
}
y();
然后它会如您所愿地工作,并且避免提升。
我不完全明白为什么下面的结尾显示 "hoisted"。
var x = 'set';
var y = function ()
{
// WHAT YOU DON'T SEE -> var x;
// is effectively "hoisted" to this line!
if (!x)
{
// You might expect the variable to be populated at this point...it is not
// though, so this block executes
var x = 'hoisted';
}
alert(x);
}
//... and this call causes an alert to display "hoisted"
y();
如有指点,将不胜感激。
变量声明提升到范围的顶部。所以你的代码等同于:
var x = 'set';
var y = function () {
var x;
if (!x) {
x = 'hoisted';
}
alert(x);
}
y();
当执行 y
时,var x
隐藏外部作用域 x
所以 y
函数内部 x
是 undefined
之后第一行声明。
Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.
因此,在您的情况下,JavaScript 知道 一个局部变量(不是在外部声明的变量) x
在函数的某处定义,但它不知道它的实际值,直到执行到赋值给 x
的赋值语句。 (声明在编译时处理,赋值在执行时完成) 直到赋值完成,将使用默认值undefined
。由于undefined
is falsy,条件
if (!x) {
满足,执行赋值语句。这就是为什么您会在警告框中看到 hoisted
。
假设您没有在函数内部声明 x
,
var x;
var y = function () {
if (!x) {
x = 'hoisted';
}
alert(x);
}
y();
alert(x);
这里,由于 x
没有在函数内的任何地方声明,在运行时,JavaScript 将在更高的范围内寻找 x
。在这种情况下,它会在函数外部找到它。因此,将使用 x
。由于您将 hoisted
分配给 x
,因此内部 alert
也会说 hoisted
并且在离开函数后, alert(x)
也会提醒 hoisted
。
this answer非常详细的解释了变量的不同作用域。在您的特定情况下,您可以使用对以下内容的引用:
this.x;
在函数外访问全局x变量。因为在函数内部你试图访问一个未定义的变量,所以使用 this
关键字你引用了函数外部的变量。
以及
的部分if(!x)
这是真的,因为你正在测试:is false
和x
在那一点是undefined
因为不存在于函数范围内,而undefined
是考虑一个JS 中的错误值,了解更多信息 please take a look here.
In javascript console.log 在函数内部给出未定义的作为未传递参数的输出,但在函数外部它给出未定义的错误,因为在函数内部浏览器显式声明了变量。例如
console.log(x)
给出 VM1533:1 未捕获的引用错误:x 未定义而
function test(x) {
console.log(x)
}
test();
未定义。 这是因为函数test()被浏览器重写为:
function test(x) {
var x;
console.log(x)
}
另一个例子:-
var x =5 ;
function test(x) {
console.log(x)
}
test();
仍未定义,因为函数变为
function test(x) {
var x;
console.log(x)
}
下面示例中的警报将给出 undefined :-
var x =5;
function test() {
alert(x);
var x =10;
}
test();
上面的函数会变成:-
function test() {
var x;
alert(x);
x =10;
}
函数中javascript变量的作用域是函数级作用域,而不是块级作用域。例如
function varScope() {
for(var i = 0; i < 10; i++){
for(var j = 0; j < 5; j++){}
console.log("j is "+j)
}
console.log("i is "+i);
}
varScope();
将输出为:
j is 5
i is 10
函数又变成了:-
function varScope() {
var i;
var j;
for(i = 0; i < 10; i++){
for(j = 0; j < 5; j++){}
console.log("j is "+j)
}
console.log("i is "+i);
}
使用此关键字有助于在已提升的函数外部引用变量。 你的情况
this.x
更新: 从 ES2015 开始,使用 const 和 let 关键字使得变量不会被提升。
示例:在函数中提升全局变量
var x = "global variable hoisted";
function check_hoisting(){
alert(x); //undefined because of js hoisting
var x = "local variable";
}
check_hoisting();
示例:由于 let 关键字而未提升变量
let x = "global variable not hoisted";
function check_hoisting(){
alert(x);
var x = "local variable";
}
check_hoisting();
JavaScript 只提升声明,不提升初始化。
作为一名新程序员,无论我在这个问题或类似问题中阅读了多少答案,我都无法找到解决这个问题的方法。因此,我将我的解决方案分享给像我一样从绝望的搜索中来到这里的其他人(加上所有寻找修复的相关问题都已锁定并且 link 到这个问题)。所以这是对你问题的回答,像我这样的新手可以理解如何以及为什么要更改我们的代码来避免这个问题,并让变量 return 成为我们期望的值。我的问题是,在学习 javascript 时,我假设每次我想修改一个变量时,我都必须以 var
开头,例如:
var myVariable = 1;
...
var myVariable = myVariable + 3;
实际上,您应该只在第一次输入 var
(当您 declare/initialize 一个变量时)。此后的所有其他时间,您必须以变量名开始该行并删除 var
如:
var myVariable = 1;
...
myVariable = myVariable + 3;
起初我没有发现我的做法有问题,直到我开始使用更多功能,然后这些提升问题开始出现,我不明白为什么,我只是假设我不能'跨函数使用相同的变量名,或者我无法引用同一个函数之外的变量,或者我不得不使用一些奇怪的方法强制 creation/using 全局变量,比如 this.variable 或 window.variable,或其他奇怪的东西。
在我删除所有 var
除了每个变量的第一个位置之后,我的问题就消失了。
同样的事情也适用于您的代码。如果你改变这个:
var x = 'set';
var y = function ()
{
if (!x)
{
var x = 'hoisted';
}
alert(x);
}
y();
(将 var x = 'hoisted';
更改为 x = 'hoisted';
)为此:
var x = 'set';
var y = function ()
{
if (!x)
{
x = 'hoisted';
}
alert(x);
}
y();
然后它会如您所愿地工作,并且避免提升。