前端 JavaScript 基础知识总结(中)

331 阅读16分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

往期文章

前言

一、一年一度的金(tong)三银(tie)四,不知各位胸怀大志的小伙伴们是否找到了自己心仪的工作呢

二、下面我对JavaScript中的部分基础知识做了一些梳理和总结,希望各位掘(da)友(lao)们能够温(shou)故(xia)知(liu)新(qing)

三、本篇将紧接上篇内容,进一步巩固 JavaScript 的有关基础知识点

总结

1.class

一、定义:

  • 类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础
  • 类是一种用户定义的引用数据类型,也称类类型
  • 传统的面向对象语言基本都是基于类的,JavaScript 基于原型的方式让开发者多了很多理解成本

二、优点:

  • ES6 之后,JavaScript 拥有了 class 关键字,虽然本质依然是构造函数,但是使用起来已经方便了许多

三、使用方式

1、定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):

  • 字段: 字段是类里面声明的变量。字段表示对象的有关数据
  • 构造函数: 类实例化时调用,可以为类的对象分配内存
  • 方法: 方法为对象要执行的操作

2、继承:

  • 类的继承使用过extends的关键字
  • 类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写,通过super关键字是对父类的直接引用,该关键字可以引用父类的属性和方法

3、修饰符:

  • 公共 public:可以自由的访问类程序里定义的成员
  • 私有 private:只能够在该类的内部进行访问
  • 受保护 protect:除了在该类的内部可以访问,还可以在子类中仍然可以访问

4、静态属性:

  • 这些属性存在于类本身上面而不是类的实例上,通过static进行定义,访问这些属性需要通过 类型.静态属性 的这种形式访问

5、抽象类:

  • 抽象类做为其它派生类的基类使用,它们一般不会直接被实例化,不同于接口,抽象类可以包含成员的实现细节
  • abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法
  • 这种类并不能被实例化,通常需要我们创建子类去继承

2.模块化

一、定义

1、模块:

  • 是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合体)

2、原因:

  • 变量和方法不容易维护,容易污染全局作用域
  • 加载资源的方式通过script标签从上到下。
  • 依赖的环境主观逻辑偏重,代码较多就会比较复杂。
  • 大型项目资源难以维护,特别是多人合作的情况下,资源的引入会让人奔溃

二、方案

1、CommonJs(典型代表:node.js早期):

  • 它通过 require 来引入模块,通过 module.exports 定义模块的输出接口
  • 这种模块加载方案是服务器端的解决方案,它是以同步的方式来引入模块的
  • 因为在服务端文件都存储在本地磁盘,所以读取非常快,所以以同步的方式加载没有问题
  • 但如果是在浏览器端,由于模块的加载是使用网络请求,因此使用异步加载的方式更加合适

2、AMD(典型代表:require.js):

  • 这种方案采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行
  • 所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数。require.js 实现了 AMD 规范

3、CMD(典型代表:sea.js):

  • 这种方案和 AMD 方案都是为了解决异步模块加载的问题,sea.js 实现了 CMD 规范
  • 它和require.js的区别在于模块定义时对依赖的处理不同和对依赖模块的执行时机的处理不同

4、ES6 Module:

  • ES6 提出的方案,使用 import 和 export 的形式来导入导出模块

3.Promise

一、定义

1、Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大

2、状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)

二、优点

  • 链式操作减低了编码难度
  • 代码可读性明显增强

三、特点

  • 对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态
  • 一旦状态改变(从pending变为fulfilled和从pending变为rejected),就不会再变,任何时候都可以得到这个结果

四、用法

1、Promise对象是一个构造函数,用来生成Promise实例:

const promise = new Promise(function(resolve, reject) {});

2、Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject:

  • resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”
  • reject函数的作用是,将Promise对象的状态从“未完成”变为“失败

五、实例方法

1、Promise构建出来的实例存在以下方法:

  • then():then是实例状态发生改变时的回调函数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数
  • catch():catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数
  • finally():finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

六、构造函数方法

1、Promise构造函数存在以下方法:

  • all():Promise.all()方法用于将多个 Promise实例,包装成一个新的 Promise实例
  • race():Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实
  • allSettled():Promise.allSettled()方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例
  • resolve():将现有对象转为 Promise对象
  • reject():Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

七、使用场景

  • 将图片的加载写成一个Promise,一旦加载完成,Promise的状态就发生变化
  • 通过链式操作,将多个渲染数据分别给个then,让其各司其职。或当下个异步请求依赖上个请求结果的时候,我们也能够通过链式操作友好解决问题
  • 通过all()实现多个请求合并在一起,汇总所有请求结果,只需设置一个loading即可
  • 通过race可以设置图片请求超时

4.迭代器 生成器

一、迭代器

1、定义:

  • Iterator(迭代器)是一种接口,也可以说是一种规范
  • 为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作

2、作用:

  • 为各种数据结构,提供一个统一的、简便的访问接口
  • 使得数据结构的成员能够按某种次序排列
  • ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费

二、生成器

1、定义:

  • Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
  • 执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态

2、特征:

  • function关键字与函数名之间有一个星号
  • 函数体内部使用yield表达式,定义不同的内部状态

三、异步解决方案

1、回调函数:

  • 所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,再调用这个函数

2、Promise:

  • Promise就是为了解决回调地狱而产生的,将回调函数的嵌套,改成链式调用

3、generator:

  • yield表达式可以暂停函数执行,next方法用于恢复函数执行,这使得Generator函数非常适合将异步任务同步化

4、async/await:

  • 将上面Generator函数改成async/await形式,更为简洁,语义化更强了

5、区别:

  • promiseasync/await是专门用于处理异步操作的
  • Generator并不是为异步而设计出来的,它还有其他功能(对象迭代、控制输出、部署Interator接口...)
  • promise编写代码相比Generatorasync更为复杂化,且可读性也稍差
  • Generatorasync需要与promise对象搭配处理异步情况
  • async实质是Generator的语法糖,相当于会自动执行Generator函数
  • async使用上更为简洁,将异步代码以同步的形式进行编写,是处理异步编程的最终方案

5.async await

一、定义

  • 是一种建立在Promise之上的编写异步或非阻塞代码的新方法,被普遍认为是JS异步操作的最终且最优雅的解决方案
  • 相对于 Promise 和回调,它的可读性和简洁度都更高

二、作用

1、async:

  • 声明一个异步方法
  • async函数返回一个promise对象,下面两种方法是等效的

2、await:

  • 等待异步方法执行
  • 正常情况下,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值
  • 不管await后面跟着的是什么,await都会阻塞后面的代码

三、优缺点

1、优点:

  • async/await的优势在于处理 then 的调用链,能够更清晰准确的写出代码,并且也能优雅地解决回调地狱问题

2、缺点:

  • 因为 await 将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了 await 会导致性能上的降低

6.事件循环

一、单线程

1、定义:

  • JavaScript语言的一大特点就是单线程,即同一时间只能做一件事情
  • 但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环

二、事件循环

1、任务:

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

2、过程:

  • 同步任务进入主线程,即主执行栈,异步任务进入任务队列
  • 主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行
  • 上述过程的不断重复就事件循环

三、任务队列

1、微任务:

  • 一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
  • 常见的微任务:Promise.then、MutaionObserver、Object.observe(已废弃;Proxy 对象替代)、process.nextTick(Node.js)

2、宏任务:

  • 宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
  • 常见的宏任务:script (可以理解为外层同步代码)、setTimeout/setInterval、UI rendering/UI事件、postMessage、MessageChannel、setImmediate、I/O(Node.js)

3、执行机制:

  • 执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
  • 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完

7.防抖 节流

一、本质

1、优化高频率执行代码的一种手段:

  • resizescrollkeypressmousemove 等事件在触发时,不断地调用绑定在事件上的回调函数,浪费资源,降低性能
  • 为了优化体验,需要对这类事件进行调用次数的限制,我们可以采用 防抖(debounce)节流(throttle) 的方式来减少调用频率

二、防抖

1、定义:

  • n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

2、应用场景:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

三、节流

1、定义:

  • n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

2、应用场景:

  • 滚动加载,加载更多或滚到底部监听
  • 搜索框,搜索联想功能

四、区别

1、相同点:

  • 都可以通过使用 setTimeout 实现
  • 目的都是,降低回调执行频率。节省计算资源

2、不同点:

  • 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeoutsetTimeout实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
  • 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次

3、例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数:

  • 节流,每隔 500ms 就执行一次
  • 防抖,则不管调动多少次方法,在2s后,只会执行一次

8.内存泄露 垃圾回收

一、内存泄露

1、定义:

  • 由于疏忽或错误造成程序未能释放已经不再使用的内存

2、作用:

  • 应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费
  • 程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存
  • 对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃

二、垃圾回收

1、定义:

  • 垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存

2、实现方式:

  • 标记清除:JavaScript最常用的垃圾收回机制

    • 当变量进入执行环境是,就标记这个变量为“进入环境“。进入环境的变量所占用的内存就不能释放,当变量离开环境时,则将其标记为“离开环境“
    • 垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉
    • 在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了
    • 随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存
  • 引用计数

    • 语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放
    • 如果一个值不再需要了,引用数却不为0,垃圾回收机制无法释放这块内存,从而导致内存泄漏

3、小结:

  • 有了垃圾回收机制,不代表不用关注内存泄露。那些很占空间的值,一旦不再用到,需要检查是否还存在对它们的引用
  • 如果是的话,就必须手动解除引用

9.Ajax

一、定义:

1、AJAX全称(Async Javascript and XML),即异步的JavaScriptXML

  • 是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页

二、原理:

  • 通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面

三、过程

  • 创建 Ajax的核心对象 XMLHttpRequest对象
  • 通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
  • 构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() 方法发送给服务器端
  • 通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
  • 接受并处理服务端向客户端响应的数据结果
  • 将处理结果更新到 HTML页面中

10.事件模型

一、定义

  • 事件是用户操作网页时发生的交互动作或者网页本身的一些操作

二、原始事件模型(DOM0级)

1、事件绑定监听函数比较简单, 有两种方式:

  • HTML代码中直接绑定
  • 通过JS代码绑定

2、特性:

  • 绑定速度快
  • 只支持冒泡,不支持捕获
  • 同一个类型的事件只能绑定一次

三、标准事件模型(DOM2级)

1、在该事件模型中,一次事件共有三个过程:

  • 事件捕获阶段:事件从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
  • 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数
  • 事件冒泡阶段:事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行

2、事件绑定监听函数的方式:

addEventListener(eventType, handler, useCapture)

3、事件移除监听函数的方式:

removeEventListener(eventType, handler, useCapture)

4、参数如下:

  • eventType指定事件类型(不要加on)
  • handler是事件处理函数
  • useCapture是一个boolean用于指定是否在捕获阶段进行处理,一般设置为false与IE浏览器保持一致

5、特性:

  • 可以在一个DOM元素上绑定多个事件处理器,各自并不会冲突
  • 执行时机
  • 当第三个参数(useCapture)设置为true就在捕获过程中执行,反之在冒泡过程中执行处理函数

四、IE事件模型(基本不用)

1、过程:

  • 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。
  • 事件冒泡阶段:事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行

2、事件绑定监听函数的方式:

attachEvent(eventType, handler)

3、事件移除监听函数的方式:

detachEvent(eventType, handler)

结尾

  • 好了,本篇的所有内容就介绍到这里了,希望大家能够在未来的日子里继续加油!