深入理解JS | 青训营笔记

48 阅读6分钟

一、基本概念

1、什么是JavaScript

JavaScript(简称JS)是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。

2、数据类型

(1)Undefined

Undefined类型只有一个值,即特殊值undefined。在使用var声明变量,但未对其加以初始化时,这个变量值就是undefined。

(2)Null

Null类型是第二个只有一个值的数据类型。其特殊值就是Null。从逻辑角度上看,null是一个空的对象指针。而这也正是使用typeof操作符检测null值,会返回“object”的原因。

(3)Boolean

即布尔类型,该类型有两个值:true、false。需要注意的是,Boolean类型的字面值true和false是区分大小写的。也就是说,True和False(以及其它的混合大小形式)都不是Boolean值,只是标识符。

(4)Number

该类型的表示方法有两种形式,第一种是整数,第二种为浮点数。整数:可以通过十进制,八进制,十六进制的字面值来表示。浮点数:就是该数值中必须包含一个小数点,且小数点后必须有一位数字。

(5)String

String类型用于表示由零或多个16位的Unicode字符组成的字符序列,即字符串。至于用单引号,还是双引号,在js中还是没有差别的。记得成对出现。

(6)Symbol

符号 (Symbols) 是 ECMAScript 第 6 版新定义的。符号类型是唯一的并且是不可修改的。Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述

(7)Object

Object数据类型,称为对象,是一组数据和功能(函数)的集合。可以用new操作符后跟要创建的对象类型的名称来创建。也可以用字面量表示法创建。在其中添加不同名(包含空字符串在内的任意字符串)的属性。

(8)Array

数组(Array)是一组按顺序排列的数据的集合,数组中的每个值都称为元素,而且数组中可以包含任意类型的数据。

(9)Funtion

ECMAScript中的函数是对象,与其他引用类型一样具有属性和方法。因此,函数名实际是一个指向函数对象的指针。

2、作用域

(1)全局作用域

全局作用域是指变量可以在当前脚本的任意位置访问,拥有全局作用域的变量也被称为“全局变量”。
特征
1.最外层的函数和在最外层函数外面定义的变量拥有全局作用域;
2.所有未定义直接赋值的变量拥有全局作用域;
3.所有 window 对象的属性拥有全局作用域,例如 window.name、window.location、window.top 等。
4.全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到。
5.- 全局作用域在页面打开时创建,在页面关闭时销毁。

(2)函数作用域

在函数内部声明的变量具有局部作用域,拥有局部作用域的变量也被称为“局部变量”,局部变量只能在其作用域中(函数内部)使用。
注意
1.只有函数被调用时才会生成,当函数执行完之后,就会被销毁。
2.函数重复调用,会重复创建一个新的作用域,它们之间是相互调用的。
3.函数作用域,可以访问全局作用域,而全局作用域不能访问函数作用域)

(3)块级作用域

表示当前执行的上下文,值与表达式在其中可见,可以被访问到的上下文,作用域决定了区块代码中的可见性。

3、js变量提升

image.png

二、JavaScript是怎么执行的

image.png

1、执行上下文

(1)介绍

image.png

(2)分类

image.png

image.png

image.png

(3)作用域链

执行下面函数,将会打印Bytedance,依次创建testCompany()、testCompany1()、testCompany2(),在testCompany2()函数里没有company声明,往外寻找执行上下文,首先是上一级的执行上下文,依次寻找,最后才到全局。这种层级结构称之为“作用域链”。

image.png

三、进阶知识点

1、闭包

解释:当一个函数去使用所在作用域的变量时,该作用域就会被函数引用,这个引用就称为闭包,即使是在该作用域外执行。(基础理解:基于作用链) 正常情况下在函数外部,无法访问到函数内的变量。上例中却能够在外部取到内部变量 a 的值。

因为 bar 使用了foo的变量a,产生了闭包,并通过return返回bar,使得foo作用域被保存下来,没有被回收。直到baz的生命周期结束才会被回收。
image.png

2、this

image.png

3、垃圾回收

(1) 标记清除法

标记清除法分为标记清除两个阶段,标记阶段需要从根节点遍历内存中的所有对象,并为可达的对象做上标记,清除阶段则把没有标记的对象(非可达对象)销毁。

(2)引入技术法

引用计数法主要记录对象有没有被其他对象引用,如果没有被引用,它将被垃圾回收机制回收。它的策略是跟踪记录每个变量值被使用的次数,当变量值引用次数为0时,垃圾回收机制就会把它清理掉。

(3)V8对垃圾回收机制的优化——分代式垃圾回收机制

原本的垃圾回收机制在每次回收时都要检查内存中所有的对象,这样的话,一些大、老、存活时间长的对象与新、小、存活时间短的对象检查频率相同,但是前者并不需要频繁进行清理,因此采用分代式垃圾回收机制。 新生代区:新生代区分为两个区:对象区域(存放比较活跃的数据),空闲区域。首先将活跃的对象复制并排序到空闲区,然后对象区域清空,最后把两个区互换。 老生代:数据来源是将新生代的两次没有回收的对象放到老生代里面,比较大的对象都会放到老生代。首先标记,然后清除。

image.png

4、事件循环

同级中:微任务优先于宏任务
微任务:同步代码(promise放在一个触发线程中,promise中有一个异步任务,会执行异步任务,将then函数放到微任务中)
宏任务:异步任务(settimeout)