作用域(scope) 是指变量的可访问性,上下文(context)是指 this 在同一作用域内的值。

1. 作用域(Scope)

1. 什么是作用域?

作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。

2. 作用域是最小的访问单元

为什么要限制变量的可见性呢,为什么你的变量不是在代码的任何地方都可用呢?一个优点是作用域为您的代码提供了一定程度的安全性。计算机安全的一个常见原则是用户应该一次只能访问他们需要的东西。

想象一下计算机管理员。由于他们对公司的系统有很多控制权限,因此向他们授予超级管理员权限就好了。他们都可以完全访问系统,一切工作顺利。但突然发生了一些坏事,你的系统感染了恶意病毒。现在你不知道谁犯的错误?你意识到应该授予普通用户权限,并且只在需要时授予超级访问权限。这将帮助您跟踪更改,并记录谁拥有什么帐户。这被称为最小访问原则。看起来很直观?这个原则也适用于编程语言设计,在大多数编程语言中被称为作用域,包括我们接下来要研究的 JavaScript 。

当你继续在你的编程旅程,您将意识到,您的代码的作用域有助于提高效率,帮助跟踪错误并修复它们。作用域还解决了命名问题,在不同作用域中变量名称可以相同。记住不要将作用域与上下文混淆。它们的特性不同。

3. JavaScript中的作用域

在JavaScript中有两种作用域:

  • 全局作用域

  • 局部作用域

定义在函数内部的变量具有局部作用域,而定义在函数外部的变量具有全局范围内。每个函数在被调用时都会创建一个新的作用域。

3.1 全局作用域

当您开始在文档中编写JavaScript时,您已经在全局作用域中了。全局作用域贯穿整个javascript文档。如果变量在函数之外定义,则变量处于全局作用域内

  1. // 默认全局作用域
  2. var name = 'Hammad';

在全局作用域内的变量可以在任何其他作用域内访问和修改。

  1. var name = 'Hammad';
  2. console.log(name); // logs 'Hammad'
  3. function logName() {
  4. console.log(name); // 'name' 可以在这里和其他任何地方被访问
  5. }
  6. logName(); // logs 'Hammad'

3.2 局部作用域

函数内定义的变量在局部(本地)作用域中。而且个函数被调用时都具有不同的作用域。这意味着具有相同名称的变量可以在不同的函数中使用。这是因为这些变量被绑定到它们各自具有不同作用域的相应函数,并且在其他函数中不可访问。

  1. // Global Scope
  2. function someFunction() {
  3. // Local Scope #1
  4. function someOtherFunction() {
  5. // Local Scope #2
  6. }
  7. }
  8. // Global Scope
  9. function anotherFunction() {
  10. // Local Scope #3
  11. }
  12. // Global Scope

快语句

块语句,如 ifswitch 条件语句或 forwhile 循环语句,不像函数,它们不会创建一个新的作用域。在块语句中定义的变量将保留在它们已经存在的作用域中。

  1. if (true) {
  2. // 'if' 条件语句块不会创建一个新的作用域
  3. var name = 'Hammad'; // name 依然在全局作用域中
  4. }
  5. console.log(name); // logs 'Hammad'

ECMAScript 6 引入了 letconst 关键字。可以使用这些关键字来代替 var 关键字。

  1. var name = 'Hammad';
  2. let likes = 'Coding';
  3. const skills = 'Javascript and PHP';

var 关键字相反,letconst 关键字支持在局部(本地)作用域的块语句中声明。

  1. if (true) {
  2. // 'if' 条件语句块不会创建一个新的作用域
  3. // name 在全局作用域中,因为通过 'var' 关键字定义
  4. var name = 'Hammad';
  5. // likes 在局部(本地)作用域中,因为通过 'let' 关键字定义
  6. let likes = 'Coding';
  7. // skills 在局部(本地)作用域中,因为通过 'const' 关键字定义
  8. const skills = 'JavaScript and PHP';
  9. }
  10. console.log(name); // logs 'Hammad'
  11. console.log(likes); // Uncaught ReferenceError: likes is not defined
  12. console.log(skills); // Uncaught ReferenceError: skills is not defined

只要您的应用程序活,全局作用域就会生存。 只要您的函数被调用并执行,局部(本地)作用域才会存在。

上下文(context)

1. 上下文的指代

上下文(context)是用来指定代码某些特定部分中 this 的值。

在浏览器中在全局作用域(scope)中 上下文 中始终是Window对象。
在Node.js中在全局作用域(scope)中 上下文 中始终是Global 对象)

  1. console.log(this); // logs: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage…}
  2. function logFunction() {
  3. console.log(this);
  4. }
  5. logFunction(); // logs: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage…}
  6. // 因为 logFunction() 不是一个对象的属性

如果作用域在对象的方法中,则上下文将是该方法所属的对象。

  1. class User {
  2. logName() {
  3. console.log(this);
  4. }
  5. }
  6. (new User).logName(); // logs User {}

(new User).logName() 是一种将对象存储在变量中然后调用logName函数的简单方法。在这里,不需要创建一个新的变量。
如果使用 new 关键字调用函数,则上下文的值会有所不同。然后将上下文设置为被调用函数的实例。考虑上面的示例,通过 new关键字调用的函数。

  1. function logFunction() {
  2. console.log(this);
  3. }
  4. new logFunction(); // logs logFunction {}

当在严格模式(Strict Mode)中调用函数时,上下文将默认为 undefined

2. 执行期上下文