面试题: --------- Day1 -------------
JavaScript有哪些数据类型?(八种)
Undefined、Null、Boolean、Number、String、Symbol、BigInt、Object; Symbol 指的是独一无二的值。每个通过 Symbol() 生成的值都是唯一的。 BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数。
Undefined、Null、Boolean、Number、String 、 Symbol 、 BigInt 属于值类型 Object属于引用数据类型 包含了Function 、 Array 、 Data
数据类型检测的方式有哪些?
方法1 typeof 只能判断 Number 、 String 、Function、 undefined 、Boolean、对于 null、array、object)返回的都是Object)
方法2 instanceof 可以对不同的实例对象进行判断,判断方法是根据对象的原型链依次向下查询 如果obj2的 原型属性(propotype) 存在于obj1的 原型链(proto) 上,(obj1 instanceof obj2)值为true。例如:对于 (Array Function Object)的判断
方法3 Object.prototype.toString.call() 对于参数为 null 或 undefined,直接返回结果。"[object Null]" "[object Undefined]" 参数不为 null 或 undefined,则将参数转为对象,再作判断。"[object Boolean]" ...
null和undefined区别?
首先 Undefined 和 Null 都是基本数据类型,undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
object.assign() 和 扩展运算符 是深拷贝还是浅拷贝,两者区别?
两者都是浅拷贝。 ● Object.assign()方法接收的第一个参数作为目标对象,后面的所有参数作为源对象。然后把所有的源对象合并到目标对象中。最终返回这个目标对象,当前面对象与后面对象,有同名属性时,后者会覆盖前者,它会修改了一个对象,因此会触发 ES6 setter。
● 扩展操作符(…)使用它时,数组或对象中的每一个值都会被拷贝到一个新的数组或对象中。它不复制继承的属性或类的属性,但是它会复制ES6的 symbols 属性。
let、const、var的区别 ( 前4必备 )?
(1)块级作用域: 块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了ES5中的两个问题: ● 内层变量可能覆盖外层变量 ● 用来计数的循环变量泄露为全局变量 (2)变量提升: var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否在会报错。 (3)给全局对象添加属性: 浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。 (4)重复声明: var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的遍历。const和let不允许重复声明变量。 (5)暂时性死区: 在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区。 (6)初始值设置: 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。 (7)指针指向: let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。
const对象的属性可以修改吗?
可以 ,const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。
箭头函数与普通函数的区别?
1 箭头函数比普通函数更加简洁 2 箭头函数没有自己的this 3 箭头函数继承来的this指向永远不会改变 4 call()、apply()、bind()等方法不能改变箭头函数中this的指向 5 箭头函数不能作为构造函数使用 6 箭头函数没有自己的arguments 7 箭头函数没有prototype
箭头函数的this指向哪⾥?
箭头函数并没有属于⾃⼰的this,它所谓的this是从父级作用域当中继承而来。
new操作符的实现原理?
(1)首先创建了一个新的空对象 (2)设置原型,将对象的原型设置为函数的 prototype 对象。 (3)让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性) (4)判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
数组的操作 (MDN)? juejin.cn/post/718554…
字符串的操作(MDN)? 未整理
--------- Day2 -------------
节流 (需要背代码)?
一段时间内只能触发一次,如果这段时间内触发多次事件,只有第一次生效会触发回调函数,一段时间过后才能再次触发(一定时间内只执行第一次) 应用场景 ① 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次; ② 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,提高性能;
防抖 (需要背代码)?
在事件被触发时,延迟n秒后再触发回调函数,如果n秒内又触发了事件,则会重新开始计算时间(一定时间内最后一次生效) 应用场景 用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约请求资源
什么是重排?什么是重绘?
重排 当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。 重排也叫回流,简单的说就是重新生成布局,重新排列元素。
下面情况会发生重排(挑几个就好): ● 页面初始渲染,这是开销最大的一次重排 ● 添加/删除可见的DOM元素 ● 改变元素位置 ● 改变元素尺寸,比如边距、填充、边框、宽度和高度等 ● 改变元素内容,比如文字数量,图片大小等 ● 改变元素字体大小 ● 改变浏览器窗口尺寸,比如resize事件发生时 ● 激活CSS伪类(例如::hover) ● 设置 style 属性的值,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow ● 查询某些属性或调用某些计算方法:offsetWidth、offsetHeight等,除此之外,当我们调用 getComputedStyle方法,或者IE里的 currentStyle 时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。
重绘 一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。
浏览器渲染内容流程?
● 在解析前,会执行预解析操作,会预先加载 CSS、JS 等文件 ● HTML 解析器解析 HTML,生成 DOM 树 ● CSS 解析器解析 CSS,产生 CSS 规则树 ● 解析 JS 脚本,该过程中需要等待 JS 执行完成才继续解析 HTML
防追问系列
URL回车后发生了什么?
URL解析:协议段+域名段(ip+端口)(HTTP协议默认端口是80,HTTPS协议默认端口是443)+路径段+查询参数段+哈希段,浏览器执行解析 DNS查询:将域名映射为IP+端口 ip是宇宙当中唯一一台主机 端口是这台主机的唯一进程(应用程序) TCP连接:宗旨确保稳定连接+可靠传输;三次握手确保稳定连接;四次挥手确保可靠传输;稳定连接:服客双方确保彼此的都能发能收;可靠传输:服客双方确保对方的数据已经传输完毕;三次握手是从客户端触发的N字形;四次挥手是从客户端出发的V字形+从服务端出发的V字形 发起HTTP请求:请求报文的构成:请求行+请求头+空行+请求体 HTTP响应返回:响应报文的构成:状态行+响应头+响应体 断开TCP连接:要经历四次挥手 浏览器渲染页面
简述TCP原理
宗旨:可靠传输+稳定连接 三次握手确保稳定连接,四次挥手确保可靠传输 稳定连接:服客双方确保彼此能发能收;可靠传输:服客双方确保对方的数据已经发送完毕 三次握手的图形:从客户端出发的N字形;四次挥手的图形:从客户端出发的V字形+从服务端出发的V字形 ps:一蹴而就原则:三次握手和四次挥手必须一次性完成,否则作废重来 UDP:没有握手+挥手,讲究直连直发直收直断,注重性能 TCP/UDP工作在OSI7层网络模型的传输层 OSI7层网络图形:物数网(IP)传(TCP/UDP)会表应(HTTP,FTP,SMTP)
GET和POST区别?
1.GET在浏览器回退不会再次请求,POST会再次提交请求 2.GET请求会被浏览器主动缓存,POST不会,要手动设置 3.GET请求参数会被完整保留在浏览器历史记录里,POST中的参数不会 4.GET请求在URL中传送的参数是有长度限制的,而POST没有限制 5.GET参数通过URL传递,POST放在Request body中 6.GET参数暴露在地址栏不安全,POST放在报文内部更安全 7.GET一般用于查询信息,POST一般用于提交某种信息进行某些修改操作 8.GET产生一个TCP数据包;POST产生两个TCP数据包
HTTP和HTTPS的区别?
1.HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
2.HTTP 是不安全的,而 HTTPS 是安全的
3.HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
4.在OSI 网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
5.HTTP 无法加密,而HTTPS 对传输的数据进行加密
6.HTTP无需证书,而HTTPS 需要CA机构WoSign的颁发的SSL证书
HTTP的状态码有哪些?
1字头:代表请求还在继续 2字头:代表请求成功(200:标准的请求成功) 3字头:代表重定向,301:永久重定向,302:临时重定向,304资源未被修改使用缓存 4字头:客户端发送错误:401:未授权,403:禁止访问,404(域名正确,但是路径错误) 5开头:服务器内部错误(500:服务端错误)
--------- Day3 -------------
你如何理解Promise?
Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。
Promise 状态?
● pending: 初始状态,不是成功或失败状态。 ● fulfilled: 意味着操作成功完成。 ● rejected: 意味着操作失败。
Promise 优缺点?
promise的then如果传入的两个函数那么第一个是 成功回调 ,第二个是失败回调 catch()就会失效
优点: 有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
缺点: Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消(不可以取消,但是可以throw一个err跳出)。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
谈谈Promise.all方法,Promise.race方法以及使用?
⚠️无论是all 还是 rece 当中有一个promise失败那么全部都会失败
● Promise.all 可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。 ● 顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
对async/await 的理解?
async 函数执行会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。 那如果 async 函数没有返回值时,它会返回 Promise.resolve(undefined)。 这和普通返回 Promise 对象的函数并无二致。
await 到底在等啥?
await 表达式的运算结果取决于它等的是什么。 ● 如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。 ● 如果它等到的是一个 Promise 对象,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。
async/await 如何捕获异常?
使用 try catch的方式
浏览器缓存机制?
浏览器缓存、DNS缓存、CDN缓存、页面本地缓存等等,有一个良好的缓存策略可以减低重复资源的请求,降低服务器的开销,提高用户页面的加载速度。
http缓存原理?
在浏览器加载资源的时候,首先会根据请求头的expires和cache-control判断是否命中强缓存策略,判断是否向远程服务器请求资源还是去本地获取缓存资源。
这当中又分为
强缓存
Expires
在浏览器第一次请求资源时,服务器端的响应头会附上Expires这个响应字段,当浏览器在下一次请求这个资源时会根据上次的expires字段是否使用缓存资源(当请求时间小于服务端返回的到期时间,直接使用缓存数据)
Cache-control cache-control字段优先级高于上面提到的Expires,值是相对时间。 在cache-control中有常见的几个响应属性值,它们分别是(下面的属性背 max-age 和 no-cache就可以了) max-age 3600 例如值为3600,表示(当前时间+3600秒)内不与服务器请求新的数据资源 no-cache 储存在本地缓存区,只是在于原始服务器进行新鲜度在验证之前,缓存不能将其提供给客户端使用
强缓存:简单来说就是给缓存资源设置一个过期时间,浏览器每次想要请求资源时都会判断一下这个资源是否过期,只在过期的时候才去向服务器请求资源。
协商缓存 那么,当浏览器在某次请求资源的时候发现本地缓存的资源过期了,这时候就会向服务器发送请求,并设置协商缓存 因此,协商缓存是需要浏览器向服务器发送请求的,服务器会根据 request header 里面的一些参数(If-None-Match,If-Modified-Since)来判断是否命中协商缓存:如果命中,则返回 304 状态码,并且在 response header中携带新的参数,通知浏览器从缓存中读取资源;如果没有命中,则返回 200 状态码,并且服务器会返回新的缓存资源给浏览器
请说出十个请求头?
Accept:客户端想要接收的响应体数据类型 Accept-Encoding:客户端想要接收的响应体压缩编码方式 Content-Type:请求体的数据类型 Content-Length:请求体的数据长度 Connection = keepAlive 保持长连接(直到页面所有资源加载完毕,才断开连接) Cookie:设置客户端的cookie信息 User-Agent:浏览器信息 Host:远程主机地址(服务端地址) Origin:客户端地址 If-None-Match:上一次响应的Etag携带的上一次数据的数据指纹(作为协缓的特征) If-Modified-Since:上一次响应的Last-Modified携带的上一次数据的最后尾更时间(作为协缓的特征)
请说出十个响应头?
Content-Type:响应体的数据类型 Content-Length:响应体的数据长度 Content-Encoding:响应体的压缩编码方式 connnection=keepAlive:保持长连接,直到页面所有资源加载完毕,才断开连接 Set-Cookie:服务端给客户端设置的cookie信息 Date:响应时间 Server:服务器信息 Access-Control-Allown-Origin:服务端允许哪个源跨域访问我 Cache-Control = maxAge(秒数) 最大缓存时间 Etag:电子指纹 Last-Modeifed:数据的最后尾更时间
哪些情况会导致内存泄漏?
用闭未释放的【全局变量+闭包+定时器+事件监听器】 当我们删除DOM元素时,忘记删除其对应的事件监听器 当我们离开页面时,没有释放掉各种的事件监听器 用完的全局变量没有释放,obj = null 用完的定时器没有clear掉 用完未释放的数据闭包,newFn = null
面试题:
深拷贝和浅拷贝的区别?
浅拷贝如果是基本类型,拷贝的就是基本类型的值。 深拷贝将对象中的所有key-value递归拷贝给另外一个对象,递归到每一个叶子结点(即value是基本数据类型或函数),深拷贝的副本修改相互不影响;
如何实现一个深拷贝?
常见的深拷贝方式有:
● 我的项目中使用的是 lodash 这个库里面的一个 _.cloneDeep() ● jQuery.extend() 通过jquery 这个可以实现 ● JSON.stringify() --这种方式存在弊端,会忽略undefined、symbol 和 函数 ● 拓展运算符就是浅拷贝,浅拷贝的第一层就是互不影响,第二层引用类型的才会受到影响。深拷贝是不管第几层都不受到影响,创建了一个新的内存。(很容易误认为 扩展运算也是深拷贝 分情况回答) ● 手写循环递归原理: 通过递归的形式遍历每个值然后根据每个值的类型来决定是否需要再次递归去处理
原型和原型链的理解?
原型链 实例对象在查找属性时,如果查找不到,就会沿着__proto__去与对象关联的原型上查找,如果还查找不到,就去找原型的原型,直至查到最顶层,这也就是原型链的概念。 原型 在js中,每个构造函数内部都有一个prototype属性,该属性的值是个对象,该对象包含了该构造函数所有实例共享的属性和方法。当我们通过构造函数创建对象的时候,在这个对象中有一个指针,这个指针指向构造函数的prototype的值,我们将这个指向prototype的指针称为原型。
apply call bind 区别?
apply、call、bind都可以为普通函数改变this指向 apply 和 call 就是传参方式不一样,apply 参数以一个数组的形式传入。但是两个都是会在调用的时候同时执行调用的函数。bind则会返回一个绑定了this的函数。 PS:bind的传参和call相同
说说你对HTML5语义化的理解?
让页面能够结构化的展示,比如段落用p标签,头部用header标签,主要内容用main标签,侧边栏用aside标签等等 比较容易阅读,方便开发人员快速了解页面的结构,更具有可读性,利与开发和维护
说一下你对事件循环(eventloop的理解)?
1.在代码的执行过程中会先执行同步代码,然后宏任务(script,setTimeout...)进入宏任务队列,微任务(Promise.then(),Promise)进入微任务队列 2.当宏任务执行完之后出队,检查微任务列表,继续执行微任务直到执行完毕 3.执行浏览器的UI渲染过程 4.检查是否有WebWorker任务,有则执行 5.继续下一轮的宏任务和微任务
跨域问题解决?
浏览器有一个重要的安全策略,称之为「同源策略」其中,源=协议+主机(IP)+端口源=协议+主机(IP)+端口,两个源相同,称之为同源,两个源不同,称之为跨源或跨域
防追问,什么是同源策略 同源策略是指,若页面的源和页面运行过程中加载的源不一致时,出于安全考虑,浏览器会对跨域的资源访问进行一些限制
跨域解决方法1-代理
开发环境使用代理解决跨域主要的方式是
1.通过nginx服务器 来配置代理转发。 目标域名然后设置一个 到达真实服务器地址就好
2 vue和react当中都有对应的proxy的配置,根据需求去配置就好
跨域解决方法2-CORS 如果浏览器要跨域访问服务器的资源,需要获得服务器的允许。就是说需要服务器开启配置允许我们访问。
讲讲CSRF XSS攻击?如何防范?二者的区别是什么?
XSS攻击:(Cross Site Scripting)跨域脚本攻击。 原理:(跨域问题解决) 不需要你做任何的登录认证,它会通过合法的操作(比如在 url 中输入、在评论框中输入),向你的页面注入脚本(可能是 js、html 代码块等)。 防范:
- 编码;对于用户输入进行编码
- 过滤;移除用户输入和事件相关的属性。(过滤 script、style、iframe等节点)
- 校正;使用 DOM Parse 转换,校正不配对的 DOM 标签
CSRF攻击:SRF(Cross-site request forgery)跨站请求伪造。 原理:
- 登录受信任网站 A,并在本地生成 Cookie (如果用户没有登录网站 A,那么网站 B 在诱导的时候,请求网站 A 的 api 接口时,会提示你登录)
- 在不登出 A 的情况下,访问危险网站 B(其实是利用了网站 A 的漏洞) 防范:
- token 验证;
- 隐藏令牌;把 token 隐藏在 http 请求的 head 中。
- referer 验证;验证页面来源。
二者的区别:
- CSRF:需要用户先登录网站 A,获取 cookie。 XSS:不需要登录。
- CSRF:是利用网站 A 本身的漏洞,去请求网站 A 的 api。 XSS:是向网站 A 注入 JS 代码,然后执行 JS 里的代码,篡改网站 A 的内容。
setInterval 时间为什么不准确?怎么解决 setInterval 是一个宏任务。其实是setInterval将会在 N 秒之后把一个函数推入任务队列,而不是让函数立即执行。假如定时器里面的代码需要进行大量的计算(耗费时间较长),或者是 DOM 操作。这样一来,花的时间就比较长,有可能前一次代码还没有执行完,后一次代码就被添加到队列了。也会导致定时器变得不准确,甚至出现同一时间执行两次的情况。 所以 因而我们一般用 setTimeout 模拟 setInterval 会更精确。
说一下你了解的js设计模式?
观察者模式 定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使它们能够自动更新自己,当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式 ● 发布 & 订阅 ● 一对多 优点 ● 支持简单的广播通信,自动通知所有已经订阅过的对象 ● 目标对象与观察者之间的抽象耦合关系能单独扩展以及重用 ● 增加了灵活性 ● 观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化。 缺点 过度使用会导致对象与对象之间的联系弱化,会导致程序难以跟踪维护和理解
单例模式 一个类只有一个实例,并提供一个访问它的全局访问点。 优点 ● 划分命名空间,减少全局变量 ● 增强模块性,把自己的代码组织在一个全局变量名下,放在单一位置,便于维护 ● 且只会实例化一次。简化了代码的调试和维护 缺点 ● 由于单例模式提供的是一种单点访问,所以它有可能导致模块间的强耦合 从而不利于单元测试。无法单独测试一个调用了来自单例的方法的类,而只能把它与那个单例作为一个单元一起测试。 场景例子 ● 定义命名空间和实现分支型方法 ● 登录框 ● vuex 和 redux中的store
代理模式 ● HTML元素事件代理 优点 ● 代理模式能将代理对象与被调用对象分离,降低了系统的耦合度。代理模式在客户端和目标对象之间起到一个中介作用,这样可以起到保护目标对象的作用 ● 代理对象可以扩展目标对象的功能;通过修改代理对象就可以了,符合开闭原则; 缺点 处理请求速度可能有差别,非直接访问存在开销
实现数组去重 set与解构赋值去重 ES6中新增了数据类型set,set的一个最大的特点就是数据不重复。Set函数可以接受一个数组(或类数组对象)作为参数来初始化,利用该特性也能做到给数组去重
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return } return [...new Set(arr)] }
Array.from与set去重 Array.from方法可以将Set结构转换为数组结果,而我们知道set结果是不重复的数据集,因此能够达到去重的目的
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return } return Array.from(new Set(arr)) }
使用 lodash 的 uniq() _.uniq([2, 1, 2]); // => [2, 1]
如何实现断点续传/大文件上传?
核心是利用 Blob.prototype.slice 方法,和数组的 slice 方法相似,文件的 slice 方法可以返回原文件的某个切片 预先定义好单个切片大小,将文件切分为一个个切片,然后借助 http 的可并发性,同时上传多个切片。这样从原本传一个大文件,变成了并发传多个小的文件切片,可以大大减少上传时间 另外由于是并发,传输到服务端的顺序可能会发生变化,因此我们还需要给每个切片记录顺序
防追问,具体代码是如何实现的 上面是我了解的一个大概的原理,我们的项目中使用的是oss,通过引入ossclient就可以对文件进行切上上传,需要配置切片的大小就可以了。
函数柯里化?
柯里化(Currying) 是把接收多个参数的原函数变换成接受一个单一参数(原来函数的第一个参数的函数)并返回一个新的函数,新的函数能够接受余下的参数,并返回和原函数相同的结果。
- 参数对复用
- 提高实用性
- 延迟执行 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。柯里化的函数可以延迟接收参数,就是比如一个函数需要接收的参数是两个,执行的时候必须接收两个参数,否则没法执行。但是柯里化后的函数,可以先接收一个参数
// 普通的add函数 function add(x, y) { return x + y }
// Currying后 function curryingAdd(x) { return function (y) { return x + y } }
add(1, 2) // 3 curryingAdd(1)(2) // 3
link与@import的区别?
区别: ● link是一种引入资源的标签,import是引入css的方式。所以,import引入的只能是css,而link可以引入所有的资源,包括图片,RSS等。 ● 加载顺序上也有一些差异。link引用的CSS会同时被加载。import引用的CSS会等到页面全部被下载完再加载。 ● 兼容性的差别。link无任何兼容问题,import兼容IE5以上。(当然,IE5估计也找不到了) ● 动态引入样式 link可以后期引入样式,而import是不可以后期引入的,只能初始化页面之前引入。 ● 复用率的问题 import可以复用之前的css文件,而link只能一次引用一个文件。当然,import复用文件时,在浏览器实际上是加载了多个文件,会有多个请求。而每一个link只是一个http请求。
判断数组的方法以及优缺点(5)
● Array.isArray(arr) :兼容性不好 ● arr instanceof Array ● arr.proto === Array.prototype ● arr.constructor === Array ● Object.prototype.toString.call(arr) === '[object Array]'
Javascript垃圾回收?
● 引用计数法:对象是否不再需要(限制:循环引入不能被回收) ● 标记清除法:从根开始,找所有从根开始引用的对象标记,然后找这些对象引用的对象标记,把不能达到的回收(这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。) ● 通过构造函数中设置(构造函数this指向 new 的对象) 避免内存泄漏: ● 尽少创建全局变量 ● 手动清除计时器 ● 少用闭包 ● 使用弱引用WeakMap和WeakSet
0.1 + 0.2 === 0.3 嘛?为什么?(16 0000000000000000)
计算机存储以二进制的方式,而0.1 在二进制中是无限循环的一些数字,所以会出现裁剪,精度丢失会出现,0.100000000000000002 === 0.1,0.200000000000000002 === 0.2 // true 这两加起来肯定不等于0.3 解决:parseFloat((0.1 + 0.2).toFixed(10)) === 0.3 // true
事件委托是什么?
事件委托就是利用事件冒泡,只定制一个事件处理程序,就可以管理某一类型的所有事件。 事件委托,又称为事件代理,是JS中很常用的绑定事件的方法。事件委托就是把原本需要绑定在子元素上面的事件委托给父元素,让父元素担当事件监听的职务,原理是DOM元素的事件冒泡。
git 常用命令?
- git clone
- git add .
- git commit -m '打印日志'
- git push -u origin 分支名
- git pull
- git branch 查看本地分支
- git branch -a 查看远程分支
- git branch -d xxx 删除分支
- git checkout xxx 切换分支
- git checkout -b xxx 新建分支并且切换到改分支
- git branch -m 旧分支名 新分支名 分支重命名
- git status 查看修改的文件
- git merge 合并分支
- git checkout -b xxx origin/xxx 拉去远程分支
- git log 查看提交记录
浏览器本地存储?
浏览器的本地存储主要分为Cookie、localStorage和sessionStorage。 共同点: 都是保存在浏览器端、且同源的 不同点:
- cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
- 存储大小限制也不同, ● cookie数据不能超过4K,sessionStorage和localStorage可以达到5M ● sessionStorage:仅在当前浏览器窗口关闭之前有效; ● localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据; ● cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭 3.作用域不同 ● sessionStorage:不能在不同的浏览器窗口中共享,即使是同一个页面; ● localstorage:在所有同源窗口中都是共享的; ● cookie: 也是在所有同源窗口中都是共享的;
GET和POST区别?
1.GET在浏览器回退不会再次请求,POST会再次提交请求 2.GET请求会被浏览器主动缓存,POST不会,要手动设置 3.GET请求参数会被完整保留在浏览器历史记录里,POST中的参数不会 4.GET请求在URL中传送的参数是有长度限制的,而POST没有限制 5.GET参数通过URL传递,POST放在Request body中 6.GET参数暴露在地址栏不安全,POST放在报文内部更安全 7.GET一般用于查询信息,POST一般用于提交某种信息进行某些修改操作 8.GET产生一个TCP数据包;POST产生两个TCP数据包
实现继承的方法?
第一就是通过原型链继承 第二是通过构造函数继承 这个是无法使用到父类的原型 第三就是组合式的 组合继承综合了原型链继承和盗用构造函数继承(构造函数继承),将两者的优点结合了起来
移动端适配方案有哪些 因为视口、逻辑像素、分辨率这些变量的不同,在每个设备展示都不一样,需要一种方案来统一。
常用适配方案
- rem & vw
- rem & 媒体查询
接下来你会被追问 rem 怎么做 flexible 方案 动态设置 rem 实现在不同尺寸的设备上界面展示效果一致
- 限制 rem 的最大值
- 通过媒体查询限制内容最大宽度 3.通过PostCSS的插件(postcss-px-to-rem),用于将像素单元生成rem单位。 webpack当中进行配置之后可以自动转换
vw 原理与实现 vw/vh是将屏幕直接分为100等份,1vw是1%的屏幕宽度,1vh是1%的屏幕高度 插件使用(postcss-px-to-viewport) webpack当中进行配置之后可以自动转换