JavaScript进阶 第一天

  • 作用域
  • 函数进阶
  • 解构赋值

一.作用域

  • 局部作用域
  • 全局作用域
  • 作用域链
  • JS垃圾回收机制
  • 闭包
  • 变量提升

1.1 作用域

① 概念:规定了变量能够被访问的“范围”,离开了这个"范围",变量不能被访问

② 分类

  • 局部作用域

      (1)函数作用域:在函数内部声明的变量,只能在函数内部被访问,外部无法直接访问

1.函数内部声明的变量,在函数外部无法被访问

2.函数的参数也是函数内部的局部变量

3.不同函数内部声明的变量无法互相访问

4.函数执行完毕后,函数内部的变量实际被清空了                

      (2)块作用域:在JavaScript中使用{ }包裹起来的代码称为代码块,代码块内部声明的变量外部将【有可能】无法被访问

1.let声明的变量会产生块作用域,var不会产生块作用域

2.const声明的变量会产生块作用域

3.不同代码之间的变量无法相互访问

4.推荐使用let或const

  • 全局作用域

① <script> 标签 和.js文件的【最外层】就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问

② 全局作用域中声明的变量,任何其他作用域都可以被访问

③ 为window对象动态添加的属性默认也是全局的,不推荐

④ 函数中未使用任何关键字声明的变量为全局变量

⑤ 尽可能少声明全局变量,防止全局变量被污染

1.2 作用域链

① 概念:本质是底层的变量查找机制

  • 在函数被执行时,会优先在当前函数作用域中查找变量
  • 如果当前作用域找不到会依次逐级查找父作用域直到全局作用域

总结

1.嵌套关系的作用域串联起来形成了作用域链

2.相同作用域链中按照从小到大的规则查找变量

3.子作用域能够访问父作用域,父级作用域无法访问子级作用域

1.3.垃圾回收机制

① 垃圾回收机制:简称GC, JS 中内存的回收和分配都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收

内存的生命周期

  • 内存分配:当我们声明变量,函数,对象的时候,系统会自动为他们分配内存
  • 内存使用:即读写内存,也就是使用变量,函数
  • 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存

③ 说明

  • 全局变量一般不会回收(关闭页面回收)
  • 一般情况下,局部变量的值,不用了,会被自动回收掉

内存泄漏:程序中分配的内存由于某种原因,程序未释放或无法释放叫做内存泄漏

⑤ 算法说明

堆和栈的分配说明:

1.栈(操作系统):由操作系统自动分配释放函数的参数值,局部变量等,基本数据类型放到栈里面

2.堆(操作系统):一般由程序员分配释放,如果程序员不释放,由垃圾回收机制回收,一般存放复杂数据类型

两种常见的垃圾回收算法:引用计数法和标记清除法

引用计数:

  • IE浏览器采用的是引用计数法,定义“内存不再使用”,就是看一个对象是否有指向它的引用,如果没有就回收
  • 跟踪记录被引用的次数
  • 如果被引用了依次,就记录一次,多次引用会累加++
  • 如果减少一个引用就减1
  • 如果引用次数是0,就释放内存

致命问题:

嵌套引用(循环引用):如果两个对象下相互引用,垃圾回收器不会进行回收,就会导致内存泄漏,因为引用次数永远不会为0

标记清除法

  • 现代浏览器已经不再使用引用计数算法了,大多是基于标记清除法的某些改进算法
  • 标记清除算法将"不再使用的对象"定义为"无法达到的对象"
  • 就是从根部(在JS中就是全局对象)触发定时扫描内存中的对象,凡是能够从根部到达的对象都是需要使用的
  • 无法从根部触发触及到的对象被标记为不再使用,稍后进行回收

 1.4.闭包

① 概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域

② 闭包 = 内层函数 + 外层函数的变量

 ③ 闭包的作用:封闭数据,提供操作,外部也可以访问函数内部的变量

 ④ 基本格式:

 ⑤ 闭包的应用:实现数据的私有

function count () {
//  数据私有  i不会被回收, 可能会有内存泄漏的问题let i = 0
function fn () {i++console.log(i)
}return fn
}
const fun = count()
fun() 

 1.5.变量提升(不建议使用)

① 变量提升是JS中比较“奇怪”的现象,允许在变量声明之前被访问(仅存在于var声明变量)

  • 把所有var声明的变量提升到当前作用域的最前面
  • 只提升声明,不提升赋值

相当于:

var num
console.log(num + '件')

② 注意

  • 变量在未声明即被访问时会报语法错误
  • 变量在var声明之前即被访问,变量的值为undefined
  • let/ const 声明的变量不存在变量提升
  • 变量提升出现在相同作用域中
  • 实际开发中推荐先声明再访问变量

二.函数进阶

  • 函数提升
  • 函数参数
  • 箭头函数

2.1 函数提升

  • 函数提升指的是把所有函数声明提升到当前作用域的最前面
  • 只提升函数声明,不提升函数调用
  • 函数表达式不支持提升
  • 函数提升出现在相同作用域中
// 1.会把所有函数声明提升到当前作用域的最前面
// 2.只提升函数声明,不提升函数调用
fn()
function fn() {console.log('函数提升')
}
// 函数表达式不支持将调用写到声明前面

2.2 函数参数

  • 动态参数
  • 剩余参数

动态参数

① arguments是函数内部-内置的伪数组变量,它包含了调用函数时传入的所有实参

② 代码

 function getSum() {console.log(arguments);let sum = 0for (let i = 0; i < arguments.length; i++) {sum += arguments[i]}console.log(sum)
}
getSum(1,2,3,4,5,6,7,8,9,10)

③ 注意

  • arguments 是一个伪数组,只存在于函数中
  • arguments 的作用是动态获取函数的实参
  • 可以通过for循环依次得到传递过来的实参

剩余参数

① 剩余参数

  • ...是语法符号,置于最末函数形参之前,用于获取多余的实参
  • 借助...获取到的剩余实参,是个真数组

② 代码

function getSum (a, b, ...arr) {console.log(arr)  // 使用的时候不需要使用...
}
getSum(2, 3)
getSum(1, 2, 3, 4, 5)

③ 展开运算符(...):将一个数组进行展开

  • 展开数组,不会修改原数组
const arr1 = [1, 2, 3]
// 展开数组: 不会修改原数组 应用场景:求数组最大值(最小值), 合并数组
// 最大值
console.log(Math.max(...arr1))
console.log(Math.min(...arr1))
console.log(...arr1)
  • 合并数组
const arr1 = [1, 2, 3]
const arr2 = [4, 5]
const arr = [...arr1, ...arr2]

④ 剩余参数和展开运算符的区别

剩余参数:在函数中使用,会得到一个真数组

展开运算符:数组中使用,数组展开

2.3 箭头函数

  • 基本语法
  • 箭头函数参数
  • 箭头函数this

1.基本语法

 ① 目的:引入箭头函数的目的是更加简短的函数写法并且不绑定this,箭头函数的语法比函数表达式更简洁

② 使用场景:箭头函数更适用于那些原本需要匿名函数的地方

③ 写法

(1)原本匿名函数写法

const fn = function () {console.log(123)
}

 (2)箭头函数基本写法

const fn = () => {console.log(123)
}fn()

(3)箭头函数传参数

const fn = (x) => {console.log(x)
}
fn(1)

(4)只有一个参数的可以省略小括号

const fn = x => {console.log(x)
}
fn(1)

(5)只有一行代码,可以省略大括号

const fn = x => console.log(x)
fn(1)

(6)只有一行代码,箭头函数可以省略return

const fn = x => x + x
console.log(fn(1))

(7)箭头函数可以直接返回一个对象

const fn = (uname) => ({ uname: uname })
console.log(fn('hello'))

2.箭头函数参数

  • 普通函数有arguments 动态参数
  • 箭头函数没有 arguments 动态参数,但是有剩余参数 ...args
const getSum = (...arr) => {let sum = 0for (let i = 0; i < arr.length; i++) {sum += arr[i]}return sum
}
console.log(getSum(1,2,3))

3.箭头函数this

① this指向window

console.log(this)

② 普通函数this指向调用者

function fn () {
// this指向调用者console.log(this)
}

③ 对象里面的普通函数的this指向该对象

        const obj = {name: 'andy',sayHi: function () {console.log(this)}}obj.sayHi()

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this

⑤ 普通函数箭头函数指向上一层作用域window

        const fn = () => {console.log(this)}fn()

⑥ 对象方法中的箭头函数中的this指向window

        const obj = {uname: 'pink老师',sayHi: () => {console.log(this)  // 指向 window}}obj.sayHi()

⑦ 这里的this指向obj

        const obj = {uname: 'pink老师',sayHi: function () {let i = 10const count = () => {console.log(this) // obj}count()}}obj.sayHi()

注意:DOM事件回调函数为了方便,还是不太推荐使用箭头函数

2.4 解构赋值

  • 数组解构
  • 对象解构

1.数组解构

① 概念:将数组的单元值快速批量赋值给一系列变量的简洁语法

② 基本语法

  • 赋值运算符 = 左侧的[ ] 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量
  • 变量的顺序对应数组单元值的位置依次进行赋值操作
const arr = [100, 60, 80]
// 数组解构
const [max, min, avg] = arr
console.log(max, min, avg)

 交换两个变量的值

let a = 1
// 必须加分号
let b = 2;
[b, a] = [a, b]

③ 必须加分号的两种情况

(1)立即执行函数

(function() {})();

(2)数组解构

const str = 'pink'
;[1, 2, 3].map(function (item) {console.log(item)
})

③ 数组解构细节

  • 变量多,单元值少,多余的值为undefined
const [a, b, c, d] = [1, 2, 3]
console.log(a, b, c, d)
  • 变量少,单元值多, 多余的参数没有值接
const [a, b] = [1, 2, 3, 4]
  • 利用剩余参数解决
const [a, b, ...c] = [1, 2, 3, 4]
console.log(a, b, c)
  •  防止undefined传递, 可以给默认参数
const [a = 0, b = 0] = []
console.log(a, b)
  •  按需导入,忽略某些返回值
const [a, b, , c] = [1, 2, 3, 4]
console.log(a, b, c)
  • 多维数组
// 多维数组
const arr = [1, 2, [3, 4]]
console.log(arr[0])
console.log(arr[2][0])// 多维数组解构
const [a, b, [c, d]] = [1, 2, [3, 4]]
console.log(a, b, c, d)

2.对象解构

① 对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法

② 基本语法

  • 赋值运算符 = 左侧的 {} 用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量
  • 对象属性的值将被赋值给与属性名相同的变量
  • 解构的变量名不要和外面的变量名冲突报错
  • 对象中找不到与变量名一致的属性时变量值为undefined
const obj = {uname: 'pink',age: 18
}const { uname, age } = obj

③ 给新的变量名赋值:可以从一个对象中提取变量并同时修改新的变量名, 新名字在后面

const uname = 'hello'
const { uname: username, age } = obj
console.log(username)

④ 解构数组对象

const pig = [{uname: '佩奇',age: 18
}]
const [{ uname, age }] = pig
console.log(uname)
console.log(age)

⑤ 多级对象解构

        const pig = {name: '佩奇',family: {mother: '妈妈',father: '爸爸',sister: '乔治'},age: 6}const { name, family: { mother, father, sister } } = pigconsole.log(name, mother, father, sister)

⑥ 多级对象数组解构

        const person = [{name: '佩奇',family: {mother: '妈妈',father: '爸爸',sister: '乔治'},age: 6}]const [{ name, family: { mother, father, sister } }] = personconsole.log(name, mother, father, sister)

3.forEach() 方法

① 作用:遍历数组中的每个元素,将元素传递给回调函数

② 场景:遍历数组的每个元素

③ 语法:

被遍历的数组.forEach(function (当前数组元素,当前元素引号) {

     // 函数体

})

const arr = ['red', 'green', 'pink']
arr.forEach(function(item, index) {console.log(item)console.log(index)
})

 ④ 注意

  • 主要用来遍历数组
  • 参数里面当前元素是必须要写的,索引号是可选的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/67330.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全攻防实战:探索互联网发展史

大家好&#xff0c;我是沐尘而生。 互联网发展史&#xff1a;数字世界的壮阔画卷 从早期的ARPANET到今天的万物互联&#xff0c;互联网经历了漫长的发展过程。然而&#xff0c;随着技术的进步&#xff0c;网络安全问题也随之而来。我们不仅要探索互联网的壮阔历程&#xff0c;…

FreeRTOS(事件组)

资料来源于硬件家园&#xff1a;资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、事件的概念与应用 1、事件的概念 2、事件的应用 二、事件的运作机制 1、FreeRTOS中事件组的句柄 2、FreeRTOS 任务间事件标志组的实现 3、FreeRTOS 中断方式事件标志组的实现…

书写自动智慧:探索Python文本分类器的开发与应用:支持二分类、多分类、多标签分类、多层级分类和Kmeans聚类

书写自动智慧&#xff1a;探索Python文本分类器的开发与应用&#xff1a;支持二分类、多分类、多标签分类、多层级分类和Kmeans聚类 文本分类器&#xff0c;提供多种文本分类和聚类算法&#xff0c;支持句子和文档级的文本分类任务&#xff0c;支持二分类、多分类、多标签分类…

Mathematica 与 Matlab 常见复杂指令集汇编

Mathematica 常见指令汇编 Mathematica 常见指令 NDSolve 求解结果的保存 sol NDSolve[{y[x] x^2, y[0] 0, g[x] -y[x]^2, g[0] 1}, {y, g}, {x, 0, 1}]; numericSoly sol[[1, 1, 2]]; numericSolg sol[[1, 2, 2]]; data Table[{x, numericSoly[x], numericSolg[x]},…

SQL | 分组数据

10-分组数据 两个新的select子句&#xff1a;group by子句和having子句。 10.1-数据分组 上面我们学到了&#xff0c;使用SQL中的聚集函数可以汇总数据&#xff0c;这样&#xff0c;我们就能够对行进行计数&#xff0c;计算和&#xff0c;计算平均数。 目前为止&#xff0c…

腾讯云CVM服务器端口在安全组中打开!

腾讯云服务器CVM端口怎么开通&#xff1f;腾讯云服务器端口是通过配置安全组规则来开通的&#xff0c;腾讯云服务器网以开通80端口为例来详细说下腾讯云轻量应用服务器开启端口的方法&#xff0c;其他的端口的开通如8080、1433、443、3306、8888等端口也适用于此方法&#xff0…

RK3588平台开发系列讲解(AI 篇)RKNPU 推理软件框架

文章目录 一、推理软件框架二、RKNN 模型三、学习步骤整理沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要讲解什么是RKNPU。 一、推理软件框架 RKNPU 硬件层 RKNPU 驱动层 RKNPU 的驱动层是连接上层应用和 RKNPU 硬件的桥梁。驱动层的主要作用是将应用程序…

如何运用小程序技术闭环运营链路?

如何通过线上小程序获取用户线索&#xff0c;提高企业抗风险能力&#xff0c;建立有效的营销数字化系统一直是困扰每一个小程序开发者与运营者的问题。 当我们选择使用小程序设计自己的运营流程时&#xff0c;从「推广」到「转化」&#xff0c;再到最终的「留存」都是运营过程…

学习笔记|printf函数的实现|不同操作系统中的换行|数的进制:2进制、10进制、16进制转换|STC32G单片机视频开发教程(冲哥)|第五集:C语言基础

文章目录 1.C语言 printf函数的实现Tips&#xff1a;ASCII码表Tips&#xff1a;找不到头文件怎么办&#xff1f;主函数添加程序:常规用法:Tips&#xff1a;不同操作系统中的换行 ⒉数的进制:2进制、10进制、16进制.常见的对应&#xff1a;应用&#xff1a;整体端口的操作 3.C语…

Java面向对象(内部类)(枚举)(泛型)

内部类 内部类是五大成员之一&#xff08;成员变量、方法、构造方法、代码块、内部类&#xff09;&#xff1b; 一个类定义在另一个类的内部&#xff0c;就叫做内部类&#xff1b; 当一个类的内部&#xff0c;包含一个完整的事物&#xff0c;且这个事务不必单独设计&#xf…

初学HTML:在线简易画板设计。

最近在HTML&#xff0c;记录下一点点成果。 设计了一个简易画板&#xff0c;通过HTML的Canvas元素实现一个在线画板&#xff0c;用户可以在上面绘制图形或涂鸦。 下面是运行效果&#xff1a; 下面是代码&#xff1a; <!DOCTYPE html> <html> <head><ti…

大数据——协同过滤推荐算法:矩阵分解

矩阵分解的方法也分为很多种&#xff1a;SVD、LFM、BiasSVD和SVD。 Traditional SVD 一般SVD矩阵分解指的是SVD奇异值分解&#xff0c;将矩阵分解成三个相乘矩阵&#xff0c;中间矩阵就是奇异值矩阵。SVD分解的前提是矩阵是稠密的&#xff0c;现实场景中数据都是稀疏的&#x…