JavaScript 部分
JavaScript 有哪些数据类型,它们的区别?
JavaScript 共有八种数据类型,分别是 Undefined、Null、Boolean、 Number、String、Object、Symbol、BigInt。
其中 Symbol 和 BigInt 是ES6 中新增的数据类型:
-
Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EpRxmxdo-1682167755746)(media/image8.png)]BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
这些数据可以分为原始数据类型和引用数据类型:
-
栈:原始数据类型(Undefined、Null、Boolean、Number、String)
-
堆:引用数据类型(对象、数组和函数)两种类型的区别在于存储位置的不同:
-
原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
-
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
-
在数据结构中,栈中数据的存取方式为先进后出。
-
堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
在操作系统中,内存被分为栈区和堆区:
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WUe06Y8-1682167755748)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rj2pZZfg-1682167755750)(media/image4.png)]栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
-
堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。
数据类型检测的方式有哪些
- typeof
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j25i9JSw-1682167755751)(media/image10.jpeg)]
其中数组、对象、null 都会被判断为object,其他判断都正确。
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqYrmAaO-1682167755753)(media/image8.png)]instanceof
instanceof 可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zzsJBso-1682167755754)(media/image11.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1aEwWhKr-1682167755756)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKFAH23X-1682167755757)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JuGYDbhI-1682167755758)(media/image12.jpeg)]
constructor 有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor 就不能用来判断数据类型了:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NvebIroh-1682167755759)(media/image13.jpeg)]
(4)Object.prototype.toString.call()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tT2WZup-1682167755761)(media/image8.png)]Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9gT3xNwL-1682167755763)(media/image14.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1DVtuWb-1682167755764)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VRrCWQPc-1682167755765)(media/image4.png)]的toString 方法(function 类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用 Object 上原型 toString 方法(返回对象的具体类型),所以采用 obj.toString()不能得到其对象类型,只能将 obj 转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object 原型上的toString 方法。
null 和undefined 区别
首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CXnw6oeH-1682167755767)(media/image8.png)]undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null 主要用于赋值给一些可能会返回对象的变量,作为初始化。
undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmQugQSv-1682167755768)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CG15CHZj-1682167755770)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iQzQu3Tj-1682167755771)(media/image15.jpeg)]
如何获取安全的 undefined 值?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xpib2Aiz-1682167755774)(media/image8.png)]因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。表达式 void 没有返回值,因此返回结果是 undefined。void 并不改变表达式的结果,只是让表达式不返回值。因此可以用 void 0 来获得 undefined。
Object.is() 与比较操作符 “=”、“” 的区别?
使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN是相等的。
什么是 JavaScript 中的包装类型?
在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VKLnpPOr-1682167755776)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dHrsLGY9-1682167755777)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hBrb2D0p-1682167755779)(media/image16.jpeg)]
在访问’abc’.length 时, JavaScript 将’abc’ 在后台转换成 String(‘abc’),然后再访问其length 属性。
JavaScript 也可以使用Object 函数显式地将基本类型转换为包装类型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggRRplIx-1682167755782)(media/image17.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kyz7UNTZ-1682167755784)(media/image8.png)]也可以使用valueOf 方法将包装类型倒转成基本类型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ST3gVJ0j-1682167755786)(media/image18.jpeg)]
看看如下代码会打印出什么:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vjeEu62I-1682167755787)(media/image19.jpeg)]
答案是什么都不会打印,因为虽然包裹的基本类型是 false,但是 false 被包裹成包装类型后就成了对象,所以其非值为 false,所以循环体中的内容不会运行。
为什么会有 BigInt 的提案?
JavaScript 中 Number.MAX_SAFE_INTEGER 表示最⼤安全数字,计算结果是 9007199254740991,即在这个数范围内不会出现精度丢失(⼩数除外)。但是⼀旦超过这个范围,js 就会出现计算不准确的情况,
这在⼤数计算的时候不得不依靠⼀些第三⽅库进⾏解决,因此官⽅提出了BigInt 来解决此问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FrIGvEOU-1682167755789)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUHm9nTV-1682167755790)(media/image4.png)]如何判断一个对象是空对象
使用JSON 自带的.stringify 方法来判断:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-au1qI0d5-1682167755793)(media/image20.jpeg)]
使用ES6 新增的方法Object.keys()来判断:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xx7y04AY-1682167755795)(media/image21.jpeg)]
const 对象的属性可以修改吗
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M8XxojS0-1682167755797)(media/image8.png)]const 保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。
但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const 只能保证这个指针是固定不
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MnX5hGrb-1682167755799)(media/image22.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bGc2jnu0-1682167755800)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IixQZ3yJ-1682167755802)(media/image4.png)]3.指向构造函数中的代码,构造函数中的 this 指向该对象(也就是为这个对象添加属性和方法)
4.返回新的对象
所以,上面的第二、三步,箭头函数都是没有办法执行的。
12. 箭头函数的this 指向哪⾥?
箭头函数不同于传统JavaScript 中的函数,箭头函数并没有属于⾃
⼰的this,它所谓的this 是捕获其所在上下⽂的 this 值,作为⾃
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZvLAMLDg-1682167755804)(media/image8.png)]⼰的 this 值,并且由于没有属于⾃⼰的 this,所以是不会被 new调⽤的,这个所谓的this 也不会被改变。
可以⽤Babel 理解⼀下箭头函数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-52LVX2yh-1682167755806)(media/image23.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SIjVoh7u-1682167755807)(media/image24.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SApdg9EW-1682167755809)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKqCpDH3-1682167755812)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EwjCusXl-1682167755815)(media/image25.jpeg)]
上述方法实际上等价于:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-00MxwhcK-1682167755817)(media/image26.jpeg)]
Object.assign 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。Object.assign 方法的第一个参数是目标对象,后面的参数都是源对象。(如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRofYgL7-1682167755819)(media/image8.png)]同样,如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KL5A8VKH-1682167755821)(media/image27.jpeg)]
利用上述特性就可以很方便的修改对象的部分属性。在 redux 中的 reducer 函数规定必须是一个纯函数,reducer 中的 state 对象要求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ucHWAUsz-1682167755823)(media/image28.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x7e1atQl-1682167755824)(media/image29.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m12q2nAW-1682167755825)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aJ3kZtFY-1682167755828)(media/image4.png)]将数组转换为参数序列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpJVotPR-1682167755829)(media/image30.jpeg)]
复制数组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZpBj0Rqj-1682167755831)(media/image31.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0FzHFTZw-1682167755832)(media/image8.png)]要记住:扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中,这里参数对象是个数组,数组里面的所有对象都是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。
合并数组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-taGmwXpE-1682167755833)(media/image32.jpeg)]如果想在数组内合并数组,可以这样:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I9koefDR-1682167755834)(media/image33.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dKcjXIRT-1682167755835)(media/image34.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRVqzuxE-1682167755836)(media/image4.png)]比较常见的应用是可以将某些数据结构转为数组:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJHEBCEb-1682167755838)(media/image35.jpeg)]
用于替换es5 中的Array.prototype.slice.call(arguments)写法。使用Math 函数获取数组中特定的值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3nMJF4qm-1682167755840)(media/image36.jpeg)]
Proxy 可以实现什么功能?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opGdY6sD-1682167755842)(media/image8.png)]在 Vue3.0 中通过 Proxy 来替换原本的 Object.defineProperty来实现数据响应式。
Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qjYsZf3X-1682167755843)(media/image37.jpeg)]
代表需要添加代理的对象,handler 用来自定义对象中的操作,比如
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ryohaMk6-1682167755845)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d3tTGB3b-1682167755847)(media/image4.png)]在上述代码中,通过自定义 set 和 get 函数的方式,在原本的逻辑中插入了我们的函数逻辑,实现了在对对象任何属性进行读写时发出通知。
当然这是简单版的响应式实现,如果需要实现一个 Vue 中的响应式,需要在 get 中收集依赖,在 set 派发更新,之所以 Vue3.0 要使用 Proxy 替换原本的 API 原因在于 Proxy 无需一层层递归为每个属性添加代理,一次即可完成以上操作,性能上更好,并且原本的实现有一些数据更新不能监听到,但是 Proxy 可以完美监听到任何方式的数据改变,唯一缺陷就是浏览器的兼容性不好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lpvAptcy-1682167755849)(media/image8.png)]常用的正则表达式有哪些?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IJVxVyR-1682167755850)(media/image38.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPcyUr5x-1682167755853)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hcwKI07O-1682167755854)(media/image4.png)]因为 JSON 的语法是基于 js 的,因此很容易将 JSON 和 js 中的对象弄混,但是应该注意的是 JSON 和 js 中的对象不是一回事,JSON中对象格式更加严格,比如说在 JSON 中属性值不能为函数,不能出现 NaN 这样的属性值等,因此大多数的 js 对象是不符合 JSON 对象的格式的。
在 js 中提供了两个函数来实现 js 数据结构和 JSON 格式的转换处理,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4MbIGseB-1682167755857)(media/image8.png)]JSON.stringify 函数,通过传入一个符合 JSON 格式的数据结构,将其转换为一个 JSON 字符串。如果传入的数据结构不符合 JSON 格式,那么在序列化的时候会对这些值进行对应的特殊处理,使其符合规范。在前端向后端发送数据时,可以调用这个函数将数据对象转化为 JSON 格式的字符串。
JSON.parse() 函数,这个函数用来将 JSON 格式的字符串转换为一个 js 数据结构,如果传入的字符串不是标准的 JSON 格式的字符串的话,将会抛出错误。当从后端接收到 JSON 格式的字符串时,可以通过这个方法来将其解析为一个 js 数据结构,以此来进行数据的访问。
JavaScript 脚本延迟加载的方式有哪些?
延迟加载就是等页面加载完成之后再加载 JavaScript 文件。js 延迟加载有助于提高页面加载速度。
一般有以下几种方式:
defer 属性:给 js 脚本添加 defer 属性,这个属性会让脚本的加载与文档的解析同步解析,然后在文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞。多个设置了 defer 属性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sCZ0R0G2-1682167755858)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ykq8TSyb-1682167755860)(media/image4.png)]的脚本按规范来说最后是顺序执行的,但是在一些浏览器中可能不是这样。
async 属性:给 js 脚本添加 async 属性,这个属性会使脚本异步加载,不会阻塞页面的解析过程,但是当脚本加载完成后立即执行 js脚本,这个时候如果文档没有解析完成的话同样会阻塞。多个 async属性的脚本的执行顺序是不可预测的,一般不会按照代码的顺序依次执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JuRZb82v-1682167755862)(media/image8.png)]动态创建 DOM 方式:动态创建 DOM 标签的方式,可以对文档的加载事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本。
使用 setTimeout 延迟方法:设置一个定时器来延迟加载 js 脚本文件
让 JS 最后加载:将 js 脚本放在文档的底部,来使 js 脚本尽可能的在最后来加载执行。
什么是 DOM 和 BOM?
DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象主要定义了处理网页内容的方法和接口。
BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的法和接口。BOM 的核心是 window,而 window 对象具有双重角色,它既是通过 js 访问浏览器 窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页 中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方 法存在。window 对象含有 location 对象、navigator 对象、screen
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0xa3DXBA-1682167755863)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wTThF2oc-1682167755865)(media/image4.png)]对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM的 window 对象的子对象。
escape、encodeURI、encodeURIComponent 的区别
encodeURI 是对整个 URI 进行转义,将 URI 中的非法字符转换为合法字符,所以对于一些在 URI 中有特殊意义的字符不会进行转义。
encodeURIComponent 是对 URI 的组成部分进行转义,所以一些特殊字符也会得到转义。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dCmjCpfp-1682167755866)(media/image8.png)]escape 和 encodeURI 的作用相同,不过它们对于 unicode 编码为 0xff 之外字符的时候会有区别,escape 是直接在字符的 unicode编码前加上 %u,而 encodeURI 首先会将字符转换为 UTF-8 的格式,再在每个字节前加上 %。
对AJAX 的理解,实现一个 AJAX 请求
AJAX 是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的 异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
创建AJAX 请求的步骤:
创建一个 XMLHttpRequest 对象。
在这个对象上使用 open 方法创建一个 HTTP 请求,open 方法所需要的参数是请求的方法、请求的地址、是否异步和用户的认证信息。
在发起请求前,可以为这个对象添加一些信息和监听函数。比如说可以通过 setRequestHeader 方法来为请求添加头信息。还可以为这个对象添加一个状态监听函数。一个 XMLHttpRequest 对象一共有 5个状态,当它的状态变化时会触发onreadystatechange 事件,可以
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jEqmtW18-1682167755868)(media/image39.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u1y6Yum1-1682167755870)(media/image4.png)]通过设置监听函数,来处理请求成功后的结果。当对象的 readyState 变为 4 的时候,代表服务器返回的数据接收完成,这个时候可以通 过判断请求的状态,如果状态是 2xx 或者 304 的话则代表返回正常。这个时候就可以通过 response 中的数据来对页面进行更新了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-20aKZu5E-1682167755872)(media/image8.png)]当对象的属性和监听函数设置完成后,最后调用 sent 方法来向服务器发起请求,可以传入参数作为发送的数据体。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wrgzn45R-1682167755873)(media/image40.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2yD4vjue-1682167755875)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HbTC31Px-1682167755876)(media/image4.png)]什么是尾调用,使用尾调用有什么好处?
尾调用指的是函数的最后一步调用另一个函数。代码执行是基于执行栈的,所以当在一个函数里调用另一个函数时,会保留当前的执行上下文,然后再新建另外一个执行上下文加入栈中。使用尾调用的话,因为已经是函数的最后一步,所以这时可以不必再保留当前的执行上下文,从而节省了内存,这就是尾调用优化。但是 ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。
ES6 模块与 CommonJS 模块有什么异同?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sVWfscDu-1682167755878)(media/image8.png)]ES6 Module 和CommonJS 模块的区别:
CommonJS 是对模块的浅拷⻉,ES6 Module 是对模块的引⽤,即 ES6 Module 只存只读,不能改变其值,也就是指针指向不能变,类似 const;
import 的接⼝是 read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向,可以对 commonJS 对重新赋值(改变指针指向),但是对ES6 Module 赋值会
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i6XypFOp-1682167755880)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fCARvqMU-1682167755881)(media/image4.png)]for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;
对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;
总结:for…in 循环主要是为了遍历对象而生,不适用于遍历数组; for…of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。
24. ajax、axios、fetch 的区别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7HJ0KTrV-1682167755887)(media/image8.png)](1)AJAX
Ajax 即“AsynchronousJavascriptAndXML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。它是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r60tuV9a-1682167755888)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v7LBGROW-1682167755890)(media/image4.png)]起ajax 简单多。fetch 不是ajax 的进一步封装,而是原生 js,没有使用XMLHttpRequest 对象。
fetch 的优点:
语法简洁,更加语义化
基于标准 Promise 实现,支持 async/await
更加底层,提供的API 丰富(request, response)脱离了XHR,是ES 规范里新的实现方式
fetch 的缺点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lXBtbN9n-1682167755892)(media/image8.png)]fetch 只对网络请求报错,对 400,500 都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
fetch 默认不会带 cookie , 需要添加配置项: fetch(url,
{credentials: ‘include’})
监听请求和返回
对请求和返回进行转化取消请求
自动转换json 数据
客户端支持抵御XSRF 攻击
25. 对原型、原型链的理解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v7i5JBlB-1682167755893)(media/image8.png)]在JavaScript 中是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性,它的属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。当使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。一般来说不应该能够获取到这个值的,但是现在
浏览器中都实现了
proto 属性来访问这个属性,但是最好不要
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNHZRo9X-1682167755895)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TPQmg6wK-1682167755897)(media/image4.png)]
使用这个属性, 因为它不是规范中规定的。ES5 中新增了一个 Object.getPrototypeOf() 方法,可以通过这个方法来获取对象的原型。
当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是 Object.prototype 所以这就是新建的对象为什么能够使用 toString() 等方法的原因。
特点:JavaScript 对象是通过引用来传递的,创建的每个新对象实体中并没有一份属于自己的原型副本。当修改原型时,与之相关的对象也会继承这一改变。
(other objects) Functions (objects)
= new r‹.‹:.()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mZ6suW1c-1682167755898)(media/image41.png)]
proto
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vCjdqROl-1682167755902)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kGA73X5k-1682167755904)(media/image4.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pym6LluP-1682167755905)(media/image45.png)]proto
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I2VEy7dZ-1682167755914)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHnsygaZ-1682167755915)(media/image4.png)]由于Object 是构造函数,原型链终点 Object.prototype. proto ,而Object.prototype. proto === null // true,所以,原型链的终点是null。原型链上的所有原型都是对象,所有的对象最终都 是由Object 构造的,而Object.prototype 的下一级是 Object.prototype. proto 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HUKipr37-1682167755917)(media/image55.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2R0xqDBH-1682167755919)(media/image8.png)]27. 对作用域、作用域链的理解
- 全局作用域和函数作用域
(1)全局作用域
最外层函数和最外层函数外面定义的变量拥有全局作用域
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cAPNUnV0-1682167755921)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s4zBkcwO-1682167755923)(media/image4.png)]使用ES6 中新增的let 和const 指令可以声明块级作用域,块级作用域可以在函数中创建也可以在一个代码块中的创建(由{ }包裹的代码片段)
let 和const 声明的变量不会有变量提升,也不可以重复声明
在循环中比较适合绑定块级作用域,这样就可以把声明的计数器变量限制在循环内部。
作用域链:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UFTcL0vR-1682167755924)(media/image8.png)]在当前作用域中查找所需变量,但是该作用域没有这个变量,那这个变量就是自由变量。如果在自己作用域找不到该变量就去父级作用域查找,依次向上级作用域查找,直到访问到 window 对象就被终止,这一层层的关系就是作用域链。
作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,可以访问到外层环境的变量和函数。
作用域链的本质上是一个指向变量对象的指针列表。变量对象是一个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6ND19Jw-1682167755927)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pp2wGpRc-1682167755928)(media/image4.png)]第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时, this 指向这个对象。
第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OvxApJ4F-1682167755930)(media/image8.png)]第四种是 apply 、 call 和 bind 调用模式,这三个方法都可以显 示的指定调用函数的 this 指向。其中 apply 方法接收两个参数: 一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举 出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对 象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其 他情况下都不会改变。
这四种方式,使用构造器调用模式的优先级最高,然后是 apply、call和 bind 调用模式,然后是方法调用模式,然后是函数调用模式。
call() 和 apply() 的区别?
它们的作用一模一样,区别仅在于传入参数的形式的不同。
apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类 数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。
call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wyynajM6-1682167755932)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KPMnn1e-1682167755934)(media/image4.png)]异步编程的实现方式?
JavaScript 中的异步机制可以分为以下几种:
回调函数 的方式,使用回调函数的方式有一个缺点是,多个回调函数嵌套的时候会造成回调函数地狱,上下两层的回调函数间的代码耦合度太高,不利于代码的可维护。
Promise 的方式,使用 Promise 的方式可以将嵌套的回调函数作为链式调用。但是使用这种方法,有时会造成多个 then 的链式调用,可能会造成代码的语义不够明确。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-07GTt19X-1682167755937)(media/image8.png)]generator 的方式,它可以在函数的执行过程中,将函数的执行权转移出去,在函数外部还可以将执行权转移回来。当遇到异步函数执行的时候,将函数执行权转移出去,当异步函数执行完毕时再将执行权给转移回来。因此在 generator 内部对于异步操作的方式,可以以同步的顺序来书写。使用这种方式需要考虑的问题是何时将函数的控制权转移回来,因此需要有一个自动执行 generator 的机制,比如
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0NyNq7z-1682167755938)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S1BG06yo-1682167755940)(media/image4.png)]Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
- Promise 的实例有三个状态:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FK2zgcUO-1682167755942)(media/image8.png)]Pending(进行中) Resolved(已完成) Rejected(已拒绝)
当把一件事情交给promise 时,它的状态就是Pending,任务完成了状态就变成了Resolved、没有完成失败了就变成了Rejected。
- Promise 的实例有两个过程:
pending -> fulfilled : Resolved(已完成) pending -> rejected:Rejected(已拒绝)
注意:一旦从进行状态变成为其他状态就永远不能更改状态了。 Promise 的特点:
对象的状态不受外界影响。promise 对象代表一个异步操作,有三种状态,pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也是 promise 这个名字的由来——“承诺”;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FqTWo3Ln-1682167755944)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQi4crll-1682167755946)(media/image4.png)]一旦状态改变就不会再变,任何时候都可以得到这个结果。promise对象的状态改变,只有两种可能:从 pending 变为 fulfilled,从 pending 变为 rejected。这时就称为 resolved(已定型)。如果改变已经发生了,你再对 promise 对象添加回调函数,也会立即得到这个结果。这与事件(event)完全不同,事件的特点是:如果你错过了它,再去监听是得不到结果的。
Promise 的缺点:
无法取消Promise,一旦新建它就会立即执行,无法中途取消。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xPlVHyIs-1682167755948)(media/image8.png)]如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
当处于pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
总结:
Promise 对象是异步编程的一种解决方案,最早由社区提出。Promise是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例。一个 Promise 实例有三种状态, 分别是 pending、resolved 和 rejected,分别代表了进行中、已成功和已失败。实例的状态只能由 pending 转变 resolved 或者rejected 状态,并且状态一经改变,就凝固了,无法再被改变了。
状态的改变是通过 resolve() 和 reject() 函数来实现的,可以在异步操作结束后调用这两个函数改变 Promise 实例的状态,它的原型上定义了一个 then 方法,使用这个 then 方法可以为两个状态的改变注册回调函数。这个回调函数属于微任务,会在本轮事件循环的末尾执行。
注意:在构造 Promise 的时候,构造函数内部的代码是立即执行的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvPzrWGR-1682167755949)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EwJGdmzt-1682167755952)(media/image4.png)]Promise 解决了什么问题
在工作中经常会碰到这样一个需求,比如我使用ajax 发一个A 请求后,成功后拿到数据,需要把数据传给 B 请求;那么需要如下编写代码:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fm4nAIGX-1682167755954)(media/image56.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mnCo74k7-1682167755956)(media/image8.png)]上面的代码有如下缺点:
后一个请求需要依赖于前一个请求成功后,将数据往下传递,会导致多个ajax 请求嵌套的情况,代码不够直观。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tc73PHrC-1682167755958)(media/image57.jpeg)]如果前后两个请求不需要传递参数的情况下,那么后一个请求也需要前一个请求成功后再执行下一步操作,这种情况下,那么也需要如上编写代码,导致代码不够直观。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmgI7XnI-1682167755959)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rIYIUDHC-1682167755960)(media/image4.png)]对async/await 的理解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dyrodpDV-1682167755962)(media/image8.png)]async/await 其实是 Generator 的语法糖,它能实现的效果都能用 then 链来实现,它是为优化then 链而开发出来的。从字面上来看, async 是“异步”的简写,await 则为等待,所以很好理解async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。当然语法上强制规定 await 只能出现在asnyc 函数中,先来看看async 函数返回了什么:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zYqIyO9h-1682167755963)(media/image58.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bCPLZaWi-1682167755963)(media/image59.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZ5KYj59-1682167755964)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rW6EP6iI-1682167755972)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ErjEk7mf-1682167755973)(media/image60.jpeg)]
那如果 async 函数没有返回值,又该如何?很容易想到,它会返回 Promise.resolve(undefined)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SizrCSVu-1682167755975)(media/image8.png)]联想一下 Promise 的特点——无等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。
注意:Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的简写,可以用于快速封装字面量对象或其他对象,将其封装成 Promise 实例。
async/await 的优势
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YDGAh2ZC-1682167755976)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TrG7nllw-1682167755977)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-31kVVz8V-1682167755979)(media/image61.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5sZKtAnM-1682167755980)(media/image8.png)]现在用 Promise 方式来实现这三个步骤的处理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lthSYNZ0-1682167755983)(media/image62.jpeg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-atyGbD5O-1682167755985)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t7st6G9T-1682167755986)(media/image4.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IpTWG3Ek-1682167755987)(media/image63.jpeg)]
结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样
async/await 对比 Promise 的优势
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dvGR5Sx-1682167755989)(media/image8.png)]代码读起来更加同步,Promise 虽然摆脱了回调地狱,但是 then 的链式调⽤也会带来额外的阅读负担
Promise 传递中间值⾮常麻烦,⽽async/await⼏乎是同步的写法,
⾮常优雅
错误处理友好,async/await 可以⽤成熟的 try/catch,Promise 的错误捕获⾮常冗余
调试友好,Promise 的调试很差,由于没有代码块,你不能在⼀个返回表达式的箭头函数中设置断点,如果你在⼀个.then 代码块中使⽤调试器的步进(step-over)功能,调试器并不会进⼊后续的.then 代码块,因为调试器只能跟踪同步代码的每⼀步。
- 对象创建的方式有哪些?
一般使用字面量的形式直接创建对象,但是这种创建方式对于创建大量相似对象的时候,会产生大量的重复代码。但 js 和一般的面向对象的语言不同,在 ES6 之前它没有类的概念。但是可以使用函数来进行模拟,从而产生出可复用的对象创建方式,常见的有以下几种:
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gued9BAW-1682167755991)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2A1gd5TK-1682167755992)(media/image4.png)]第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来,它只是简单的封装了复用代码,而没有建立起对象和类型间的关系。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yZKX34nr-1682167755993)(media/image8.png)]第二种是构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么就可以把它称为构造函数。执行构造函数首先会创建一个对象,然后将对象的原型指向构造函数的 prototype 属性,然后将执行上下文中的 this 指向这个对象,最后再执行整个函数,如果返回值不是对象,则返回新建的对象。因为 this 的值指向了新建的对象,因此可以使用 this 给对象赋值。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此可以通过原型来识别对象的类型。但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建,因为在 js 中函数也是一个对象,因此如果对象属性中如果包含函数的话,那么每次都会新建一个函数对象,浪费了不必要的内存空间,因为函数是所有的实例都可以通用的。
-
第三种模式是原型模式,因为每一个函数都有一个 prototype属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。因此可以使用原型对象来添加公用属性和方法,从而实现代码的复用。这种方式相对于构造函数模式来说,解决了函数对象的复用问题。但是这种模式也存在一些问题,一个是没有办法通过传入参数来初始化值,另一个是如果存在一个引用类型如 Array 这样的值,那么所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MFnBA1wS-1682167755994)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-edpNJxk8-1682167755995)(media/image4.png)]第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。因为构造函数模式和原型模式分开使用都存在一些问题,因此可以组合使用这两种模式,通过构造函数来初始化对象的属性,通过原型对象来实现函数方法的复用。这种方法很好的解决了两种模式单独使用时的缺点,但是有一点不足的就是,因为使用了两种不同的模式,所以对于代码的封装性不够好。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i9M3zRsD-1682167755996)(media/image8.png)]第五种模式是动态原型模式,这一种模式将原型方法赋值的创建过程移动到了构造函数的内部,通过对属性是否存在的判断,可以实现仅在第一次调用函数时对原型对象赋值一次的效果。这一种方式很好地对上面的混合模式进行了封装。
-
第六种模式是寄生构造函数模式,这一种模式和工厂模式的实现基本相同,我对这个模式的理解是,它主要是基于一个已有的类型,在实例化时对实例化的对象进行扩展。这样既不用修改原来的构造函数,也达到了扩展对象的目的。它的一个缺点和工厂模式一样,无法实现对象的识别。
对象继承的方式有哪些?
-
第一种是以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向超类型传递参数。
-
第二种方式是使用借用构造函数的方式,这种方式是通过在子 类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不 能向超类型传递参数的缺点,但是它存在的一个问题就是无法实现函 数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b5dtjBDG-1682167755998)(media/image1.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OUCMs9T-1682167755999)(media/image4.png)]
-
第三种方式是组合继承,组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以超类型的实例来作为子类型的原型,所以调用了两次超类的构造函数,造成了子类型的原型中多了很多不必要的属性。
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ihTxRk6E-1682167756000)(media/image8.png)]第四种方式是原型式继承,原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。
-
第五种方式是寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是自定义类型时。缺点是没有办法实现函数的复用。
-
第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。
哪些情况会导致内存泄漏
以下四种情况会造成内存的泄漏:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-33upTUHE-1682167756002)(media/image64.jpeg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vP9DQISc-1682167756003)(media/image4.png)]意外的全局变量:由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
被遗忘的计时器或回调函数:设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
脱离 DOM 的引用:获取一个 DOM 元素的引用,而后面这个元素被删除,由于一直保留了对这个元素的引用,所以它也无法被回收。
闭包:不合理的使用闭包,从而导致某些变量一直被留在内存当中。
就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是自定义类型时。缺点是没有办法实现函数的复用。
- 第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。
哪些情况会导致内存泄漏
以下四种情况会造成内存的泄漏:
[外链图片转存中…(img-33upTUHE-1682167756002)][外链图片转存中…(img-vP9DQISc-1682167756003)]意外的全局变量:由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
被遗忘的计时器或回调函数:设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
脱离 DOM 的引用:获取一个 DOM 元素的引用,而后面这个元素被删除,由于一直保留了对这个元素的引用,所以它也无法被回收。
闭包:不合理的使用闭包,从而导致某些变量一直被留在内存当中。