前端学习笔记:JavaScript 的作用域

什么是作用域(scope)?

在JavaScript中,作用域(Scope)是一个控制变量和函数可见性的环境,通常是指代码的上下文(context)。它决定了变量、函数、对象等的生命周期,以及它们在代码中的可访问性。作用域通常分为全局作用域(Global)和局部作用域(Local)。

什么是全局作用域(Global)和局部作用域(Local)?

全局作用域(Global):

在浏览器中,JavaScript默认有一个全局对象window ,全局作用域的变量实际上被绑定到window的一个属性

在JavaScript中,全局作用域是指在整个代码中都可以访问的变量和函数。在全局作用域中定义的变量和函数可以被任何其他作用域访问。

举个栗子🌰:

javascript 复制代码
var message = "Hello, I am global!!";

function sayHello() {
  console.log(message);
}

sayHello(); // 输出:Hello, I am global!!

// 在浏览器环境下,也可以通过 window.message 访问
console.log('window.message: ', window.message); // window.message:  Hello, I am global!!

在上面的例子中,message变量和sayHello函数都是在全局作用域中声明的,你可以在代码中的任何地方访问它们,包括函数内部和其他作用域。
全局作用域的优势: 全局作用域中定义的变量和函数具有全局范围的可见性,可以在代码的任何地方使用,方便共享和重用**。
使用注意事项:

  1. 全局作用域中的变量可能会被其他代码意外修改,导致不可预料的结果。
  2. 避免滥用全局作用域,应尽量使用局部作用域来隔离变量和函数,以减少命名冲突和代码混乱的可能性。
  3. 全局作用域中的变量和函数会占用内存,并且在整个程序执行期间都存在,因此应注意控制全局作用域中的资源使用。

局部作用域(Local):

局部作用域是指在函数(特定代码块)内部声明的变量和函数,只能在该函数(特定代码块)内部访问。

函数作用域:

当一个函数被调用时,会创建一个新的作用域,并将该作用域添加到作用域链中。在函数内部声明的变量将分配在函数的局部作用域中,并成为该作用域的局部变量。这些变量只能在函数内部访问,而不能在函数外部访问。

举个栗子🌰:

scss 复制代码
function outerFunction () {
  var outerVariable = "I am outside!"; // 外部函数的局部变量  

  function innerFunction () {
    var innerVariable = "I am inside!"; // 内部函数的局部变量  

    console.log(outerVariable); // 可以访问外部函数的局部变量 => I am outside!

    console.log(innerVariable); // 只能在该内部函数内部访问 => I am inside!
  }
  innerFunction(); // 调用内部函数  

  // console.log(innerVariable); // ReferenceError: innerVariable is not defined 

}
outerFunction(); // 调用外部函数

console.log(outerVariable);  //  ReferenceError: outerVariable is not defined

在上面的例子中,outerVariableouterFunction的局部变量,只能在outerFunction内部访问。而innerVariable是内部函数innerFunction的局部变量,只能在innerFunction内部访问。通过这种方式,JavaScript实现了局部作用域的限制作用。

innerFunction 中,我们可以访问和使用 innerVariableouterVariable,因为内部函数可以访问外部函数中定义的变量。

但是,无法在 outerFunction 的外部访问 innerVariableouterVariable,因为它们只在函数的内部可见,即它们在局部作用域中。

块级作用域:

在ES6之前,早期的 JavaScript 版本中,只有函数作用域,也就是变量的作用域仅限于函数内部。从 ES6 开始引入了块级作用域,使用 let 和 const 关键字可以声明块级作用域的变量和常量。

块级作用域是由花括号 {} 包围的代码块。这些代码块可以是函数、if 语句、for 循环等。在块级作用域中声明的变量具有局部作用域,这意味着这些变量只能在该块内部访问。当离开该块时,这些变量将不再存在。

举个栗子🌰:

ini 复制代码
{
  let x = 10;
  const y = 20;

  console.log(x); // 输出:10
  console.log(y); // 输出:20

  {
    let z = 30;
    console.log(z); // 输出:30
  }

  console.log(z); // 报错:z is not defined
}

console.log(x); // 报错:x is not defined
console.log(y); // 报错:y is not defined

在上面的示例中,我们使用了两个代码块,每个代码块都有自己的块级作用域。在第一个代码块中,我们声明了变量 x 和常量 y,并且可以在该代码块内部访问它们。在第二个代码块中,我们声明了变量 z,并且只能在该代码块内部访问它。在代码块外部,我们无法访问任何在代码块内部声明的变量和常量。这展示了块级作用域的特点,变量和常量的作用范围被限制在当前的代码块内部。

一些作用域相关的知识扩展

1.什么是共有作用域和私有作用域?

在JavaScript中,共有作用域指的是全局作用域,而私有作用域则指的是函数作用域和块级作用域。

此外,在JavaScript中,闭包可以访问其外部函数的变量,这可以看作是共有作用域和私有作用域的一种特殊情况。闭包可以访问其外部函数的变量,但这些变量对外部是不可见的,因此它们仍然具有私有作用域的特性。

2.JavaScript 中的命名空间和作用域有什么不同?

命名空间是一种管理标识符(如类名、函数名和变量名)的方式,用来避免名称冲突。JavaScript里并不存在"命名空间"的概念。但由于JavaScript的所有对象都有自己的属性,这些属性又可以是对象,因此可以层层包装,从而创造出类似于其他语言中的命名空间的效果。

一个命名空间通常是一个包含一组相关属性和方法的对象,这样就可以将相关的功能组织在一起,并且不会与全局范围内的其他同名变量产生冲突。

举个栗子🌰:

javascript 复制代码
var myApp = {
    sayHello: function() {
        console.log("Hello!");
    },
    age: 20
};

myApp.sayHello(); // 输出 "Hello!"
console.log(myApp.age); // 输出 20

在上面的例子中,创建了一个名为"myApp"的命名空间,并将相关函数和变量添加到该命名空间中。

总结:命名空间是一种将代码组织成逻辑上相互隔离的容器的方法,可以使用对象来模拟命名空间。作用域决定了变量和函数的可见性和可访问性,可以通过函数和块级作用域来定义局部变量和函数。

3.词法作用域?

在JavaScript中,词法作用域是在代码编写阶段确定的作用域,与代码的执行过程无关。它是通过函数的嵌套关系来确定变量的可访问范围。这样可以更好地组织和管理代码,并避免命名冲突。词法作用域是一种静态作用域。

举个栗子🌰:

scss 复制代码
function outer() {
  var x = 10;
  
  function inner() {
    var y = 20;
    console.log(x); // 可以访问外部函数的变量 x
    console.log(y); // 可以访问自己的变量 y
  }
  
  inner();
}

outer();

在上面的例子中,inner 函数可以访问外部函数 outer 中定义的变量 x,但无法访问其他函数中定义的变量。

4.简述this 关键字,以及作用域对它有什么影响?

在JavaScript中,this 是一个特殊的变量,它引用了当前对象。其值取决于函数的调用方式和函数的作用域。

在全局作用域中,即在任何函数外部,this 指向全局对象(在浏览器中为window对象)。

  • 全局作用域或函数外部 :在全局作用域中,this 指向全局对象。在浏览器中,这通常是 window 对象。
  • 普通函数调用 :在普通函数调用时,this 指向全局对象。
  • 对象的方法 :当函数作为对象的方法被调用时,this 指向该对象。这意味着在方法内部,你可以通过 this 访问对象的属性和方法。
  • 构造函数 :当函数被用作构造函数(通过 new 关键字)时,this 指向新创建的对象实例。这允许你定义对象的属性和方法。
  • 事件监听器 :在事件监听器中,this 通常指向触发事件的元素。
  • 箭头函数 :箭头函数不绑定自己的 this,它继承自包围它的函数的 this。因此,箭头函数内部的 this 值取决于外层函数的作用域。
  • 函数调用方式 :除了上述几种情况外,还可以使用 call, apply, 和 bind 方法来显式设置函数的 this 值。
    总的来说,作用域对 this 的值具有重要影响,因为它决定了函数被调用时的上下文环境。在不同的作用域中,this 的值可能会有所不同,这取决于函数是如何被调用的。

5.JavaScript 中的 9 种作用域???

一种说法是:JavaScript 中并没有明确的9种作用域分类。关于"JS中的9种作用域"的说法可能源自对作用域概念的不同理解、不同的版本或者扩展讨论;以下是9种作用域的一个划分:

全局作用域(Global Scope)、函数作用域(Function Scope)、块级作用域(Block Scope)、模块作用域(Module Scope)、this 对象的作用域、with 语句的作用域、eval 函数的作用域、catch 语句的作用域、闭包作用域(Closure Scope)。

自我思考

1.为什么早期的 JavaScript 版本中,没有块级作用域?

  1. 在ES6之前,使用 var 声明的变量存在变量提升的特性。这意味着无论在哪里声明变量,它都会被提升到函数的顶部。这导致在代码块中声明的变量实际上被视为函数作用域的一部分,而不是块级作用域。

  2. 浏览器的 JavaScript 实现存在差异,特别是在处理块级作用域方面。引入块级作用域可能导致不同浏览器的行为不一致,这对于当时的互联网生态来说是个问题。为了保持兼容性,JavaScript 在早期没有引入块级作用域。

    举个栗子🌰:

scss 复制代码
function example() {
  if (true) {
    var x = 10;
  }
  console.log(x); // 输出:10
}

example();

在上面的例子中,变量 x 在 if 代码块中声明,但由于变量提升的特性,它被提升到了函数作用域的顶部,因此在函数内部任何地方都可以访问到它。

随着 ES6 规范的发布,JavaScript 引入了 let 和 const 关键字来声明块级作用域的变量和常量。这些关键字的引入解决了早期 JavaScript 版本中块级作用域的缺失问题,并且得到了现代浏览器的广泛支持。

2.简要说明ES6块级作用域的特点是什么?

块级作用域通过变量和常量在块级作用域中声明,只在所处于的块级有效,且没有变量提升的特性。

块级作用域有助于避免变量冲突,隐藏内部私有函数或变量,减少潜在的命名冲突,还有利于模块管理和内存回收。

3.什么是作用域链?

作用域链是JavaScript中决定变量查找顺序的机制,它是一个指向执行上下文层级结构的链式引用列表。当代码访问一个变量时,引擎会从当前作用域开始逐级向上搜索该变量,直到全局作用域为止。如果在链上找不到变量,则抛出错误。

小结

  • 本文主要总结了JavaScript中全局作用域(Global)和局部作用域(Local)一些基础概念和对应的案例演示,以及作用域相关的扩展知识。
  • 以上内容主要来于自己的对网上各种资料的一些学习总结,如果有什么错误或者不足之处,感谢欢迎各位大佬指导。
  • 如果本文对你有帮助,麻烦帮忙👍点赞支持下吧!~
相关推荐
勿语&25 分钟前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
黄尚圈圈27 分钟前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水1 小时前
简洁之道 - React Hook Form
前端
正小安3 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch5 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光5 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   5 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   5 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web5 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常5 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式