闭包是什么?利弊?如何解决弊端?
闭包是什么:JS中内层函数可以访问外层函数的变量,外层函数无法操作内层函数的变量的特性。我们把这个特性称作闭包。
闭包的好处:
隔离作用域,保护私有变量;有了闭包才有局部变量,要不然都是全局变量了。实现结果缓存
让我们可以使用回调,操作其他函数内部;
变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期;
实现类和继承
闭包的弊端:内层函数引用外层函数变量,内层函数占用内存。如果不释放内存,过多时,易引起内存泄露。
解决办法:无法自动销户,就及时手动回收,使用后将函数的引用赋null。
let,const和var有什么区别?
变量提升:var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined。let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
重复声明:var允许重复声明变量。let和const在同一作用域不允许重复声明变量
暂时性死区:var不存在暂时性死区。let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
变量修改:const 声明的变量不能被重新赋值,而 let 和 var 可以。但是,使用 const 声明的对象或数组可以修改它们的属性或元素。
块级作用域:let 和 const 声明的变量具有块级作用域,可以在不同的块中重新定义变量。而使用 var 声明的变量在不同的块中被重新定义,会影响整个函数的作用域。
javascript有几种数据类型?分别是什么?
基本数据类型:Number、String、Boolean、BigInt(ES6)、Symbol(ES6)、Null、Undefined
引用数据类型:Object
常用的数组方法
push:向数组末尾添加一个或多个元素,并返回新数组的长度
pop:从数组末尾删除一个元素,并返回该元素的值
shift:从数组开头删除一个元素,并返回该元素的值
unshift:向数组开头添加一个或多个元素,并返回新数组的长度
splice:从数组中删除或替换一个或多个元素,可以传入三个参数,分别是开始位置、要删除的元素数量、插入的元素(一直与slice记混,重点记一下)
slice:返回数组的一个片段或子数组,可以传入两个参数,分别是开始索引位置、截取到的索引位置
concat:将两个或多个数组合并成一个新数组
join:将数组元素连接成一个字符串
indexOf():返回要查找的元素在数组中的位置,如果没找到则返回 -1
includes():返回要查找的元素在数组中的位置,找到返回true,否则false
find():返回第一个匹配的元素
reverse:将数组元素反转
sort:对数组元素进行排序
map:对数组中的每个元素执行指定的函数,并返回一个新数组
filter:对数组中的每个元素执行指定的测试函数,并返回一个新数组,其中包含所有通过测试的元素
reduce:对数组中的每个元素执行指定的累加器函数,并返回一个累加器值。(这个函数在实际开发中是一个特别好用的方法,如果能用好可以大大提高开发效率)
forEach:对数组中的每个元素执行指定的函数,无返回值
需要留意的是哪些方法会对原数组产生影响,哪些方法不会,这也是一个比较重要的特性
会改变原数组的方法:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
ES6 新增哪些东西?
箭头函数;字符串模板;支持模块化(import、export);类(class、constructor、extends);let、const 关键字;新增一些数组、字符串等内置构造函数方法,例如 Array.from、Array.of 、Math.sign、Math.trunc 等;新增一些语法,例如扩展操作符、解构、函数默认参数等;新增一种基本数据类型 Symbol;新增元编程相关,例如 proxy、Reflect;Set 和 Map 数据结构;Promise;Generator 生成器
防抖和节流
我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求,onmousemove、resize、onscroll 等,有些时候,我们并不能或者不想频繁触发事件,这时候就应该用到函数防抖和函数节流。
函数防抖(debounce),指的是短时间内多次触发同一事件,只执行最后一次,或者只执行最开始的一次,中间的不执行。
函数节流(throttle),指连续触发事件但是在 n 秒中只执行一次函数。即 2n 秒内执行 2 次... 。节流如字面意思,会稀释函数的执行频率。
async 与 await 的作用
async 是一个修饰符,async 定义的函数会默认的返回一个 Promise 对象 resolve 的值,因此对 async 函数可以直接进行 then 操作,返回的值即为 then 方法的传入函数。
await 关键字只能放在 async 函数内部, await 关键字的作用就是获取 Promise 中返回的内容, 获取的是 Promise 函数中 resolve 或者 reject 的值。
JS的垃圾回收站机制
JS 常见的垃圾回收方式:标记清除、引用计数方式。
标记清除方式:
工作原理:当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
工作流程:
垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记;
去掉环境中的变量以及被环境中的变量引用的变量的标记;
被加上标记的会被视为准备删除的变量;
垃圾回收器完成内存清理工作,销毁那些带标记的值并回收他们所占用的内存空间。
引用计数方式:
工作原理:跟踪记录每个值被引用的次数。
工作流程:
声明了一个变量并将一个引用类型的值赋值给这个变量,这个引用类型值的引用次数就是 1;
同一个值又被赋值给另一个变量,这个引用类型值的引用次数加1;
当包含这个引用类型值的变量又被赋值成另一个值了,那么这个引用类型值的引用次数减 1;
当引用次数变成 0 时,说明没办法访问这个值了;
当垃圾收集器下一次运行时,它就会释放引用次数是0的值所占的内存。
纯函数
对于相同的输入,永远得到相同的输出
没有任何可观察到的副作用
bind、call、apply 区别?
call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向
apply:接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入
改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
call:方法的第一个参数也是this的指向,后面传入的是一个参数列表
跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
bind:方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)改变this指向后不会立即执行,而是返回一个永久改变this指向的函数
js数据类型判断的方式
typeof、instanceof、Object.prototype.toString.call()(对象原型链判断方法)、 constructor (用于引用数据类型)
typeof:常用于判断基本数据类型,对于引用数据类型除了function返回function,其余全部返回object。
instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上
constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同
浅拷贝和深拷贝
浅拷贝是指创建一个新对象,将原对象中的属性值复制到新对象中,如果属性值是一个引用类型数据,那么新对象中的属性值仍然是原对象中的引用,也就是说,新对象和原对象中的引用类型数据共享一份内存空间。这意味着,如果修改了新对象中的引用类型数据,那么原对象中对应的属性值也会受到影响。
在JavaScript中,存在浅拷贝的现象有:
Object.assign
Array.prototype.slice(), Array.prototype.concat()
使用拓展运算符实现的复制
深拷贝是指创建一个新对象,将原对象中的属性值复制到新对象中,如果属性值是一个引用类型数据,那么新对象中的属性值是原对象中属性值的一个完全独立的副本,也就是说,新对象和原对象中的引用类型数据不共享任何内存空间。这意味着,修改新对象中的引用类型数据不会影响原对象中对应的属性值。
常见的深拷贝方式有:
JSON.stringify()
手写循环递归
函数式编程
简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论
它具有以下特性:闭包和高阶函数、惰性计算、递归、函数是"第一等公民"、只用"表达式"
原型与原型链
每个对象都有一个 __proto__ 属性,该属性指向自己的原型对象
每个构造函数都有一个 prototype 属性,该属性指向实例对象的原型对象
原型对象里的 constructor 指向构造函数本身
作用域与作用域链
作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6 的到来,为我们提供了块级作用域。
作用域链指的是作用域与作用域之间形成的链条。当我们查找一个当前作用域没有定义的变量(自由变量)的时候,就会向上一级作用域寻找,如果上一级也没有,就再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链 。
简述ajax的优缺点
优点:
无刷新更新数据(在不刷新整个页面的情况下维持与服务器通信)
异步与服务器通信(使用异步的方式与服务器通信,不打断用户的操作)
前端和后端负载均衡(将一些后端的工作交给前端,减少服务器与宽度的负担)
界面和应用相分离(ajax将界面和应用分离也就是数据与呈现相分离)
缺点:
ajax不支持浏览器back按钮
安全问题 Aajax暴露了与服务器交互的细节
对搜索引擎的支持比较弱
破坏了Back与History后退按钮的正常行为等浏览器机制