1.JavaScript 中的垃圾回收机制
定义:指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。
JavaScript在创建对象时会为它们分配内存,不再使用时会自动释放内存,这个过程称为垃圾收集。
四种常见的内存泄漏:
- 全局变量 不用var声明的变量,相当于挂载到window对象上,解决:使用严格模式
- 未清除的定时器
- 闭包
- dom的引用:没有清理的dom元素引用
2.跨域解决方案
- (后端)服务器配置CORS(跨域资源共享)
- (后端)node.js或Nginx反向代理,把跨域改造成同域
- (前端)将JSON升级为JSONP在JSON基础上,利用 script 标签可以跨域的特性,加上头设置
3.事件传播的三个阶段
捕获 > 目标 > 冒泡
在捕获阶段,事件通过父元素向下传递到目标元素
然后到达目标元素,冒泡开始
4.JavaScript中作用域是指什么?
在JavaScript中,每个函数都有自己的作用域。
作用域基本上是变量以及如何通过名称访问这些变量的规则的集合。
只有函数汇总的代码才能访问函数作用域内的变量。
在同一个作用域中的变量名必须是唯一的。一个作用域可以嵌套在另一个作用域内。如果一个作用域嵌套在另一个作用域内,最内部作用域的代码可以访问另一个作用域的变量。
5.JavaScript中的null和undefined
- null 表示一个空的对象,什么也没有
- undefined 表示声明未赋值
- undefined 是从null派生出来的
null == undefined // true
null === undefined // false
typeof(null) // object
typeof(undefined) // undefined
6.什么是防抖和节流?有什么区别?如何实现?
防抖
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算事件。
应用场景:
- 搜索框输入查询
- 表单验证
- 按钮提交事件
思路:每次触发事件时都取消之前的延时调用方法
节流
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
使用场景:
- 按钮点击事件
- 拖拽事件
- onSroll
思路:每次触发事件时都判断当前是否有等待执行的延时函数
7.简述JavaScript原型、原型链?有什么特点?
原型:
- 每一个构造函数都有一个 prototype 属性指向一个对象,这个对象就是构造函数实例的原型
原型链:
- 每一个实例都有以__proto__属性执行原型对象,来获取原型对象上的属性和方法,原型对象中也有一个__proto__属性指向另外一个原型对象,以此类推,直到原型链的最终端null为止,这个串成链的过程就是原型链
特点:
- 实现继承一个对象可以拿到另一个对象的属性和方法
- 构造函数都有一个prototype属性指向原型对象
- 原型对象都有一个constructor属性指向构造函数
- 构造函数 new 实例化实例对象
- 对象上有__proto属性指向原型
8.JS数据类型有哪些
8种数据类型:
- 基本数据类型
- string
- number
- boolean
- undefined
- null
- symbol (ES6)
- bigInt (ES6)
- 引用数据类型
- object
9.描述一下 cookies,sessionStorage 和 localStorage 的区别?
- cookie 是浏览器自动携带在请求里发送给服务端去验证的,sessionStorage 和 localStorage 不会自动携带
- cookie体积相对sessionStorage 和 localStorage 小
- 后端可以设置cookie之后,前端修改不了的
- cookie可以设置过期时间
- cookie是用来做状态保持的,因为http请求时无状态的
- cookie是用户第一次访问服务器服务器分发给浏览器的,第二次请求就会携带
- sessionStorage存储在内存中,关闭浏览器数据会消失
- localStorage 关闭浏览器数据不会消失,需要手动清除
10.介绍一下 XMLhttprequest 对象
Ajax 的核心是 JavaScript对象 XMLHttpRequest。该对象在 Internet Explorer5中首次引入,是一种支持异步请求的技术。通过XMLHttpRequest对选哪个,开发人员可以在页面加载以后进行页面的局部更新。
11.JS异步编程的几种方式及区别
- js 是单线程语言
- 所谓异步,就是指在执行一件任务,这件任务分A、B两个阶段,执行完A阶段后,需要去做另外一个任务得到结果后才能执行B阶段。
- 异步编程有以下几种常用方式:callback、Promise、Generator、async。
1.callback
指通过函数传参传递到其他执行代码的,某一块可执行代码的引用,被主函数调用后又回到主函数
缺点:如果存在多个任务,需要层层嵌套,形成回调地狱,代码会显得冗余且耦合度很高。降低代码的阅读性和可维护性
2.promise
Promise是一个对象,可以获取异步操作的消息。
Promise对象有两个特点:
- 对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:pending,resolved和rejected
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果
常用于解决异步回调问题,可以将回调函数的嵌套改为链式调用。
优点:解决回调地狱
缺点:还是有些多余的代码,如被Promise包装的函数有一堆的new Promise、then、catch
3.generator函数
是ES6提供的一种异步解决方案,由每执行一次函数返回的是一个遍历器对象,返回的对象可以依次遍历Generator里面的每一个状态
需要用遍历器对象的next方法来执行函数
Generator有三个特征:
- 函数命名时function后面需要加*
- 函数内部有yield;外部执行需要调用next方法。
- 每个yield会将跟在她后面的值包裹成一个对象的返回,
返回的对象中包括返回值和函数运行状态,直到return,
返回done为true。
优点:相比Promise在写法上更加精简且逻辑清晰
4.async
是Generator函数的语法糖
相比Generator函数,async函数在写法上的区别就是async替代了*,await替代了yield,并且async自带执行器
async函数返回的Promise,必须等到函数体内所有await后面的Promise对象都执行完毕后,或者return或者抛错之后才能改变状态;也就是只有async里面的异步操作全部操作完,才能回到主任务来,并且在then方法里面继续执行主任务。
async与Promise、Generator函数之间的对比
- Promise虽然很好的解决了地狱回调的问题,但是代码中有很多与语义无关的then、
- Generator函数需要自动执行器来执行函数,且yield后面只能是Promise对象或者Thunk函数。
- async 函数的实现最简洁,最符合语义,几乎没有语义不相关的代码。与Generator相比不需要程序员再提供一个执行器,async本身自动执行,使用起来方便简洁。
// callback异步
function callback() {
let readFile;
readFile(fileA, function (data) {
readFile(fileB, function (data) {
// ......
});
});
}
// promise
function getData() {
let require = new Promise((res, rej) => {
res(), rej();
});
require
.then((res) => {
let result = res.data;
})
.catch((err) => {
let error = err.message;
});
}
// generator
function * foo(){
yield getFirstData;
yield getSecondData;
return getThirdData
}
let require = foo()
require.next()
require.next()
// async
let getListData = async function(){
let result = await reqGetListData()
if(result.code = 200){
// ...
}
}
11.什么是闭包?为什么要用它?
闭包: 子函数调用父函数上的变量,返回给外界去使用,那么称子函数就是一个闭包
优点:缓存数据
缺点:内存泄漏,溢出
闭包作用:自执行函数,不会污染全局变量,形成块儿级作用域 变量私有化