酷家乐面试
什么前端路由?前端路由的优缺点
- 前端路由不同于传统路由,它不需要服务器来进行解析,而是通过一个hash函数或者H5提供的history API来实现。在进行开发时,路由用来设定访问路径,并将路径与相应的组件映射起来,用户在访问相应的路径时,路由根据映射关系实现不同组件间的切换,整个过程都是在同一个页面中实现,不涉及页面间的跳转,也就是我们常说的单页应用。
- 优点:
- 页面刷新速度快
- 复用性强
- 页面状态可记录
- 缺点: 使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
常见的块级元素、行内元素、行内-块元素
- 块元素:dir、div、h1-h6、form、menu、ol、ul、li、table
- 行内元素:a、br、img、input、select
- 行内-块元素:img、input
sessionstorage、localstorage、cookies的区别以及好坏处
- 区别:
- cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递
- cookie数据还有路径(path)的概念,可以限制。cookie只属于某个路径下
- cookie数据不能超过4K , webStorage可以达到5M或更大
- 数据的有效期不同
- sessionStorage:仅在当前的浏览器窗口关闭有效
- localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据
- cookie:只在设置的cookie过期时间之前一直有效,即使窗口和浏览器关闭
- 作用域不同
- sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面
- localStorage:在所有同源窗口都是共享的
- cookie:也是在所有同源窗口中共享的
- 优缺点:
- cookie:优点:内存小。缺点: 限制大小, 每次随http请求一起发送,浪费宽带
- localstorage:优点: 可以大量保存浏览器中数据;不会随http请求一起发送。缺点: 不同窗口下数据不能独立,会相互干扰; 不能被爬虫读取; 在浏览器的隐私模式下不能读取; 写入数据量大的话会卡
- sessionstorage:优点: 可以大量保存浏览器中数据 ; 不同窗口下的sessionStorage,存储相互独立;互不干扰。缺点:数据不共享。
ES6新特性
新增了let 和const用于定义变量。set和map,也添加了箭头函数,扩展运算符... 数组和对象的解构,symbol,promise、class、async和await
聊一聊箭头函数
箭头函数是ES6引入的新特性,简化了原有的函数声明。与普通函数的区别在:
- 箭头函数没有this指针,所以要通过作用域链来寻找最近的有this的作用域并获取其this
- 当参数只有一个时可以省略()
- 当只有一个返回值并且只有一条语句时,可以省略return和{}
- 箭头函数没有自己的arguments,所以可以通过访问上一层的arguments或者使用rest参数
- 不能通过new来调用,意味着箭头函数不能用于构造函数
rest
...变量名,是数组
作用域
JavaScript的作用域包括全局作用域和局部作用域。作用域决定了其内部变量的访问性,在作用域内部的变量是无法在作用域外部访问的
垃圾回收机制
在程序运行过程中,系统会分配内存给程序使用,但是程序如果运行时间长的话,就必须及时进行垃圾回收来释放内存,防止内存占用过多导致崩溃。
垃圾回收有两种方式:1、标记清除。2、引用计数
- 标记清除。垃圾回收器会将内存中所有的变量都添加上标记,然后把在用的变量的标记删除,因为这些变量正在被使用,不能进行回收。剩下的变量都是不被使用的,理论上是可以进行回收的。最后垃圾回收器会回收那些带有标记的变量,释放其内存。
- 引用计数。用于跟踪变量被引用的次数。声明了一个变量并将引用类型的值赋给它时,该值的引用次数为1。如果这个这又被赋给另一个变量,该值引用次数加1,如果包含这个值的变量引用了另一个值,该值引用次数减1,如果该值引用次数减为0了,那么说明这个值无法被访问了,就可以将其所占用的内存释放了。
map和set
- map:用于保存键值对。类似于Object。
- 与Object的区别:1、object的键只能是字符串或者symbol。map可以为任何值,对象、数组都可以;2、map的键值对个数可以用size获取,而object只能用循环或者使用Object.keys().length获取
- 属性:size
- 方法:set、get、has、delete、clear
- set:类似于数组,但是set允许存放任何值,且值唯一,不会重复
- 属性:size
- 方法:add、delete、has、clear
async/await
async: 返回一个promise对象,也就是async声明的函数就是内部不是异步的,使用该函数的效果也是异步的,因为是返回了一个promise对象。
await:只能用在async内部,使用await之后会阻塞线程,等待函数执行完
bigInt
- big int 特殊的数字类型,支持任意长度的整数
- 使用可以在长整数后添加n或者使用BigInt(10)
- 不支持前置+
事件循环
JS主线程不断的循环往复的从任务队列中读取任务,执行任务,其中运行机制称为事件循环
一个 Event Loop 中,可以有一个或者多个任务队列(task queue),一个任务队列便是一系列有序任务(task)的集合;每个任务都有一个任务源(task source),源自同一个任务源的 task 必须放到同一个任务队列,从不同源来的则被添加到不同队列
BFC
BFC (块级格式化上下文),是一个独立的渲染区域,让处于 BFC
内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
清除浮动
- 使用clear:left,right,both;的空元素
- 使用overflow:hidden,auto;
- 给:after添加clear
- 给浮动元素后面的元素添加clear
隐藏元素
- display:none
- visibility:hidden
- opacity:0
- z-index:-1
设置两栏布局
- 两个div,一个设置float,另一个不用做处理
- 三个div,父元素设置relative,子元素设置absolute
- 三个div,父元素设置display:flex;子元素设置flex
ES6 let const var 之间的区别
- var声明的变量是全局或者整个函数块的, let,const声明的变量是块级的变量
- var声明的变量存在变量提升,let,const不存在
- let、var声明的变量允许重新赋值,const不允许
Vue,JQuery 与原生 JS 区别?对比、优缺点
- JQuery和原生js是事件驱动的,vue是数据驱动的
- JQuery和原生js是直接操作dom的,业务逻辑与ui混杂,且交互事件也在ui中,所以使得整个页面很混乱
- vue的数据是双向绑定的,JQuery和原生js不是
写一个深拷贝
function isObj(obj) {
return obj instanceof Object;
}
function deepCopy(obj) {
let copy;
switch (typeof obj) {
case 'undefined':
break;
case 'number':
copy = obj + 0;
break;
case 'string':
copy = obj + '';
break;
case 'boolean':
copy = obj;
break;
case 'object':
copy = null;
if (obj instanceof Array) {
copy = [];
for (let value of obj) {
if (!isObj(value)) copy.push(value);
else {
let tempValue = deepCopy(value);
copy.push(tempValue);
}
}
} else if (obj instanceof Object) {
copy = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
let value = obj[key];
if (!isObj(value)) copy[key] = value;
else {
let tempValue = deepCopy(value);
copy[key] = tempValue;
}
}
}
}
}
return copy;
}
扩展运算符属于深拷贝还是浅拷贝
如果扩展的数组或对象是一层的,元素只是简单的类型,是深拷贝
如果扩展的数组或对象的元素也是个引用类型,是浅拷贝
https和http的区别
http传输的数据都是未加密的,也就是明文的,网景公司设置了SSL协议来对http协议传输的数据进行加密处理,简单来说https协议是由http和ssl协议构建的可进行加密传输和身份认证的网络协议,比http协议的安全性更高。
主要的区别如下:
Https协议需要ca证书,费用较高。
http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
使用不同的链接方式,端口也不同,一般而言,http协议的端口为80,https的端口为443
http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
什么是跨域,为什么出现跨域问题
- 跨域: 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
- 为什么: 出于浏览器的同源策略限制 , 如果缺少了同源策略,则浏览器的正常功能可能都会受到影响
- 解决跨域问题
- 设置document.domain解决无法读取非同源网页的 Cookie问题
- 使用跨文档通信API
- jsonp
- cors
- 普通跨域请求:只需服务器端设置Access-Control-Allow-Origin
- 带cookie跨域请求:前后端都需要进行设置
GET和POST的区别
- get参数通过url传递,post放在request body中。
- get请求在url中传递的参数是有长度限制的,而post没有。
- get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
- get请求只能进行encodeURI编码,而post支持多种编码方式
- get请求会浏览器主动cache,而post支持多种编码方式。
- get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
TCP与UDP的区别
- TCP是面向连接的,udp是无连接的即发送数据前不需要先建立链接。
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。 并且因为tcp可靠,面向连接,不会丢失数据因此适合大数据量的交换。
- TCP是面向字节流,UDP面向报文,并且网络出现拥塞不会使得发送速率降低(因此会出现丢包,对实时的应用比如IP电话和视频会议等)。
- TCP只能是1对1的,UDP支持1对1,1对多。
- TCP的首部较大为20字节,而UDP只有8字节。
- TCP是面向连接的可靠性传输,而UDP是不可靠的。
说一下http
超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少
说一下https
是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
输入url后的过程
输入url后,首先需要找到这个url域名的服务器ip,为了寻找这个ip,浏览器首先会寻找缓存,查看缓存中是否有记录,缓存的查找记录为:浏览器缓存-》系统缓存-》路由器缓存,缓存中没有则查找系统的hosts文件中是否有记录,如果没有则查询DNS服务器,得到服务器的ip地址后,浏览器根据这个ip以及相应的端口号,构造一个http请求,这个请求报文会包括这次请求的信息,主要是请求方法,请求说明和请求附带的数据,并将这个http请求封装在一个tcp包中,这个tcp包会依次经过传输层,网络层,数据链路层,物理层到达服务器,服务器解析这个请求来作出响应,返回相应的html给浏览器,因为html是一个树形结构,浏览器根据这个html来构建DOM树,在dom树的构建过程中如果遇到JS脚本和外部JS连接,则会停止构建DOM树来执行和下载相应的代码,这会造成阻塞,这就是为什么推荐JS代码应该放在html代码的后面,之后根据外部央视,内部央视,内联样式构建一个CSS对象模型树CSSOM树,构建完成后和DOM树合并为渲染树,这里主要做的是排除非视觉节点,比如script,meta标签和排除display为none的节点,之后进行布局,布局主要是确定各个元素的位置和尺寸,之后是渲染页面,因为html文件中会含有图片,视频,音频等资源,在解析DOM的过程中,遇到这些都会进行并行下载,浏览器对每个域的并行下载数量有一定的限制,一般是4-6个,当然在这些所有的请求中我们还需要关注的就是缓存,缓存一般通过Cache-Control、Last-Modify、Expires等首部字段控制。 Cache-Control和Expires的区别在于Cache-Control使用相对时间,Expires使用的是基于服务器 端的绝对时间,因为存在时差问题,一般采用Cache-Control,在请求这些有设置了缓存的数据时,会先 查看是否过期,如果没有过期则直接使用本地缓存,过期则请求并在服务器校验文件是否修改,如果上一次 响应设置了ETag值会在这次请求的时候作为If-None-Match的值交给服务器校验,如果一致,继续校验 Last-Modified,没有设置ETag则直接验证Last-Modified,再决定是否返回304
JS的事件捕获和事件冒泡
- 事件冒泡:ie提出,事件由开始最具体的元素开始接收,然后向上一级元素传递
- 事件捕获:网景提出,由外部元素先响应事件,然后再向内传递事件
- 阻止冒泡:event.stopPropagation();用event.target == this;addeventlistener( , , true)
- 阻止捕获:event.preventDefault();addeventlistener(,, false)
target 和currenttargt区别
currentTarget当前所绑定事件的元素
target当前被点击的元素
null和undefined的区别
- 意义不一样。null表示没有对象。此处没有值;undefined表示应该有值,但是没定义
- 类型不一样。
- 转为值时不一样。null转为0;undefined转为NaN
手写new关键字
function myNew() {
// 创建一个空对象
let obj = new Object();
// shift删除数组第一个元素,并返回一个元素。原有arguments数组第一个参数是构造函数,返回值为构造函数。
const Constructor = [].shift.call(arguments);
// 将 obj 的原型指向构造函数,这样 obj 就可以访问到构造函数原型中的属性
obj.__proto__ = Construtor.prototype;
// 执行构造函数的方法
const ret = Constructor.apply(obj, arguments);
// 返回构造函数中有返回值且返回值是个引用类型,没有返回值则默认返回这个对象
return typeof ret === 'object' ? ret : obj;
};
手写一个单例模式
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
let singleton = function (name) {
this.name = name;
};
singleton.prototype.getName = function () {
return this.name;
}
singleton.getInstance = (function () {
let instance = null;
return function (name) {
if (!instance) {
instance = new singleton(name);
}
return instance;
}
})();
let s1 = singleton.getInstance('s1');
let s2 = singleton.getInstance('s2');
console.log(s1.getName())
console.log(s2.getName())
timer promise async await 执行顺序
async>await>promise>timer
服务器主动向客户端发送请求的方式
- 轮询:客户端定时向服务器发送请求,服务器接到请求后返回信息后关闭连接。缺点:大部分无用,浪费资源
- 长连接:客户端在发送一次请求后挂起,直达服务端有更新后才主动推送信息。
- 推送:和长连接类似,但是资源消耗比长连接少