今日份学习,JavaScript中的作用域

首先得了解什么是JS引擎

JS引擎是执行 JavaScript 代码的程序或解释器,它负责将高级 JavaScript 代码转换为计算机能够理解的低级机器码。

通俗一点来讲,JS引擎就像一个翻译官,能够将你写的js代码翻译成计算机能够读懂的语言,这样计算机就能够按照你的意思去工作。

目前了解的两个主要的JS运行环境

  1. 浏览器
    浏览器中的JS引擎能够让网页实现各种交互效果,像点击按钮后弹出提示框,或者动态更新页面内容等。
  2. Node.js
    Node.js则可以执行后端代码,能够让JS脱离浏览器环境,在服务器端运行,比如搭建Web服务器,处理HTTP请求等。

JS引擎执行js代码的过程

  1. 词法分析 把代码拆解为一个个词法单元

词法单元:代码中最小的有意义的部分,比如:变量名,函数名,关键字,运算符等

js 复制代码
var a = 2//以下就是拆解后的词法单元
var
a
=
2
//空格在这里的作用是分隔`var`和`a`,属于分隔符,但在词法分析中通常不会被当作独立的词法单元保留,而是作为词法单元之间的边界标记。
  1. 语法分析 ---AST(抽象语法术)

    就是对上一步词法分析拆解的词法单元进行语法分析,分析它们都是干什么的,同时查找语法是否有问题

  2. 代码生成

    将AST转换为目标代码(会与源代码有差异,也就是进行了一些优化后的代码)

  3. 执行代码

S作用域

  1. 全局作用域
    最外层的作用域,声明在函数和代码块之外
  2. 函数作用域
    在函数内部声明的作用域,也就是在函数内部声明的变量,只能在函数内部生效
  3. 块级作用域
    前提是由{}包裹的代码块,其次是还要使用let 和 const声明的变量,才能够形成块级作用域,这两者缺一不可

特殊点:即使有{}包裹,但是用var进行变量声明,这形成不了块级作用域,该变量还是可以被外部作用域访问

js 复制代码
var a = 10;//属于全局作用域
console.log(a);//在全局中查找a     
//输出结果:10
function foo(a, b) {
    {
        let a = 10//属于块级作用域
        const b = 10//属于块级作用域
        console.log(a + b);//在块级作用域内查找a和b  
        //输出结果:20
    }
    console.log(a + b);////属于函数作用域,在函数作用域内查找a和b的值,也就是传进来的两个参数a,b,不能用块级作用域内的a,b 
    //输出结果:3
}
foo(1, 2)

作用域查找规则

  1. 先在当前作用域中查找,找得到就返回,找不到就去外层作用域查找
  2. 只能从内到外查找,不能从外到内查找

(比如:在当前函数作用域内找到你想要的变量a你就可以去该函数的外层作用域内找你想要的变量a但如果反过来,外层作用域想要用变量a,但外层没有,而函数作用域内有,这时,就不能由外向内层进行查找了)

js 复制代码
var a = 10;
function foo(b) {
    {
        const b = 10
        console.log(a + b);//在块级作用域内又b直接用,但是没有a,则向外层作用域找,也就是函数foo的作用域,也没有就再去外层作用域,也就是全局作用域内找到a=10
        //输出结果:20
    }
    function bar() {
        console.log(a + b);//在函数bar内部都没有a,b,则向外层的函数foo的作用域内找,b=2,a没找到,再去外层作用域,也就是全局作用域内找到a=10
        //输出结果:12
    }
    bar()
}
foo(2)
console.log(a + b);//全局作用域尝试访问变量b,但全局没有定义b,且作用域查找不能从外向内,因此报错`b is not defined`

let const 和var的区别

  1. let,const 声明的变量不存在声明提升(会形成暂时性死区),var存在(var可提升并初始化为 undefined,let和const提升但不初始化)
js 复制代码
console.log(a); // undefined (var提升)先进行var a变量的声明,后再进行赋值,所以在执行前,就已经声明了变量a,只是没有赋值,所以输出undefind
var a = 1;
//暂时性死区
console.log(b); // ReferenceError 报错
let b = 2;
//暂时性死区
console.log(c); // ReferenceError 报错
const c = 3;
  1. let,const 声明的变量不能重复声明
js 复制代码
var d = 4;
var d = 5; // 允许

let e = 6; 
let e = 7; // 语法错误:Identifier 'e' has already been declared

const f = 8;
const f = 9; // 不允许
  1. var 声明的全局变量会挂载到window上,let和const不会
js 复制代码
var j = 16;
console.log(window.j); // 16 (浏览器环境,非node.js环境)

let k = 17;
console.log(window.k); // undefined

const l = 18;
console.log(window.l); // undefined
  1. consyt 声明的变量 值不能修改,let可以
js 复制代码
var g = 10;
g = 11; // 允许

let h = 12;
h = 13; // 允许

const i = 14;
i = 15; // 不允许
  1. const的特殊特性:基本类型值不能修改,但引用类型,引用地址不能修改,但内容可以修改,且必须初始化
js 复制代码
// 基本类型:值不可变
const PI = 3.14;
PI = 3.14159; // TypeError

// 引用类型:引用不可变,内容可变
const person = { name: 'Alice' }; 
person.name = 'Bob'; // 允许修改对象属性 
console.log(person); // { name: 'Bob' } 
// 尝试重新赋值整个对象会报错 
person = { name: 'Charlie' }; // TypeError: Assignment to constant variable

// 必须初始化
const NAME; //SyntaxError: Missing initializer

默认使用 const

当变量不需要重新赋值时

减少意外修改的风险
需要重新赋值时使用 let

扩展----欺骗词法

  1. with
    with的作用是什么?
    with的主要作用就是将对象中的值进行批量修改,但同时存在一个风险

在对对象属性进行修改时,如果对象中没有该属性,会导致该属性泄露到了全局

js 复制代码
var o1 = { a: 1 }; 
var o2 = { b: 2 }; 
function foo(obj) { 
    with (obj) {
        a = 2; // 由于o2没有a属性,会泄漏到全局作用域 
        } 
     } 
foo(o2); 
console.log(a); // 输出2(全局变量被隐式创建) console.log(o1); // 输出{a: 1}(o1未被修改)
  1. eval ---将本不属于当前作用域的代码,强行添加到当前作用域中执行
    eval的作用是什么?
    eval() 是 JavaScript 中的一个全局函数,用于将字符串作为 JavaScript 代码执行
js 复制代码
function foo(str){
    eval(str)  //eval会直接将str字符串当作var a=10的变量声明和赋值来执行
    console.log(a,b);//因为eval的缘故,在函数作用域内多了a的声明和赋值
    //输出结果:10,2
}
var b=2
foo('var a=10')
相关推荐
挽淚几秒前
JavaScript 数组详解:从入门到精通
javascript
言兴1 分钟前
教你如何理解useContext加上useReducer
前端·javascript·面试
sunbyte5 分钟前
50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | GoodCheapFast(Good - Cheap - Fast三选二开关)
前端·javascript·css·vue.js·tailwindcss
南篱13 分钟前
JavaScript 中的 this 关键字:从迷惑到精通
javascript
coding随想40 分钟前
掌控网页的魔法之书:JavaScript DOM的奇幻之旅
开发语言·javascript·ecmascript
然我1 小时前
不用 Redux 也能全局状态管理?看我用 useReducer+Context 搞个 Todo 应用
前端·javascript·react.js
前端小巷子1 小时前
Web 实时通信:从短轮询到 WebSocket
前端·javascript·面试
DanB242 小时前
html复习
javascript·microsoft·html
呼啦啦呼啦啦啦啦啦啦8 小时前
利用pdfjs实现的pdf预览简单demo(包含翻页功能)
android·javascript·pdf
前端 贾公子10 小时前
vue-cli 模式下安装 uni-ui
前端·javascript·windows