一、YY
准备
1 如何制定前端项目的开发规范?
答:
这件事情本来应该由项目的 leader 主导的,但是因为我刚调入的项目组的 leader 是偏向后端的,对前端开发没有太多的经验,所以才交给我来做。所以我就参考目前主流的开发规范(vue 官方 以及 airbnb 爱彼迎)以及上一个 team 的规范,制定了一套当前项目组的开发规范。比起一开始的规范,主要解决了两个问题:一是尾逗号的问题,这样提交代码到 git 上就不会因为加了一个逗号,导致变更两行了。第二个是限制每行的最大长度,这样看起来比较清晰。第三个是:方法强制要求写注释,方便后面的人理解这个方法的意思。
2 为什么选择 Jest ,在项目中有何应用?
答:
Jest 是 Facebook 出品的一个测试框架,大厂出品会有保障些。相比其他框架,Jest 内置了常用的测试工具,如自带断言、测试覆盖率工具,可以开箱即用。
主要是为了提高代码的质量和可读性。在这个项目中,主要是测逻辑层的一些复杂/通用的方法,view 层的 UI 是没有测试的。没有测 UI 一方面是刚开始引入 Jest,逻辑层都覆盖的还不是很全面。另外就是我本身还没有想好怎么做会比较方便。覆盖率目前是 20% 左右。
覆盖率是集成的 Istanbul,有四个测量维度(行、方法、分支<if 块>、语句),yarn run jest --coverage
3 对 Vuex 的理解,为什么不用 Vuex 去管理状态?
4 说说你上家公司的架构是怎么样的,可以画出图吗?
5 你是怎么去做首屏加载优化的?
答:
当时那个项目,首页加载慢的原因,一个是白屏时间长,一个是数据loading时间长。
通过工具分析后,发现白屏时间长是因为在页面初始化的时候,加载了过多不必要的js资源,例如没有用到的图片、字体等,且首页背景图比较空,所以视觉上看起来加载时间也长,针对这些采取的措施是,延迟不必要资源的加载时间,然后使用骨架图提高用户体验。
第二个数据loading时间过长的问题,是因为首页的模块比较多,每个模块都拆分出一个接口去请求,同时发送的请求数超过了浏览器最大的并发数,所以造成有些模块的数据展示的比较慢。针对这个问题,我选择合并了一些请求来解决这个问题。图片资源过多也是一个问题,首先压缩了图片,对一些简单的图片使用base64编码。
6 算法
伪代码写排序和查找,能分析他们的复杂度;了解下为什么需要平衡二叉树,更深则涉及广度搜索和深度搜索
6.1 冒泡排序
- 每次比较相邻两个元素,如果第一个比第二个大,则交换位置;
- 对比每一对相邻的元素,从开始一对到最后一对,这样在最后的就是最大的元素;
- 针对所有元素重复以上步骤,除了最后一个;
- 重复1~3,直到排序完成
function bubbleSort(array) {
let len = array.length;
for(let outer = len; outer >= 2; outer --) {
for(let inner = 0; inner < outer - 1; inner ++) {
if(array[inner] > array[inner+1]) {
[array[inner], array[inner+1]] = [array[inner+1], array[inner]]
}
}
}
}
6.2 选择排序
原理:从未排序的队列中找出最小(最大)的元素,放在排序队列的第一位,然后再从未排序队列找出最小(最大)的元素,放来已排序队列的最后一位,以此类推,直到排序完成。
function selectSort(array) {
let len = array.length;
for(let outer=0; outer < len - 1; outer ++) {
for(let inner = outer; inner < len; inner ++) {
if(array[outer]>array[inner]) {
[array[outer], array[inner]] = [array[inner],array[outer]]
}
}
}
}
6.3 插入排序
原理:通过构建有序队列,对于未排序的队列,从后往前扫描,找到对应的位置并插入。在扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入位置。
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已排序的元素序列从后往前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位
- 重复步骤3,直到找到已排序的元素小于或等于新元素的位置
- 将该新元素插入到该位置后
- 重复步骤2~5
function insertSort(array){
let len = array.length;
// 外循环从1开始,默认0是有序队列
for(let outer=1; outer<len;outer++){
for(let inner=outer;inner>0;inner--){
if(array[inner]>array[inner-1]) {
[array[inner], array[inner-1]] =[array[inner-1], array[inner]]
} else {
break;
}
}
}
}
6.4 快速排序
原理:通过一趟排序,将待排序队列分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
function quickSort(array) {
if(arr.length <= 1) {
return arr; //递归出口
}
var left = [],
right = [],
current = arr.splice(0,1);
for(let i = 0; i < arr.length; i++) {
if(arr[i] < current) {
left.push(arr[i]) //放在左边
} else {
right.push(arr[i]) //放在右边
}
}
return quickSort(left).concat(current,quickSort(right));
}
7 设计模式
7.1 观察者模式
当对象之间存在一对多的依赖关系时,可使用观察者模式。例如,当一个对象有变更时,会自动通知依赖他的其他所有对象。观察者模式,属于行为模式。
// 可观察者
const Observable = (function(){
let message = {}
return {
on: function(type, fn) {
if(typeof message[type] === 'undefined') {
message[type] = [fn];
} else {
message[type].push(fn);
}
},
off: function(type, fn) {
if(message[type] instanceof Array) {
message = message.filter(i => i !== fn);
}
},
notify: function(type, args) {
if(!message[type]) {
return;
}
let events = {
type: type,
args: args || {},
};
for(let i =0; i< message[type].length: i++) {
message[type][i].call(this, events)
}
},
}
})()
//订阅消息
Observe.on('say', function (data) {
console.log(data.args.text);
})
Observe.on('success',function () {
console.log('success')
});
//发布消息
Observe.notify('say', { text : 'hello world' } )
Observe.notify('success');
7.2 状态模式
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。
允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类。
class ActiveBtnState {
handleClick() {
console.log('active btn')
}
}
class DisableBtnState {
handleClick() {
console.log('disabel btn')
}
}
class NormalBtnState {
handleClick() {
console.log('normal')
}
}
Class Button {
constructor() {
this.active = new ActiveBtnState();
this.disable = new DisableBtnState();
this.normal = new NormalBtnState();
this.currentState = 'normal';
}
changeState(state) {
this.currentState = state;
}
handleClick() {
switch(this.currentState) {
case: 'active':
this.active.handleClick();
break;
case: 'normal':
this.normal.handleClick();
break;
case: 'disable':
this.disable.handleClick();
break;
}
}
}
7.3 责任链模式
为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。
function order500(type) {
if(type === 1) {
console.log('500元');
} else {
return 'next';
}
}
function order200(type){
if(type === 2) {
console.log('200元');
} else {
return 'next';
}
}
function orderNormal(type) {
if(type > 0) {
console.log('10元');
} else {
console.log('下次继续鸭')
}
}
var chain = function(fn) {
this.fn = fn;
this.next = null;
}
chain.prototype.setNext = function (nextHandle) {
return this.next = nextHandle;
}
chain.prototype.passRequest = function () {
var ret = this.fn.apply(this,arguments);
if(ret === 'next') {
return this.next && this.next.passRequest.apply(this.next,arguments);
}
return ret;
}
//现在我们把3个函数分别包装成职责链节点:
var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);
// 然后指定节点在职责链中的顺序
chainOrder500.setNext(chainOrder200);
chainOrder200.setNext(chainOrderNormal);
//最后把请求传递给第一个节点:
chainOrder500.passRequest(1);
chainOrder500.passRequest(2);
chainOrder500.passRequest(0);
7.4 工厂模式
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行
8 在小程序中遇到过什么问题?
9 在上一家公司有什么收获?
答:
10 对前端工程化的理解
答:
工程化就是系统化、模块化、规范化开发的一个过程,要解决的是如何提高编码、测试、维护阶段的生产效率,是一种管理学或者说方法论。
前端工程化要解决什么:
- 制定各项规范(编码规范、开发流程规范、接口等文档规范)
- 使用版本控制,高效安全的管理源代码
- 使用合适的前端技术和框架,提高生产效率,降低维护难度
- 模块化的方式组织代码
- CommonJs: module.exports.sayHello = function() {}
- AMD:define
- UMD:允许同时是使用 AMD 和 CommonJs
- ES Modules: export const a = {}; import {a} from xxx
- 组件化的编程思想
- 将数据层分离管理
- 使用面向对象或函数编程的方式组织架构
- 模块化的方式组织代码
- 提高代码的可测性,引入单元测试,提高代码质量
- 通过使用各种自动化的工程工具,提升整个开发、部署效率
11 三次握手和四次挥手
- 三次握手 建立连接前,客户端和服务端需要通过握手来确认对方:
- 客户端发送 syn(同步序列编号) 请求,进入 syn_send 状态,等待确认
- 服务端接收并确认 syn 包后发送 syn+ack 包,进入 syn_recv 状态
- 客户端接收 syn+ack 包后,发送 ack 包,双方进入 established 状态
- 四次挥手
- 客户端 -- FIN --> 服务端, FIN—WAIT
- 服务端 -- ACK --> 客户端, CLOSE-WAIT
- 服务端 -- ACK, FIN --> 客户端, LAST-ACK
- 客户端 -- ACK --> 服务端,CLOSED
12 react 和 vue 之间的区别
还是说说相似之处:
- 使用 virtual dom
- 提供了响应式和组件化的视图组件
- 将注意力保持在核心库,其他功能如路由交给相关的库
不同之处:
- 运行时性能:React 在更新一个组件时,整个子组件树也会重新渲染,除非使用 shouldComponentUpdate 进行优化。而 vue 是在渲染的时候自动追踪的,所以系统能精准的知道哪个组件确实需要被渲染。
- HTML & CSS:React 使用 jsx,能使用完整的 JavaScript 语言来进行编程(使用临时变量),且开发工具对 jsx 的支持度高于 vue 模版。而 vue 的模版是开发者更容易接受。
- 响应式原理不同:vue 是依赖收集,递归监听 data 的所有属性直接修改。当数据改变时,自动找到引用组件重新渲染。 而 react 基于状态机,手动优化,数据不可变,需要 setState 驱动新的 State 替换老的 State。当数据改变时,以组件为根目录,默认全部重新渲染。
- diff 算法不同:vue diff 使用双向链表,边对比边更新 dom,而 react 主要使用 diff 队列保存需要更新哪些 DOM,得到 patch 树,再统一操作批量更新DOM。
13 px、em、rem、vh、vm 之间的区别
- px:代表物理屏幕上能显示出的最小的一个点
- em:是相对于父级的字体大小
- rem:是相对于 HTML 根元素的字体大小
- vh、vw:相对于视口的高度和宽度, 1vh 等于 1/100 的视口高度,1vw 等于 1/100 的视口宽度
14 JavaScript 跨域访问
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。
这就要说到同源策略了。同源策略是一种约定,同源是指“协议+域名+端口”三者相同。
同源会限制以下内容:
- Cookie、localStroage、IndexDB 等存储性内容的访问
- DOM 节点
- Ajax 请求
但是有三个标签是允许跨域加载资源的:
- <img src="xxx" />
- <link href='xxx' />
- <script src='xx' />
跨域的方式有以下几种:
- jsonp:利用 <script> 标签没有跨域限制的漏洞,网页可以从其他来源动态产生 json 数据,但需要对方服务器支持。缺点是仅支持get请求。
- cors:需要前后端支持,服务端设置 access-control-allow-origin 属性即可。
- nginx 反向代理:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
此处不再赘述,详细可以参考:juejin.cn/post/684490…
15 Http 状态码以及请求方法
- 1开头:表示临时响应并需要请求者继续执行操作的状态代码。
- 100:请求者需继续发出请求。服务器已接收一部分请求,等待剩余。
- 101:(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
- 2开头:(成功)表示成功处理了请求的状态代码。
- 200:成功
- 201:已创建
- 202:已接受,但未处理
- 203:非授权信息,返回的信息可能来自另一来源
- 204:无返回内容
- 205:重置内容
- 206:成功处理部分 get 请求
- 3开头:(重定向) 表示要完成请求,需要进一步操作。
- 300 (多种选择) 针对请求,服务器可执行多种操作。
- 301 (永久移动) 请求的网页已永久移动到新位置。
- 302 (临时移动)服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
- 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET,请求来检索响应时,服务器返回此代码。
- 304 (未修改) 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
- 305 (使用代理)请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。
- 307 (临时重定向)服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
- 4开头:(请求错误) 这些状态代码表示请求可能出错,妨碍了服务器的处理。
- 400 (错误请求) 服务器不理解请求的语法。
- 401 (未授权) 请求要求身份验证。对于需要登录的网页,服务器可能返回此响应。
- 403 (禁止) 服务器拒绝请求。
- 404 (未找到) 服务器找不到请求的网页。
- 5开头:(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。
- 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
- 501 (尚未实施) 服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码。
- 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
- 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。
- 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
- 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
16 盒模型
盒模型分为 IE盒模型 和 W3C标准盒模型。
区别在于:IE盒模型的属性 width,height 包含 border 和 padding,由 content + border + padding 组成,而 W3C标准盒模型只包含 content。
可以通过 box-sizing 属性控制,默认是 content-box 即标准盒模型,border-box 为 IE盒模型。
17 块级元素和内联元素的区别
答:
块级元素能够设置width和height,而且padding和bottom各个方向上都能够设定。而内联元素的width和height都无法定义,padding各个方向上能够设定(注意,非常多同学都觉得padding-top/bottom是不能够设定,这是一个大大的误解。不信你自己试一试。答案立即揭晓),然后margin-left/right能够设定,可是margin-top/bottom是不能够设定的了。
18 前端 CDN
答:
cdn是指内容分发网络。另外分两种,一种叫做静态cdn,一种是动态cdn。静态cdn是把你服务器的资源,拉到离请求端更近的地方存储,这样请求的时候就更快。动态cdn,因为资源是动态变化的,就不能拉到边缘节点存起来,这样没意义。他是优化请求端到服务端的传输链路,具体优化方式要比较熟悉网络的相关知识,减少传输时间
19 DOM 的 onload 和 DomContentLoaded 事件有什么区别
答:
- 当 onload 事件触发时,页面上所有的 DOM、样式表、脚本、图片、flash 都已经加载完成
- 当 DOMContentLoaded 事件触发时,仅当 DOM 加载完成,不包括图片、样式表、flash 这些
20 requestAnimationFrame 方法的作用?应用场景?
答:
作用:浏览器可以优化并行的动画动作,更合理的重新排列动作序列。并把能合并的动作放在一个渲染周期内完成,从而呈现更流畅的动画效果,节省 CPU。
应用场景:游戏、动画
21 网站的登陆是如何保持的,一个完整的登陆流程如何实现
答:
通过 cookies 来保持的,cookies 里面存储 token,每次请求到后端服务器的时候,都会带上 token,验证用户是否已经登陆,或者登陆状态又没有过期。
流程:输入用户名、密码 -》 点击登陆,发送登陆请求 -》 服务器端验证密码,生成token -》写入到 cookies ,返回成功
22 编写一个函数,用于从cookie里面获取数据
var getParam = function(name) {
var reg = new RegExp("(\?|#|&") + name + "=([^&#\?]*)(&|#|$|\?)");
var m = window.location.href.match(reg);
return decodeURI(!m ? '' : m[2]);
}
23 编写一个 Emitter 事件分发类,有 on、off、trigger、once 等方法
详见:www.cnblogs.com/penghuwan/p…
24 在 CSS3 中设置什么样式,可以改变默认盒子模型计算方式?
box-sizing: border-box;
25 支持正则的方法

26 浏览器事件循环(Event loop)
事件循环是一个执行模型,指: 执行一个宏任务,然后执行清空微任务列表,循环再执行宏任务,再清微任务列表,在不同的地方有不同的实现。
微任务 microtask(jobs):
- process.nextTick (Node独有)
- Promise
- Object.observe
- MutationObserver
宏任务 macrotask(task):
- setTimout
- script
- IO
- UI Rendering 详见:segmentfault.com/a/119000001…
27 从浏览器输入 url 到展示的过程
- DNS 解析
- TCP 三次握手
- 发送请求,分析 URL,设置请求头
- 服务器返回请求的文件(HTML)
- 浏览器渲染
- HTML parser -》 DOM tree
- 表计算法
- DOM 树构
- Css parser -》 Style tree
- 解析 css 代码,生成样式树
- attachment --> Render Tree
- 结合 dom tree 和 style tree 生成渲染树
- layout:布局
- GPU painting:像素绘制页面
- HTML parser -》 DOM tree
28 Typescript
29 单页面应用首屏显示比较慢,原因是什么?有什么解决方案?
首页白屏的原因:
单页面应用的 html 是靠 js 生成的,所有需要的资源都要下载到浏览器进行解析。因为首屏需要加载很大的 js 文件(app.js vendor.js),所以网速差的时候会产生一定程度的白屏。
解决方案:
- 优化 webpack 减少打包体积, code-split 按需加载
- 服务端优化,在服务端事先拼接好首页所需的 html
- 处理加载的时间片,合理安排加载顺序,尽量不要有大面积空隙
- 合理使用缓存
- 首页加 loading 或 骨架图
- 使用首屏SSR + 跳转SPA方式来优化
- 使用 ssr 的优势:
- 更好的 seo,搜素引擎爬虫抓取工具可以直接查看完全渲染的页面
- 更快的内容到达时间,无需等待所有的 JavaScript 都完成下载并执行,用户会更快的看到完整渲染的页面。
- 需要权衡的地方:
- 开发条件所限:浏览器特定的代码只能在某些生命周期钩子函数中使用。
- 涉及构建设置和部署的更多要求。需要在 node.js server 运行环境
- 更多的服务器端负载。
- 使用 ssr 的优势:
30 在页面上渲染一千行以上的数据后,滚动页面时,导致页面卡顿严重,原因是什么?有什么办法可以避免卡顿?
30.1
原因:
- 渲染的元素多,会导致大量的 dom,从而导致 dom 在初始化或者 reflow、repaint 的时候发生大量计算,导致卡帧、掉帧,主观上会显得页面卡顿
- 渲染过多的元素,同时触发滚动事件,会占用大量内存
解决方案:
使用虚拟列表,只渲染可视区域的列表元素,当可视区滚动时,根据滚动的 offset 大小以及所有列表元素的位置,计算在可视区应该渲染哪些元素。
30.2 顺便说下懒加载:
懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好的优化网页性能的方式。
为什么要用呢?
- 提升用户体验
- 减少无效资源的加载
- 防止并发加载的资源过多会阻塞 js 的加载
原理:
- 将页面上 img 的 src 属性设置为空字符串,真实的路径则设置在 data-original 属性中
- 监听页面滚顶的 scroll 事件,在 scroll 事件的回调中,判断懒加载的图片是否进入
问题
1 使用 css 描述一个 div 宽度比父元素宽度小 50px
.child {
width: calc(100% - 50px);
}
2 以下 JavaScript 代码输出的结果是什么?请做出解释
const m = [1, 2, 3]
const fn = (n, ...m) => n + m
console.log(fn(1))
3 使用 typescript 声明一个函数当入参为 number 类型时返回 string 类型,入参为 string 类型时返回 number 类型。
见问题8
4 如何提高 webpack 构建速度?
5 使用 React Hook(或 Vue) 描述一个 fetch 异步请求组件
6 ES6 两种导出方式的区别
- 命名导出(每个模块包含任意数量)
- 默认导出(每个模块包含一个) 命名导出:
// 导出早前定义的函数
export { myFunction,myVariable };
// 导出单个特性(可以导出var,let,const,function,class)
export let myVariable = Math.sqrt(2);
export function myFunction() { ... };
默认导出:
// 默认导出函数
export default function(){}
// 默认导出类
export default class{}
7 下面哪些会触发 Http 请求
// A
<textarea>
<img scr='a.png' style="display:none;" alt="my home">
</textarea>
// B
<textarea style="display:none;">
<img scr='a.ong' style="visibility:hidden" alt="my home">
</textarea>
// C
<div style="display:none;background-image:url('a.png);"></div>
// D
<textarea>
<span style="display:none;background-image:url('a.png);" alt="my home"></span>
</textarea>
正确答案是 C。 解析:在 textarea 中会被解析为纯文本,而不是 dom 元素。
- 解析HTML【遇到
标签加载图片】 —> 构建DOM树
- 加载样式 —> 解析样式【遇到背景图片链接不加载】 —> 构建样式规则树
- 加载javascript —> 执行javascript代码
- 把DOM树和样式规则树匹配构建渲染树【遍历DOM树时加载对应样式规则上的背景图片】
- 计算元素位置进行布局
- 绘制【开始渲染图片】
原理参考:segmentfault.com/a/119000001…
8 说说 typescript 的函数重载
这个概念是强类型语言中才有的,在 JavaScript 中依据不同的类型/参数个数执行一些不同的函数体,很常见。
关于函数重载,最精确的定义放在最前面,最后函数实现时,需要使用 | 操作符或者 ? 操作符,把所有可能的输入类型全部包含进去。
// 这里是声明
function change(val: number):string
function change(val: string): number
// 这里是实现
function change(val: number | string) {
if(typeof val === 'string') {
return Number(val)
} else if(typeof val === 'number') {
return String(val)
}
}
9 Vuex 的作用是什么?
vuex 是一个转为 Vue.js 开发的状态管理模式。采用集中式存储管理应用的所有组件的状态,并以一定的规则保证状态以一种可预测的方式发生变化。
10 首屏加载做了哪些优化?会想起上次做的优化,现在你觉得还可以做哪些改进?
11 block、inline 和 inline-block
- block
- 独占一行,默认自动填满父元素宽度
- 可以设置 width、height 属性
- 可以设置 margin、padding 属性
- 常见块级元素:div, form, table, p, pre, h1~h6, dl, ol, ul 等
- inline
- 不会独占一行,相邻元素会排列在同一行里,直到排列不下才会换行,宽度随元素内容变化而变化
- 无法设置 width、height
- 可以设置 padding、左右margin,但不可以上下margin
- 常见行内元素:span、a、strong、em、label、input、select、textarea、img、br 等
- inline-block
- 应用此特性的元素呈现为内联对象,周围元素保持在同一行,但可以设置宽度和高度地块元素的属性 可在一下情况进行切换:
- 让一个 inline 元素从新的一行开始
- 让块元素和其他元素保持在同一行
- 可以设置元素的宽高
- 默认与文字同宽
兼容性:IE 不支持该属性,但使用display:inline-block在IE下会触发 layout,从而使内联元素拥有了该属性的表象。
inline-block 为什么会存在间隙:inline-block 元素间有空格或是换行 解决方案:
- 设置
font-size:0 - 设置
letter-spacing为负数
12 npm 发包怎么控制发上去之后,不被别人下载?
- npm init -y
- npm version <update_type> // patch补丁版本、minor次版本、major主版本,更新包
- npm publish // 发布包
步骤一:在 package.json 中设置 private: true,npm 将拒绝发布它,这是为了防止一个私有模块被无意间发出去。
步骤二:配置 publishConfig,这个配置是会在模块发布时用到的一些值的集合。如果你不想模块被默认被标记为最新的,或者默认发布到公共仓库,可以在这里配置tag或仓库地址。
13 如何配置项目 eslint 出错的情况下,代码无法 push 到远端?
使用 git hook。
任何时候当前版本库中出现如 commit、push 等特殊事件时,都会触发执行一个或多个任意的 shell 脚本,称之为 git 钩子。它存放在.git/hooks目录下。
从顺序上可分为:
- 前置钩子,在动作完成前调用
- 后置钩子,在动作完成后执行
14 typescript 中的 interface 和 type 有什么区别,使用场景?
- An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.
- An interface can have multiple merged declarations, but a type alias for an object type literal cannot.
interface是接口,type是类型,本身就是两个概念。只是碰巧表现上比较相似。 希望定义一个变量类型,就用type,如果希望是能够继承并约束的,就用interface。 如果你不知道该用哪个,说明你只是想定义一个类型而非接口,所以应该用type。
相同点:
- 都可以描述一个对象或函数
- interface 可以 extends、implement,type 可以通过交叉类型实现同样的行为
不同点:
- type 可以声明基本类型别名、联合类型、元组 等类型,interface 不可以
- type 语句中可以使用 typeof 获取实例的类型进行赋值,interface 不可以
- interface 能声明合并
15 vue 怎么实现数据监听,array 类型呢?
vue 的双向绑定,是通过数据劫持结合发布者-订阅者模式的方式来实现的。
对 array 类型,vue 内部实现了一组观察数组的变异方法,例如 push、pop、shift 等。更改我们需要监听的Array数组属性值(属性值为函数),在监听函数里执行数组的原生方法,并通知所有注册的观察者进行响应式处理。
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
;[
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
].forEach(item=>{
Object.defineProperty(arrayMethods,item,{
value:function mutator(){
//缓存原生方法,保证不污染数组的原生方法,之后调用
const original = arrayProto[item]
let args = Array.from(arguments)
original.apply(this,args)
},
})
})
// 调用
let obarr = []
obarr.__proto__ = arrayMethods
// 如果浏览器不支持 __protp__,直接使用 defineProperty
Object.defineProperty(obarr, 'push', {
value: arrayMethods.push
})
16 描述一下状态机模式。是否有看过 git 上比较成熟的使用状态机实现的项目?
17 怎么拦截网页上的广告弹出?(思路)
1、对 URL 请求进行拦截。梳理出常见的广告url,进行过滤
18 动态切换主题的原理是什么?
应该是替换类的值。。
19 git相关知识
1 reabse
功能:可以把本地未push的分叉提交历史整理成直线
目的:使得查看历史提交的变化时更容易,因为分叉的提交需要三方对比