导图社区 JavaScript高级教程学习内容
这是一篇关于JavaScript高级教程相关内容学习的思维导图。是我在学习JavaScript高级遇到的一些知识,整理成笔记,希望能帮助大家!
编辑于2021-08-11 00:38:02你好,我根据B站coderwhy老师Vue2课程视频,顺利自学找到前端开发工作,非常感谢coderwhy老师,整理了一份Vue2非常详细的知识点思维导图(已获老师授权),放在 GitHub上,大家可以一起参考学习,有不足之处,多多指正,觉得有帮助的请点个 Star❤,谢谢。GitHub地址:https://github.com/itchaox/Vue2-mind-map
这是一篇关于JavaScript高级教程相关内容学习的思维导图。是我在学习JavaScript高级遇到的一些知识,整理成笔记,希望能帮助大家!
社区模板帮助中心,点此进入>>
你好,我根据B站coderwhy老师Vue2课程视频,顺利自学找到前端开发工作,非常感谢coderwhy老师,整理了一份Vue2非常详细的知识点思维导图(已获老师授权),放在 GitHub上,大家可以一起参考学习,有不足之处,多多指正,觉得有帮助的请点个 Star❤,谢谢。GitHub地址:https://github.com/itchaox/Vue2-mind-map
这是一篇关于JavaScript高级教程相关内容学习的思维导图。是我在学习JavaScript高级遇到的一些知识,整理成笔记,希望能帮助大家!
JavaScript高级教程—相关内容学习
基础总结深入
数据类型
数据类型分类
基本(值)类型
String
任意字符串
Number
任意的数字
boolean
true/false
undefined
undefined
undefined代表未定义,未赋值
null
null
null代表定义,并且赋值为null
对象(引用)类型
Object
任意对象
Function
一种特别的对象:可以执行
Array
一种特别的对象:数值下标,内部数据是有序的
什么时候给变量赋值为null?
初始赋值,表明将要赋值为对象
结束前,让对象成为垃圾对象(被垃圾回收器回收)
判断数据类型
typeof
返回数据类型的字符串表达
能判断
undefined
数值
字符串
布尔值
function
不能判断
null和object
object和array
输出都是object
instanceof
判断对象的具体类型
===
undefined
null
数据、变量与内存
数据
数据是存储在内存中代表特定信息的东西
变量
可变化的量,由变量名和变量值组成
内存
内存条通电后产生的可存储数据的空间(临时的)
三者关系
内存是用来存储数据的空间
变量是内存的标识
问题:在js调用函数传递变量参数时,是值传递还是引用传递?
理解1:都是值(基本、地址值)传递
理解2:可能是值传递,也可能是引用传递(地址值)
问题:JS引擎如何管理内存?
内存生命周期
分配小内存空间,得到它的使用权
存储数据,可以反复进行操作
释放小内存空间
释放内存
局部变量:函数执行完自动释放
对象:成为垃圾对象 -> 垃圾回收器回收
对象
什么是对象?
用来保存多个数据的容器
一个对象代表现实中的一个事物
为什么使用对象?
统一管理多个数据
对象是怎么组成?
属性
属性名(字符串)和属性值(任意)组成
方法
一种特别的属性,属性值为函数的属性
如何访问对象内部数据?
.属性名
编码简单,有时不能用
['属性名']
编码复杂,能通用
必须使用['属性名']的方式:
属性名包含特殊字符:- 空格 等等
属性名不确定
函数
什么是函数?
实现特定功能的n条语句的封装体
只有函数是可以执行的,其它类型的数据是不能执行
为什么要用函数?
提高代码复用
便于阅读交流
如何定义函数?
函数声明
表达式
如何调用(执行)函数?
直接调用
通过对象调用
new调用
改变this的指向
回调函数
回调函数定义
自己定义
自己没有调用
函数最终执行
常见的回调函数
dom事件回调函数
定时器回调函数
ajax请求回调函数
生命周期回调函数
IIFE(立即调用函数表达式)
作用
隐藏实现
不会污染外部(全局)命名空间
用它来编码js模块
函数中的this
this是什么?
任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
所有函数内部都有一个变量this
它的值是调用函数的当前对象
如何确定this的值?(举例说明)
test( ):window
p.test( ):p
var p = new test( ):p(新创建的对象)
p.call(obj):obj
函数高级
原型与原型链
原型(prototype)
函数的prototype属性
每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
原型对象中都有一个属性constructor,它指向函数对象
给原型对象添加属性(一般都是方法)
作用:函数的所有实例对象自动拥有原型中的属性(方法)
显式原型和隐式原型
每个函数function都有一个prototype,即显式原型(属性)
每个实例对象都有一个__proto__,可称为隐式原型(属性)
对象的隐式原型的值为其对应构造函数的显示原型的值
总结
函数的prototype属性:在定义函数的时自动添加的,默认值是一个空Object对象
对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
原型链
访问一个对象的属性时
先在自身属性中查找,找到返回
如果没有,再沿着__proto__这条链向上查找,找到返回
如果最终没找到,返回undefined
别名
隐式原型链
作用
查找对象的属性(方法)
原型继承
构造函数的实例对象自动拥有构造函数原型对象的属性(方法)
利用的就是原型链
原型链补充
函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
所有函数都是Function的实例(包含Function)
Object的原型对象是原型链的尽头
原型链-属性问题
读取对象的属性值时:会自动到原型链中查找
设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
探索instanceof
instanceof是如何判断的?
表达式:A instanceof B
如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
Function是通过new自己产生的实例
面试题
执行上下文与执行上下文栈
变量提升与函数提升
变量声明提升
通过var定义(声明)的变量,在定义语句之前就可以访问到
值:undefined
函数声明提升
通过function声明的函数,在之前就可以直接调用
值:函数定义(对象)
执行上下文
代码分类(位置)
全局代码
函数(局部)代码
全局执行上下文
在执行全局代码前将window确定为全局执行上下文
对全局数据进行预处理
var定义的全局变量-->undefined,添加为window的属性
function声明的全局函数-->赋值(fun),添加为window的方法
this-->赋值(window)
开始执行全局代码
函数执行上下文
在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中)
对局部数据进行预处理
形参变量-->赋值(实参)-->添加为执行上下文的属性
arguments-->赋值(实参列表),添加为执行上下文的属性
var定义的局部变量-->undefined,添加为执行上下文的属性
function声明的函数-->赋值(fun),添加为执行上下文的方法
this-->赋值(调用函数的对象)
开始执行函数体代码
执行上下文栈
在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
在全局执行上下文(window)确定后,将其添加到栈中(压栈)
在函数执行上下文创建后,将其添加到栈中(压栈)
在当前函数执行完后,将栈顶的对象移除(出栈)
当所有的代码执行完后,栈中只剩下window
面试题
面试题一
题目
运行结果
整个过程产生了几个执行上下文?
5个
作用域与作用域链
作用域
理解
一个代码段所在的区域
它是静态的(相对于上下文对象),在编写代码时就确定了
分类
全局作用域
局部作用域
没有块作用域(ES6有了)
作用
隔离变量,不同作用域下同名变量不会有冲突
作用域链
理解
多个上下级关系的作用域形成的链,它的方向是从下向上的(从内到外)
查找变量时就是沿着作用域链来查找的
查找一个变量的查找规则
在当前作用域下的执行上下文中查找对应的属性,如果有直接返回,否则会向就近的上级作用域查找
在上一级作用域下的执行上下文中查找对应的属性,如果有直接返回,否则继续向就近的上级作用域查找
重复上面操作,直到全局作用域,如果还找不到就抛出找不到的异常
面试题
面试题一
面试题二
闭包
理解闭包
如何产生闭包?
当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
闭包到底是什么?
使用chrome调试查看
理解一:
闭包是嵌套的内部函数(绝大部分人)
理解二:
包含被引用变量(函数)的对象(极少数人)
注意:
闭包存在于嵌套的内部函数中
产生闭包的条件?
函数嵌套
内部函数引用了外部函数的数据(变量/函数)
常见的闭包
将函数作为另一个函数的返回值
将函数作为实参传递给另一个函数使用
闭包的作用
作用
使函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
让函数外部可以操作(读写)到函数内部的数据(变量/函数)
问题
函数执行完后,函数内部声明的局部变量是否还存在?
一般是不存在的
闭包中的变量才可能存在
在函数外部能直接访问函数内部的局部变量吗?
不能,但我们可以通过闭包让外部操作它
闭包的生命周期
产生:
在嵌套内部函数定义执行完时就产生了(不是在调用)
死亡:
在嵌套的内部函数成为垃圾对象时
闭包的应用-自定义JS模块
定义JS模块
具有特定功能的js文件
将所有的数据和功能都封装在一个函数内部(私有的)
只向外暴露一个包含n个方法的对象或函数
模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
闭包的缺点及解决
缺点
函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
容易造成内存泄露
解决
尽量少用闭包
及时释放
内存溢出与内存泄露
内存溢出
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时,就会抛出内存溢出的错误
内存泄露
占用的内存没有及时释放
内存泄露积累多了就容易导致内存溢出
常见的内存泄露
意外的全局变量
没有及时清理的计时器或回调函数
闭包
面试题
面试题一
代码片段一
// 代码片段一 var name = 'the window' var object = { name: 'the bookmark', getName: function () { return function () { return this.name } } } alert(object.getName()()) // 弹出:the bookmark
// 代码片段一 var name = 'the window' var object = { name: 'the bookmark', getName: function () { return function () { return this.name } } } alert(object.getName()()) // 弹出:the bookmark
代码片段二
// 代码片段二 var name = 'the window' var object = { name: 'the bookmark', getName: function () { var that = this return function () { return that.name } } } alert(object.getName()()) // 弹出:the window
// 代码片段二 var name = 'the window' var object = { name: 'the bookmark', getName: function () { var that = this return function () { return that.name } } } alert(object.getName()()) // 弹出:the window
面试题二
function fn(n, o) { console.log(o); return { fn: function (m) { return fn(m, n); } } } var a = fn(0); a.fn(1); a.fn(2); a.fn(3); // undefined 0 0 0 var b = fn(0).fn(1).fn(2).fn(3) // undefined 0 1 2 var c = fn(0).fn(1); c.fn(2); c.fn(3) // undefined 0 1 1
function fn(n, o) { console.log(o); return { fn: function (m) { return fn(m, n); } } } var a = fn(0); a.fn(1); a.fn(2); a.fn(3); // undefined 0 0 0 var b = fn(0).fn(1).fn(2).fn(3) // undefined 0 1 2 var c = fn(0).fn(1); c.fn(2); c.fn(3) // undefined 0 1 1
面向对象高级
对象创建模式
Object构造函数模式
套路:先创建空Object对象,再动态添加属性/方法
适用场景:起始时不确定对象内部数据
问题:语句太多
对象字面量模式
套路:使用{ }创建对象,同时指定属性/方法
使用场景:起始时对象内部数据是确定的
问题:如果创建多个对象,有重复代码
工厂模式
套路:通过工厂函数动态创建对象并返回
适用场景:需要创建多个对象
问题:对象没有一个具体的类型,都是Object类型
工厂函数-概念
返回一个对象的函数
自定义构造函数模式
套路:自定义构造函数,通过new创建对象
适用场景:需要创建多个类型确定的对象
问题:每个对象都有相同的数据,浪费内存
构造函数+原型的组合模式
套路:自定义构造函数,属性在函数中初始化,方法添加到原型上
适用场景:需要创建多个类型确定的对象
继承模式
原型链继承
套路
定义父类型构造函数
给父类型的原型添加方法
定义子类型的构造函数
创建父类型的对象赋值给子类型的原型
将子类型原型的构造属性设置为子类型
给子类型原型添加方法
创建子类型的对象:可以调用父类型的方法
关键
子类型的原型为父类型的一个实例对象
借用构造函数继承(假的)
套路
定义父类型构造函数
定义子类型构造函数
在子类型构造函数中调用父类型构造
关键
在子类型构造函数中通用super()调用父类型构造函数
原型链+借用构造函数的组合继承
利用原型链实现对父类型对象的方法继承
利用super()借用父类型构建函数初始化相同属性
线程机制与事件机制
进程与线程
进程(process)
程序的一次执行,它占有一片独有的内存空间
可以通过windows任务管理器查看进程
线程(thread)
是进程内的一个独立执行单元
是程序执行的一个完成流程
是CPU的最小的调度单元
图解
相关知识
应用程序必须运行在某个进程的某个线程上
一个进程中至少有一个运行的线程:主线程,进程启动后自动创建
一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的
一个进程内的数据可以供其中的多个线程直接共享
多个进程之间的数据是不能直接共享的
线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
相关问题
何为多进程与多线程?
多进程:一个应用程序可以同时启动多个实例运行
多线程:在一个进程内,同时有多个线程运行
比较单线程与多线程?
多线程
优点
能有效提升CPU的利用率
缺点
创建多线程开销
线程间切换开销
死锁与状态同步问题
单线程
优点
顺序编程简单易懂
缺点
效率低
JS是单线程还是多线程?
JS是单线程运行的
但使用H5中的Web Workers可以多线程运行
浏览器运行是单线程还是多线程?
都是多线程运行的
浏览器运行是单进程还是多进程?
有的是单进程
firefox
老版IE
有的是多进程
chrome
新版IE
如何查看浏览器是否是多进程运行的?
打开任务管理器,查看进程运行
浏览器内核
支撑浏览器运行的最核心的程序
不同浏览器可能不一样
Chrome(旧版),Safari:webkit
Chrome(新版):Blink
firefox:Gecko
IE:Trident
360,搜狗等国内浏览器:Trident + webkit
内核由很多模块组成
主线程
js引擎模块:负责js程序的编译与运行
html,css文档解析模块:负责页面文本的解析
DOM/CSS模块:负责dom/css在内存中的相关处理
布局和渲染模块:负责页面的布局和效果的绘制(内存中的对象)
......
分线程
定时器模块:负责定时器的管理
DOM事件响应模块:负责事件的管理
网络请求模块:负责ajax请求
定时器引发的思考
定时器真是定时执行的吗?
定时器并不能保证真正定时执行
一般会延迟一丁点(可以接受),也有可能延迟很长时间(不能接受)
定时器回调函数是在分线程执行的吗?
在主线程执行的,js是单线程的
定时器是如何实现的?
事件循环模型
JS是单线程执行的
如何证明js执行是单线程的?
setTimeout()的回调函数是在主线程执行的
定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
为什么js要用单线程模式,而不用多线程模式?
JavaScript的单线程,与它的用途有关
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM
这决定了它只能是单线程,否则会带来很复杂的同步问题
代码的分类:
初始化代码
回调代码
js引擎执行代码的基本流程
先执行初始化代码:包含一些特别的代码 回调函数(异步执行)
设置定时器
绑定事件监听
发送ajax请求
后面在某个时刻才会执行回调代码
浏览器的事件循环(轮询)模型
模型原理图
相关重要概念
执行栈
execution stack
所有的代码都是在此空间中执行的
浏览器内核
browser core
js引擎模块(在主线程处理)
其它模块(在主/分线程处理)
任务队列
同一个 callback queue
task queue
消息队列
同一个 callback queue
message queue
事件队列
同一个 callback queue
event queue
事件轮询
event loop
从任务队列中循环取出回调函数放入执行栈中处理(一个接一个)
事件驱动模型
event-driven interaction model
请求响应模型
request-response model
执行流程
H5 Web Workers(多线程)
介绍
Web Workers 是HTML5提供的一个JavaScript多线程的解决方案
我们可以将一些大计算量的代码交由Web Worker运行而不冻结用户界面
但是子线程完全受主线程控制,且不得操作DOM
所以,这个新标准并没有改变JavaScript单线程的本质
使用
创建的分线程执行的js文件
在主线程中的js中发消息并设置回调
图解
应用练习
不足
慢
不能跨域加载JS
worker内代码不能访问DOM(更新UI)
不是每个浏览器都支持这个新特性