Javascript进阶
作用域
分类
- 局部
- 函数 ==>执行完变量被清空
- 块 ==>用{}包住 ==>有可能被无法访问 【用var声明的变量】
- 全局 ==> 在script标签和.js文件最外层进行声明
作用域链
最底层的变量查找机制 ==> 在函数被执行时,会优先查找当前函数作用域中查找变量,找不到再找父级作用域
垃圾回收机制 Garbage Collection
JS中内存的分配和回收都是自动完成的
内存的生命周期
内存分配–>内存使用 -->内存回收
全局变量一般不会回收,直至关闭页面
内存泄漏
程序中分配内存未释放或无法释放由于某种原因
JS垃圾回收机制 - 算法说明
堆和栈
- 栈:操作系统自动分配函数参数及局部变量【基本数据类型】
- 堆:由程序员分配释放,或者通过垃圾回收机制【复杂数据类型】
引用计数法【基本不使用了】
若对象无指向它的引用,进行回收
[!NOTE]
设置count变量来保存对于某变量的引用次数,引用一次自增,减少引用自减,当count变为0,释放内存
引用的意思是是否有变量名或者指针保存复杂数据类型变量的地址
若复杂数据类型互相指向,则count永不为0,导致内存泄漏
标记清除法
从根部(即
闭包 - closure
简单理解:内层函数 use–> 外层函数变量
作用
封闭数据,提供操作,外部也可以访问函数内部的变量
闭包机制
function folder() {let a = 1function fn() {console.log(a)}fn()}folder()
效果为
右边的Closure就是所谓的闭包
Local:局部变量
Global:全局变量
常见闭包形式
function outer() {let a = 1function inner() {console.log(a);}return inner;}let b = outer();b(); // 1
[!IMPORTANT]
相当于外部函数可以调用inner()函数,间接使用到,修改到函数内部变量,但不会让外部直接堆变量进行修改
借此实现数据的私有。 但由于始终可以查找到变量,导致变量无法被释放,产生内存泄漏的问题
变量提升
允许变量声明之前被访问(var声明变量)
const和let声明的变量不会出现这种情况
内部会先检查有无var声明的变量,若有,则将声明提前,赋值不会提前
console.log(a); // undefinedvar a = 10;console.log(a); // 10
函数进阶
函数提升
函数在声明之前可以被调用(在同等作用域下,提到最前面)
若被调用的函数为赋值得到的,则不可行,因为变量提升只提升声明,不含赋值
// 函数提升fn()function fn() {console.log('函数提升')}// 变量提升fun()var fun = function () {console.log('变量提升')}
函数参数
动态参数
函数内置 arument
- 伪数组
- 只存在函数中
调用时有参数,定义时括号内无参数
function addAll() {let sum = 0;for (let i = 0; i < arguments.length; i++) {sum += arguments[i];}return sum;}console.log(addAll(1, 2, 3, 4, 5)); //15console.log(addAll(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); //55
剩余参数
将不定数量的多余实参变为一个真数组
function sum(a, b, ...rest) {let result = a + b;for (let i = 0; i < rest.length; i++) {result += rest[i];}return result;}console.log(sum(1, 2, 3, 4, 5)); // 15console.log(sum(1, 2)); // 3console.log(sum(1, 2, 3, 4, 5, 6)); // 21
展开运算符
...
将数组展开(或者对象等)
应用:
- 求数组最大组 --Math.max()
- 合并数组
const arr = [1, 2, 3, 4, 5]console.log(...arr)console.log(Math.max(...arr))console.log(Math.min(...arr))const arr1 = [1, 2, 3, 4, 5]const arrAll = [...arr1, ...arr]console.log(...arrAll)
箭头函数
以更简洁的方式写匿名函数
语法技巧
- 只有一个参数,可以省略括号
- 函数只有一行代码可以省略大括号
- 只有一句return语句,可省略return
- 可用来返回对象
// 箭头函数const add = (a, b) => {console.log(a + b);return a * b}add(2, 3); // 5const double = a => a * 2;double(3); // 6const item = (uname) => ({ name: uname })console.log(item('John'))// {name: 'John'}
只可以用剩余参数
const all = (...arr) => console.log(...arr);all(1, 2, 3, 4, 5); // 1 2 3 4 5
不会创建自己的this,只会从自己的作用域的上一层沿用this
回调函数不推荐使用箭头函数
//this指向const a1 = () => thisconsole.log(a1()); // windowconst a2 = function () {let i = 1const a3 = () => thisconsole.log(a3()); // window}a2();const obj = {uname: "shaly",sayName: () => this}console.log(obj.sayName()) // shalyconst obj2 = {uname: "shaly",sayName: function () {const a4 = () => thisconsole.log(a4())}}console.log(obj2.sayName())