1.10 作用域链
- 定义:
| 作用域链:查找变量的过程 |
| 作用: 查找变量 |
| 查找规则:首先会在自身作用域找变量,找到就用 |
| 如果没有,就去上级作用域查找,找到就用 |
| 如果没有,一直往上找,直到全局作用域,有就用,没有就报错 |
| |
| 作用域是一个相对概念 |
| 作用域的顶端一定是全局作用域 |
| 作用域是函数声明的时候确定的,作用域链是函数调用的时候有的,不调用不存在 |
| |
| 作用域是虚拟的 |
| 作用域链是可见的 |
- 案例
| var a = 0; |
| function fn1() { |
| var a = 1; |
| function fn2() { |
| var a = 2; |
| function fn3() { |
| var a = 3; |
| console.log(a); |
| } |
| fn3(); |
| } |
| fn2(); |
| } |
| fn1(); |
- 案例(说明作用域是在函数声明的时候确定的)
| var num = 10; |
| function fun() { |
| var num = 20; |
| fun2(); |
| } |
| function fun2() { |
| console.log(num); |
| } |
| fun(); |
1.11 预解析(变量提升,代码提升)
- 定义
| 预解析对象:①带var的变量 ②函数声明定义的函数 |
| 预解析发生时间:在js代码开始执行之前 |
| |
| 规则: |
| 1.先预解析函数声明定义的函数, |
| 如果提升的时候发现函数同名,后面的函数会覆盖前面的函数 |
| 函数提升的时候整体提升 |
| 2.再去提升带var的变量,提升变量的时候变量同名,会忽略, |
| 只提升变量名(var a),变量的值是不会提升的 |
| 3.函数表达式定义的函数,预解析规则按照带var的变量对待 |
| var fun1 = function(){} |
| 4.不带var的变量,不做预解析 |
| 5.函数内部也会做预解析 |
| |
| ☆☆☆预解析完成的代码 一行一行从上至下去执行!!! |
- 案例题
| console.log(a); |
| a = 0; |
| |
| -------------------------------------------------------- |
| 提升前 |
| console.log(a); |
| var a = 0; |
| console.log(a); |
| 提升后 |
| var a; |
| console.log(a); |
| a = 0; |
| console.log(a); |
| |
| -------------------------------------------------------- |
| 提升前 |
| console.log(a); |
| var a = '我是变量'; |
| function a() { console.log('我是函数') } |
| console.log(a); |
| |
| 提升后 |
| function a() { console.log('我是函数') } |
| |
| console.log(a); |
| a = '我是变量'; |
| console.log(a); |
| |
| -------------------------------------------------------- |
| 提升前 |
| console.log(a()); |
| var a = '我是变量'; |
| function a() { console.log('我是函数') } |
| console.log(a); |
| |
| 提升后 |
| function a() { console.log('我是函数') } |
| |
| console.log(a()); |
| a = '我是变量'; |
| console.log(a); |
| |
| -------------------------------------------------------- |
| 提升前 |
| console.log(a); |
| var a = 0; |
| console.log(a); |
| function fn() { |
| console.log(a); |
| var a = 1; |
| console.log(a); |
| } |
| fn() |
| console.log(a); |
| |
| 提升后 |
| function fn() { |
| var a; |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| var a; |
| console.log(a); |
| a = 0; |
| console.log(a); |
| fn(); |
| console.log(a); |
| |
| -------------------------------------------------------- |
| 提升前 |
| console.log(a); |
| var a = 0; |
| console.log(a); |
| function fn() { |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| fn() |
| console.log(a); |
| |
| 提升后 |
| function fn() { |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| var a; |
| console.log(a); |
| a = 0; |
| console.log(a); |
| fn() |
| console.log(a); |
| |
| -------------------------------------------------------- |
| 提升前 |
| console.log(a); |
| var a = 0; |
| console.log(a); |
| function fn() { |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| fn() |
| function fn() { |
| console.log(a); |
| var a = 1; |
| console.log(a); |
| } |
| |
| var fn = function () { |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| fn(); |
| var a = 100; |
| console.log(a); |
| |
| 提升后 |
| function fn() { |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| function fn() { |
| var a; |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| var a |
| console.log(a); |
| a = 0; |
| console.log(a); |
| fn(); |
| fn = function () { |
| console.log(a); |
| a = 1; |
| console.log(a); |
| } |
| fn(); |
| a = 100; |
| console.log(a); |
| |
| |
1.12 js中的堆内存和栈内存
- 定义
| 1. js代码,首先会创建全局执行上下文环境 |
| 2. 只要函数调用 不管几次 每一个都会创建执行上下文环境 |
| 3. 基本数据类型变量名和值都放在栈内存当中 |
| 4. 对象数据类型(数组 函数 对象)在栈内存中存储的是地址,数据存储在堆内存当中 |
- 程序开始到结束的整个流程
| 1、程序一开始执行,碰见了全局环境,首先会创建全局环境并且进行压栈,全局代码执行的时候依赖的就是全局环境当中的东西;比如 全局变量(全局变量如果存的是基本数据类型,那么这个值是直接存在栈当中的,如果这个变量存的是对象类型(函数、数组),那么数据是要在堆内存当中开辟自己的空间专门存储的。然后把堆里面这块空间的地址存给栈当中的对应变量); |
| 2、当程序执行碰到了函数调用;函数是比较特殊,因为它也可以执行;函数执行的时候也要有自己的环境去依赖。因此函数执行也是创建自己的函数环境进行压栈(函数环境一定是压在全局环境之上的),局部变量,是在函数环境当中存在的,只有函数执行,局部变量才会出现。函数执行完成以后,函数环境要弹出栈(销毁归还内存), 局部变量也就不复存在了。 |
| 3、当函数调用完成以后,会继续执行全局代码,一直到所有的代码都执行完成,代表程序执行结束,程序结束的时候,我们的全局环境最后出栈。 |
1.13 基本数据类型和引用数据类型
| |
| |
| |
| var a = 10; |
| var b = a; |
| a = 20; |
| console.log(b); |
| |
| |
| var arr1 = [1, 2, 3]; |
| var arr2 = arr1; |
| arr2[1] = 22; |
| console.log(arr1); |
| |
| |
| var arr1 = [1, 2, 3]; |
| var arr2 = arr1; |
| arr2 = [1, 22, 3]; |
| console.log(arr1); |
| |
| |
| var arr1 = []; |
| var arr2 = []; |
| var arr3 = arr1; |
| arr3 = []; |
| arr3[0] = 12; |
| console.log(arr1, arr2, arr3); |
| |
| var arr = [1, 2, 3]; |
| var arr1 = [1, 2, 3]; |
| |
| console.log(arr == arr1); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统