20190530(blw)
JavaScript数据类型转换: juejin.im/post/5cee56…
20190524(wyn)
- 箭头函数和普通函数的区别?
- note.youdao.com/noteshare?i…
- vue-router 有几种路由模式?他们的实现原理?
- note.youdao.com/noteshare?i…
- webpack 和 gulp 的区别?
-
gulp 任务执行器
侧重规范前端开发的流程,通过配置一系列的task,定义task处理的事务(例如:文件压缩合并,启动server),然后定义执行顺序,来让gulp执行task,从而构建其前端项目的流程。合并后仍然是你写的代码,只是局部变量名被替换,一些语法做了转换而已,整体内容并没有发生改变。
-
webpack 模块打包器
侧重模块打包,把开发中的所有资源(图片,js文件,css文件等)都开成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。打包后的代码已经不只是你写的代码,其中夹杂很多webpack自身的模块处理代码。
-
区别
Gulp是对整个过程进行控制,所以在其配置文件(gulpfile.js)中配置的每一个task对项目中该task配置路径下所有的资源都可以管理 Webpack则不是这样管理资源的,它是根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源, 对资源文件的处理是通过入口文件产生的依赖形成的,不会像Gulp那样,配置好路径后,该路径下所有规定的文件都会受影响
-
- 在webpack中如何做长缓存优化?
- 用户从访问网页开始,浏览器向服务器下载请求,服务器返回请求的时候,通过控制http协议的这些响应头,告诉浏览器某些资源以内的是强缓存,不用更新它。
- 如果代码有更新,版本号发生变化,则这段代码需要更新的代码。如果已经被浏览器缓存,用户希望获取缓存代码。只更新改变的代码。
- 优化方式一:在webpack中,可以在output给出输出的文件制定chunkhash,并且分离经常更新的代码和框架代码,通 过NameModulesPlugin或者HashedModulesPlugin使再次打包文件名不变。 chunkhash:它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。 HashedModulesPlugin:由于引入了一个新模块,使得打包过程中部分模块的模块ID发生了改变。而模块ID的改变,直接导致了包含这些模块的chunk内容改变,进而导致chunkHash的改变
20190517(swl)
- https通信双方获取加密密钥的过程?https为什么需要证书?
图解SSL/TLS协议 - 阮一峰
漫画:什么是 HTTPS 协议? - 实现一个chunk函数,
chunk([1, 2, 3, 4, 5], 2) -> [[1, 2], [3, 4], [5]]
30 seconds of code 这个链接收集了很多短小但实用的代码片段,你可以在30秒内理解它。里面很可能就有你每天在用的lodash方法// 先计算出生成的数组长度,然后利用Array.from的第二个参数去映射 const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size) ); 复制代码
- 下面是MDN给出的bind方法的Polyfill(篇幅原因略去了类型检测),思考标注的代码解决了什么问题,你觉得该实现还有哪些比较重要的缺陷?
如果没有上面的简单原型链继承,这里F的原型对象上的print方法就会丢失:Function.prototype.bind = function (oThis) { var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () { }, fBound = function () { return fToBind.apply(this instanceof fBound ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; // 以下两行代码解决了什么问题,试举例说明 if (this.prototype) fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; 复制代码
除此之外,这个bind实现没有处理函数的length属性,而原生的bind会进行处理。例如:const F = function() { this.name = 'haha' } F.prototype.print = function() { return this.name } const FBound = F.myBind(null) const f = new FBound() console.log(f) console.log(f.print()) // 不维护原型的话,这里会找不到print,进而报错 复制代码
这可能会导致依赖length的后续操作失败,例如柯里化等const add = (a, b) => a + b const addOne = add.bind(null, 1) addOne.length // 1 复制代码
这里又涉及到另一个问题,函数的length属性是不可写的,我们只能通过Object.defineProperty去设置:
MDN - Function.prototype.bind()Function.prototype.myBind = function (ctx, ...fixed) { if (typeof this !== 'function') { throw new TypeError('What is trying to be bound is not callable'); } const fToBind = this const fNOP = function () { } const fBound = function (...args) { return fToBind.call( this instanceof fBound ? this : ctx, ...fixed, ...args ) } if (this.prototype) fNOP.prototype = this.prototype fBound.prototype = new fNOP() // 设置新函数的length,如果本来就是0,那我们就也设置为0 Object.defineProperty(fBound, 'length', { value: Math.max(0, fToBind.length - fixed.length), writable: false, configurable: true }) return fBound } const addThreeNum = (a, b, c) => a + b + c console.log(addThreeNum.myBind(null, 1).length) // 2 复制代码
- 补全以下代码,实现一个简单的Observable
class Observable { constructor() { this.cbs = [] } subscribe (cb) { this.cbs.push(cb) } emit (x) { this.cbs.forEach(cb => cb(x)) } } const observable = new Observable() observable.subscribe(console.log) observable.subscribe(x => console.log(x * 2)) observable.emit(3) // output: 3 6 复制代码
20190510(sjj)
- []==![]
我们来分析一下:[]==![] 是true还是false?
- 首先,我们需要知道 ! 优先级是高于 == (更多运算符优先级可查看:运算符优先级)
- ![]引用类型转换成布尔值都是true,因此![]的是false
- 其中一方是 boolean,将 boolean 转为 number 再进行判断,false转换成 number,对应的值是 0.
- 有一方是number,那么将object也转换成Number,空数组转换成数字,对应的值是0.(空数组转换成数字,对应的值是0,如果数组中只有一个数字,那么转成number就是这个数字,其它情况,均为NaN)
- 0 == 0; 为true
- commonJS的es6模块的区别
- commonJS 浅拷贝,值可以被修改,优先从缓存中取值,加载时执行,一旦出现某个模块被“循环加载”,就只输出已执行的部分,还未执行的部分不输出
- es6 动态(原始值发生变化,import加载的值也会发生变化)只读引用,脚本执行时,去取值
- console.log(fn); // function fn() {console.log('哈哈')}
fn = 'hello'
function fn() {console.log('哈哈')};
console.log(fn); // 'hello'
所有的声明都会提升到当前作用域最顶上,
同一个变量只会声明一次,其它会被忽略
函数声明的优先级高于变量声明的优先级,并且函数声明和函数定义的部分一起被提升
20190426(shj)
- for..in 和 for...of 的区别
- for...in 循环读取键名,for...of 循环读取键值
- for...of 循环需要调用遍历器接口,for...in不需要。对于普通的对象,因为没有遍历器接口,所以不能直接用for...of 遍历对象
- 某些情况下,for。。。in循环会以任意顺序遍历键名
- (补充)for...of 与forEach 对比,for...of 可以使用break,continue,return跳出循环
- 什么是事件委托
- 通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
- 事件委托的实现是利用事件冒泡的机制
- 对于不支持冒泡机制的事件(如focus、blur等),想要使用事件委托,需要利用捕获机制。通过document.addEventListener 将事件模型设置为事件捕获
- 如何判断数组类型
- 使用 instanceof 操作符
- 使用Array.isArray()
- 使用Object的toString()方法
Object.prototype.toString.call([]); //"[object Array]"
- new 一个对象会发生什么
- 创建空对象
- 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象
- 使用新对象调用函数,函数中的this被指向新实例对象中
- 将初始化完毕的新对象地址保存到等号左边的变量中
- 若构造函数中返回this或返回值是基本类型(number、string、boolean、null、undefined、symbol)的值,则返回新对象;若返回值是引用类型的值,则实际返回值为这个引用类型。
- JSONP的原理
- 原理:Web页面上调用js文件时不受是否跨域的影响(不仅如此,我们还发现凡是拥有src这个属性的标签都拥有跨域的能力,比如script、img、iframe、link)
- 实现:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了
- CORS
跨域请求在发送前,会判断该请求是简单请求还是复杂请求。
- 如果是简单请求,浏览器会在请求头增加Origin字段后发送跨域请求。请求发送过去后,服务端一般会在响应头里添加上Access-Control-Allow-Origin 字段,浏览器通过校验该值是否是Origin的值或者是*,来判断是否跨域
- 如果是复杂请求,跨域请求会先发送一个预检请求(携带复杂请求部分信息)来询问服务器是否同意这次复杂请求。
- 预检请求使用OPTIONS方法,发送Origin、Access-Control-Request-Method、Access-Control-Request-Headers(可选)头部。
- 发送该请求后,服务器可以通过在响应头中携带以下头部
- Access-Control-Allow-Origin
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
- Access-Control-Max-Age (预检请求的有效期)
- 预检请求结束后,结果将按照响应中指定的时间缓存起来,下次再发送这样的复杂请求时,不会再发送预检请求
- vue父子组件中的生命周期与钩子函数的调用顺序
- 从外到内,再从内到外,mixins先于组件
- 父组件beforeCreated ->父组件created ->父组件beforeMounted ->子组件beforeCreated ->子组件created ->子组件beforeMounted ->子组件mounted -> 父组件mounted。
20190418(rtj)
- CSS有哪些继承属性?
- CSS中关于文字排版的属性如:font、word-break、letter-spacing、text-align、text-rendering、word-spacing、white-space 、text-indent、text-transform、text-shadow
- 其他类型的如:line-height、color、visibility、cursor
- 描述一下offsetWidth/offsetHeight、clientWidth/clientHeight、scrollWidth/scrollHeight的区别?
- offsetWidth/offsetHeight返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
- clientWidth/clientHeight返回值只包含content + padding,如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight返回值包含content + padding + 溢出内容的尺寸
- 什么情况下会打印出1?
let a = ?
if (a == 1 && a == 2 && a ==3 ) {
console.log(1)
}
复制代码
在类型不同时,用==比较会进行隐式类型转换,而在隐式类型转换时会调用toString()或者valueOf()方法,所以我们可以利用这个特性,定义a为一个对象类型,并且复写这两个方法其中之一就可以达到题目中的效果。
let a = [1, 2, 3] a.valueOf = a.shift // a.toString = a.shift 这个方法也可以 if (a == 1 && a == 2 && a == 3) { console.log(1) } 复制代码
- 讲一下什么是防抖和节流以及他们的区别和用途?
防抖(debounce)
- 概念:指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算。
- 用途:比如用户搜索时,当输入停止后再去触发搜索事件
节流(throttle)
- 概念:频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数
- 用途:比如处理浏览器滚动事件
20190412(blw)
- document 中的load事件和DOMContentLoaded事件之间的区别是什么?
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完成加载。
window的load事件仅在 DOM 和所有相关资源全部完成加载后才会触发。
- 如此执行正确吗?【function foo(){console.log(123) }()】
JavaScript 解析器将 function foo(){ }();解析成function foo(){ }和();。其中,前者是函数声明;后者(一对括号)是试图调用一个函数,却没有指定名称,因此它会抛出Uncaught SyntaxError: Unexpected token )的错误。 修改方法是:再添加一对括号,形式上有两种:(function foo(){ })()和(function foo(){ }())。以上函数不会暴露到全局作用域,如果不需要在函数内部引用自身,可以省略函数的名称。
- 负责的主要业务内容是什么? 开放性问题。要求有条理,逻辑清晰。
20190404(wyn)
- 介绍一下CSS的盒子模型?种类、组成、区别
每个元素被表示为一个矩形的盒子,由四部分组成:内容content/内边距padding/边框/border/外边距margin
盒模型有两种:标准盒模型(W3C盒模型)、IE盒模型
区别:标准盒模型内容大小就是content大小,而IE盒模型内容大小则是content+padding+border总的大小
- 什么是margin坍塌?怎么解决
相邻的两个标准流中的块元素,如果它们在垂直方向上设置了外边距,那么外边距会发生重叠,最终的外边距等于发生层叠的外边距中绝对值较大者
解决:触发BFC(Block Formatting Contexts 块级格式化上下文) 1、 body根元素 2、浮动元素:float:除none以为的值 3、绝对定位元素:position:absolute/fixed 4、display:inline-block/table-cells/flex 5、overflow:除了visible以外的值(hidden/auto/scroll)
- display: none;与visibility: hidden的作用和区别
作用:都是让元素不可见
区别: display:none会让元素完全从 render 树中消失,渲染的时候不占据任何空间,子元素不允许覆盖值。 visibility:hidden不会让元素从渲染树 dom 中消失,而且还是会占据空间,只是内容不可见而已,子元素允许覆盖值(设置visibility:visible;元素可见)。
- vue-router 中组件内的导航钩子beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave的用法
直接在路由组件内部直接进行定义的
接收参数(to,from,next) 1、 to:router即将进入的路由对象 2、 from:当前导航即将离开的路由 3、 next:,进行管道中的一个钩子,如果执行完了,调用next();否则为false,终止导航。 beforeRouteEnter:进入路由之前执行的函数 beforeRouteUpdate:当前路由改变 beforeRouteLeave:离开路由之前执行的函数
- position的absolute与fixed共同点与不同点
共同点: 1.改变行内元素的呈现方式,display被置为block;2.让元素脱离普通流,不占据空间;3.默认会覆盖到非定位元素上
不同点: absolute:生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位。 fixed:生成绝对定位的元素,相对于浏览器窗口进行定位。滚动网页,fixed元素与浏览器窗口之间的距离不变。
20190328(blw)
- cookie、sessionStorage和localStorage的区别。
- script、script async和script defer的区别
script - HTML 解析中断,脚本被提取并立即执行。执行结束后,HTML 解析继续。
script async - 脚本的提取、执行的过程与 HTML 解析过程并行,脚本执行完毕可能在 HTML 解析完毕之前。当脚本与页面上其他脚本独立时,可以使用async,比如用作页面统计分析。
script defer - 脚本仅提取过程与 HTML 解析过程并行,脚本的执行将在 HTML 解析完毕后进行。如果有多个含defer的脚本,脚本的执行顺序将按照在 document 中出现的位置,从上到下顺序执行。 注意:没有src属性的脚本,async和defer属性会被忽略。
- CSS和script的标签一般放在什么地方为什么?
把link标签放在head之间是规范要求的内容。此外,这种做法可以让页面逐步呈现,提高了用户体验。将样式表放在文档底部附近,会使许多浏览器(包括 Internet Explorer)不能逐步呈现页面。一些浏览器会阻止渲染,以避免在页面样式发生变化时,重新绘制页面中的元素。这种做法可以防止呈现给用户空白的页面或没有样式的内容。把script标签恰好放在body之前脚本在下载和执行期间会阻止 HTML 解析。把script标签放在底部,保证 HTML 首先完成解析,将页面尽早呈现给用户。 例外情况是当你的脚本里包含document.write()时。但是现在,document.write()不推荐使用。同时,将script标签放在底部,意味着浏览器不能开始下载脚本,直到整个文档(document)被解析。也许,对此比较好的做法是,script使用defer属性,放在head中。
- CSS 选择器的优先级是如何计算的
浏览器通过优先级规则,判断元素展示哪些样式。优先级通过 4 个维度指标确定,我们假定以a、b、c、d命名,分别代表以下含义: a表示是否使用内联样式(inline style)。如果使用,a为 1,否则为 0。 b表示 ID 选择器的数量。 c表示类选择器、属性选择器和伪类选择器数量之和。 d表示标签(类型)选择器和伪元素选择器之和。 优先级的结果并非通过以上四个值生成一个得分,而是每个值分开比较。a、b、c、d权重从左到右,依次减小。判断优先级时,从左到右,一一比较,直到比较出最大值,即可停止。所以,如果b的值不同,那么c和d不管多大,都不会对结果产生影响。比如0,1,0,0的优先级高于0,0,10,10。
- 如何为功能受限的浏览器提供页面? 使用什么样的技术和流程?
优雅的降级:为现代浏览器构建应用,同时确保它在旧版浏览器中正常运行。
渐进式增强:构建基于用户体验的应用,但在浏览器支持时添加新增功能。
利用 caniuse.com 检查特性支持。
使用 autoprefixer 自动生成 CSS 属性前缀。
使用 Modernizr进行特性检测。