走进 JavaScript 作用域迷宫,领略语言的逻辑之美

在编程的浩瀚星海中,JavaScript(简称JS)以其独特魅力和无尽的灵活性,成为了连接创意与现实的桥梁。它不仅仅是一门语言,更是一种艺术,一种让想法跃动于屏幕之上的魔法。今天,我们启程深入JS的内心世界,从基础的数据类型出发,逐步踏入作用域的神秘殿堂,揭示那些构成其表达力与功能性的核心要素。

数据类型的万花筒

在JS的调色板上,数据类型是绘梦的颜料,分为原始类型(基本类型)、引用类型(复杂类型)两大类。

  • 原始类型 包括数字(Number)、字符串(String)、布尔值(Boolean)、nullundefined和Symbol(ES6引入)。这些类型的数据存储简单值,直接保存在变量中,复制时会产生完全独立的副本。
js 复制代码
var str = 'hello world' //字符型
var num = 123 //数字
var flag = true //boolean
var u = undefined
var u null 
  • 引用类型,如对象(Object)、数组(Array)、函数(Function)等,存储的是指向对象内存地址的引用。复制这类变量时,实际上是复制了引用而非对象本身,因此多个变量可能指向同一块内存,修改其中一个会影响其他。
js 复制代码
var obj = {} // 对象
var arr = {} // 数组
var fn = function() {} //函数

编译的交响曲

虽然JS是一门解释型语言,但理解编译过程对于把握其运行机制至关重要。尽管没有传统意义上的编译步骤,但现代引擎如V8采用即时编译(JIT)技术,大致经历以下几个阶段:

  1. 解析:将源代码转换为解析树,这一步骤类似于词法分析和语法分析的结合,快速识别并理解代码结构。
  2. 字节码生成:将解析树转换为字节码,这是一种低级的中间表示形式,易于快速执行。
  3. 优化:基于代码的实际运行情况动态优化字节码,甚至直接生成机器代码,提高执行效率。
js 复制代码
var a = 123 //先加载到 var,a和123 再进行解析 最后编译成 var a = 123
console.log(a) //执行

作用域的迷宫

作用域是JS中变量与函数的生存空间,其规则塑造了代码的行为逻辑。

  • 全局作用域:所有部分都能访问到的变量、函数或对象的作用范围。
  • 函数作用域:函数内部声明的变量仅在该函数内部有效。
  • 块作用域 (ES6新特性):通过letconst声明的变量,在特定代码块(例如if、for、while或者花括号 {} 内)的作用范围,出了这个块就无法访问。增强了局部控制和代码的清晰度。
  • 不过我们在使用let或者const时也会出现如下特殊情况 形成暂时性死区
js 复制代码
let a = 1
{console.log(a)//输出的结果是Cannot access 'a' before initialization
    let a = 1// 暂时性死区
}

词法作用域的法则

词法作用域在代码编写时就已经确定,由变量在源代码中的物理位置决定。这意味着内部作用域可以(向下)访问外部作用域的变量 ,而外部作用域无法(向上)穿透内部作用域

js 复制代码
var a = 1  //全局变量   
function foo() {
    var a = 2
}
foo()
console.log(a)//打印出的结果会是1

挑战词法作用域的魔术师

  • eval() :让原本不属于这里的代码,变得好像天生就定义在了这里一样。
js 复制代码
function foo(a, str) {
    eval(str)  //var b = 2  欺骗词法作用域
    console.log(a, b); //输出的结果是1,2

}
foo(1,'var b = 2')
  • with() {}:当修改对象中不存在的属性时,这个属性会被泄露到全局,变成全局变量 我们可以通过以下代码来理解
js 复制代码
function foo(obj) {
        a = 2
}
var o1 = {
    a: 1
}
foo(o1)
console.log(o1) //输出的结果是a : 1

但当使用with如下

js 复制代码
function foo(obj) {
    with(obj) {//with 修改了作用域链,导致变量a指向的是window.a而不是o1.a
        a = 2
    } 
}
var o1 = {
    a: 1
}
foo(o1)
console.log(o1) //输出的结果是a : 2

var与let的对决

  • var 的声明有变量提升特性,可能导致变量在声明之前就被访问,且在全局作用域中绑定到window对象,增加了命名冲突的风险。
javascript 复制代码
console.log(myVar); // 输出: undefined,而不是报错,说明变量提升了
var myVar = "Hello, world!"; // 变量声明及赋值

// 即使在函数内部使用 var 声明,该变量也会绑定到全局对象
function testFunction() {
    var anotherVar = "I'm also global";
}
8testFunction();
9console.log(window.anotherVar); // 输出: "I'm also global",表明 anotherVar 成为了全局对象的属性
  • let 则引入了真正的块级作用域,解决了var的许多问题,如循环变量闭包问题,以及提供了更清晰的作用域管理。

块级作用域的守护者

letconst的出现,为JS引入了严格而清晰的块级作用域概念,使得变量的生命周期更加可控,减少了作用域污染,提升了代码的健壮性和可维护性。

const的'永恒'誓约

尽管名为"常量",const确保的只是变量引用的不可变性。对于基本类型,值确实不可更改;但对于对象或数组,尽管变量引用不可变,但其内容仍可被修改。

综上所述,JavaScript的世界里,作用域与数据类型是构建程序逻辑的基石,而对它们的深入理解,是每一位JS艺术家通往卓越之路的必修课。通过这次探索,我们不仅见识了JS的表层魅力,更窥见了其背后的逻辑之美与设计哲学。在接下来的创作与实践中,愿这些知识成为你手中的画笔,绘制出更加绚丽多彩的数字画卷。

相关推荐
正小安1 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch3 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光3 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   3 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   3 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web3 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常3 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇4 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr4 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho5 小时前
【TypeScript】知识点梳理(三)
前端·typescript