学习JavaScript:词法范围与动态范围

学习JavaScript:词法范围与动态范围,javascript,lexical-scope,Javascript,Lexical Scope,所以我在读这本书,下面是代码示例,并使用节点控制台运行它们。在第7章“词汇与动态范围界定”一段中,作者声称以下代码将导致错误: const x = 3; function f() { console.log(x); // this will work console.log(y); // this will cause a crash } const y = 3; f(); 这是因为(如书中所述) JavaScript中的作用域是词汇性的 及 词法作用域是指定义函数的作用域中

所以我在读这本书,下面是代码示例,并使用节点控制台运行它们。在第7章“词汇与动态范围界定”一段中,作者声称以下代码将导致错误:

const x = 3;
function f() {
    console.log(x); // this will work
    console.log(y); // this will cause a crash
}

const y = 3;
f();
这是因为(如书中所述)

JavaScript中的作用域是词汇性的

词法作用域是指定义函数的作用域中的任何变量(与调用函数时相反)都在函数的作用域中

但是,此代码运行正常,并生成以下输出:

三,

三,


我已经搜索了词汇范围界定的其他例子及其含义,但它们似乎都暗示了与书中所说略有不同的东西。所以我想知道,书中的解释是完全错误的还是我遗漏了一些非常基本的东西?

引用的描述

词法作用域是指定义函数的作用域中的任何变量(与调用函数时相反)都在函数的作用域中

…是正确的

代码示例是错误的。函数
f
可以访问其声明范围内存在的任何变量(或常量)。这本书的错误之处在于,在声明函数之后,可以将常量添加到该作用域中


声明函数的位置很重要。当它被声明时,就没有那么多了。

上面的代码可以正常工作。然而,这将失败

const x = 3;
function f() {
    console.log(x); // this will work
    console.log(y); // this will cause a crash
}
f();
const y = 3;
这是因为在函数调用和

x
是可访问的,因为作用域是词法性的,如果在本地未找到,函数将访问在全局作用域中定义的
x

通过这个例子可以更清楚地理解这一点

function b(){
  console.log(v) //=> 1
} //lexically defined at global scope

function a(){
  var v = 2
  console.log(v) //=> 2
  b() //called in the scope of a()
}

var v = 1
a()
console.log(v) //=> 1
b()中的
console.log
将给出1,因为根据词法全局范围
v=1
。但是根据动态范围(由
a()
创建),它应该是2,而事实并非如此


希望这有帮助:)

这本书看起来很老了——11年前。世界已经不一样了。现在我们看到JavaScript日复一日地变化。我认为我们不应该使用两年前出版的任何书籍

您(和本书)提到的问题与另一个概念有关:严格模式。在ECMAScript 5中,可以通过在JavaScript文件顶部添加“use strict”来启用此模式。因此,您将看到一些错误在不处于常规模式时抛出。如果你想让示例工作,你可能需要找到一个旧的浏览器,IE8或类似的-我不确定,然后创建一个HTML文件,然后添加你的脚本,然后打开严格模式,它可能会给你与作者所说的相同的结果

严格模式在今天的JavaScript中已不再适用——我想谈谈ECMAScript 6、ES6或ECMAScript 2015。我们现在编写JavaScript时不需要关心严格模式。我在npmjs.org上有很多模块,但没有一个模块有“使用严格”的声明


只有我的两分钱:在编程方面,不要读旧书,因为一切都在快速变化。

你的代码很有效——我想你要找的术语是提升。我认为提升与此几乎没有关系。这本书还以一个完全不同的段落解释了提升。这个例子应该是为了理解词汇作用域而提供的。嘿,对不起,我的错,我无意中链接到了这本书的旧版本。我正在阅读2016年出版的第三版:好的,现在我需要看看剧本本身。我认为这没有问题。即使变量“y”在被引用后也被声明了,但是在JavaScript中有“提升效应”,它应该不会像作者所说的那样引起任何错误。即使在严格模式下,因为严格模式不能避免吊装。但是,在声明变量之前使用它是一种不好的做法。Linter的配置应该让开发人员注意到这一点。代码运行得非常好,问题是书中说它不应该。另外,我认为提升不适用于这个示例,
const
s和
let
s如果在声明之前使用,与
var
s相比,将导致错误。您好,您是对的,如果在声明
y
之前调用
f()
,将导致
ReferenceError
。这本书说,即使在声明了
y
之后调用
f()
也会产生错误,因为根据这本书,在声明了
f()
时,
y
没有。我倾向于认为这可能是最合理的解释,这本书包含了无数其他的小错误,因此作者也可能会犯错误。。。这对我来说似乎是一个重大错误,假设这个解释是正确的,这本书失去了很多可信度和尊重,因为作者甚至没有运行他的代码示例来检查它们是否正确。。。