├── 简历 ├── 简历.pdf └── 简历.md ├── 大学期间记录 ├── 前言.md ├── ES6面试专题.md ├── 前端性能优化专题.md ├── 腾讯二面机试.js ├── index.html ├── 支付宝前端面试.md └── 前端小密圈-一年经验初探阿里巴巴前端社招.md ├── README.md └── leetcode学习 ├── test.js └── 排序算法.md /简历/简历.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youkongling/interview-preparation/HEAD/简历/简历.pdf -------------------------------------------------------------------------------- /大学期间记录/前言.md: -------------------------------------------------------------------------------- 1 | # 突然写这个项目的原因 2 | 今年大三,去年12月份的时候面试了一次阿里,被大佬狠狠的暴捶了一顿,之前在学习也好,社团也好,觉得自己学的还是不错的,毕竟成绩一直是专业前3%,大学期间也时常去外面接一些外包来做,感觉自己在专业知识和动手实践上的能力都还不错,但是阿里大佬的面试告诉我,学的还不够,一面完了就没有消息了,应该是挂了 3 | 寒假没敢在家里待着,怕在家待一个月到春招的时候就废了,在北京找到分寒假的实习(第一次来北方,很不适应),但来这后还是学到了不少,之前没用过react,公司这边使用的是react+redux,前端用的UI组件是ant-design,三天上手,到现在为止,也在线上推了一部分小功能,谢谢老大耐心教我 4 | 昨天晚上又在cnode上逛招聘的帖子,看到支付宝前端招聘,就抱着试试的心态给人家发了一份简历,没想到人家直接给我春招内推了,心里窃喜的同时,也不免担心又一次被吊打,所以打算把基础知识点老老实实的过一遍,同时这次没过的话,秋招也还用得上(啰嗦一堆家常) 5 | 6 | # 主要内容 7 | 这边主要会围绕三个部分来复习,同时也是整理下自己学过的一些知识,基础知识(`html5,css3,javascript`),流行技术(`react,vue,es6,webpack`),项目总结(做项目踩的一些坑) 8 | 大概就是这些东西了,写的时候会参考别人的面试经验和博文,希望自己这次能沉淀下来一些东西 9 | -------------------------------------------------------------------------------- /大学期间记录/ES6面试专题.md: -------------------------------------------------------------------------------- 1 | ## ES6面试专题 2 | 关于es6的新特性的问题,已经在面试中被问到好多次了,每次回答都是乱七八糟的,想想,是时候总结下了,感谢各位前辈提供的参考 3 | 4 | ### Promise必知必会 5 | 1. Promise构造函数是同步执行的,promise.then中的函数是异步执行的 6 | 2. Promise有3种状态,pending,fulfilled,rejected,状态改变只能从pending->fulfilled或者是pending->rejected,状态一旦改变则不能再变 7 | 3. 构造函数中的resolve或者reject只有一次执行有效,多次调用没有任何作用 8 | 4. Promise可以链式调用,每次调用.then或者.catch都会返回一个新的Promise,从而实现链式调用 9 | 5. Promise的.then或者.catch可以被调用多次,但这里Promise构造函数只能执行一次,或者说Promise内部状态一经改变,并且有了一个值,那么后续调用.then或者.catch都会直接拿到这个值 10 | 6. .then或者.catch中的一个error对象并不会抛出错误,所以不会被后续的.catch捕获,返回任何非Promise的值都会被包裹成Promise对象 11 | 7. .then或者.catch返回的对象不能是Promise本身,不然会陷入死循环 12 | 8. .then或者.catch的参数期望是函数,传入非函数会发生值穿透 13 | 9. .then可以接受两个参数,第一个是处理成功的函数,第二个是处理错误的函数,.catch是.then第二个参数的简便写法,但是他们用法上需要注意一点的是:.then的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的.catch可以捕获之前的错误 14 | 10. process.nextTick和promise.then都属于microtask,而setImmediate属于macrotask,在事件循环的check阶段执行,事件循环的每个阶段(macrotask)之间都会执行microtask,事件循环的开始会执行一次microtask 15 | 16 | 参考链接 [Promise必知必会](https://juejin.im/post/5a04066351882517c416715d) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 突然写这个项目的原因 2 | 今年大三,去年12月份的时候面试了一次阿里,被大佬狠狠的暴捶了一顿,之前在学习也好,社团也好,觉得自己学的还是不错的,毕竟成绩一直是专业前3%,大学期间也时常去外面接一些外包来做,感觉自己在专业知识和动手实践上的能力都还不错,但是阿里大佬的面试告诉我,学的还不够,一面完了就没有消息了,应该是挂了 3 | 4 | 寒假没敢在家里待着,怕在家待一个月到春招的时候就废了,在北京找到分寒假的实习(第一次来北方,很不适应),但来这后还是学到了不少,之前没用过react,公司这边使用的是react+redux,前端用的UI组件是ant-design,三天上手,到现在为止,也在线上推了一部分小功能,谢谢老大耐心教我 5 | 6 | 昨天晚上又在cnode上逛招聘的帖子,看到支付宝前端招聘,就抱着试试的心态给人家发了一份简历,没想到人家直接给我春招内推了,心里窃喜的同时,也不免担心又一次被吊打,所以打算把基础知识点老老实实的过一遍,同时这次没过的话,秋招也还用得上(啰嗦一堆家常) 7 | 8 | # 主要内容 9 | 这边主要会围绕三个部分来复习,同时也是整理下自己学过的一些知识,基础知识(`html5,css3,javascript`),流行技术(`react,vue,es6,webpack`),项目总结(做项目踩的一些坑) 10 | 11 | 大概就是这些东西了,写的时候会参考别人的面试经验和博文,希望自己这次能沉淀下来一些东西 12 | 13 | ## 秋招开始 14 | 辗转几度,春招刚过,秋招也快来了,三四月份面试过阿里,腾讯,美团,头条,滴滴,以及各式各样的B轮,C轮的公司,其中,有高兴,有失落,最后感谢东哥把我捞到滴滴来,在这边也快待了两个月了,收获还不错,谢谢东哥的耐心教导,这两天逛了下v社的帖子,秋招的迹象开始了,又要开始准备面试了,这个笔记本我又打算开始记录一些自己的功课,希望能有所收获 15 | 16 | ## 2020春季面试准备 17 | 在滴滴待了一年半了,不知道明年的绩效怎么样,先做准备总是没错的,好久没学新东西了,算法一直是我特别头大的地方,看大家都是从刷LeetCode开始练算法的,在网上搜了下,这位大佬(@[lucifer210](https://github.com/azl397985856/leetcode))整了一个25.1k star的leetcode刷题心得库,本着像大佬学习的态度,在这里记录下自己的学习路程,话不多说,开整~ 18 | -------------------------------------------------------------------------------- /大学期间记录/前端性能优化专题.md: -------------------------------------------------------------------------------- 1 | ## 前端性能优化专题 2 | 前端性能优化一直是一个很宽泛的概念,但是每次面试的时候都会被问到这方面的知识点,最近在面试过程中发现自己对这一块的理解不成体系,遂而打算总结一下,梳理自身所学,闲话不多说,咱们往下看。 3 | 4 | ### 一. 静态资源优化 5 | 静态资源优化主要是减少静态资源的加载时间,主要包括html,css,js和图片文件 6 | 1. 合并css,js文件,以减少http请求次数,节省网络请求时间 7 | 2. 使用uglify对文件进行混淆压缩,后端开启gzip压缩,以减少请求文件大小 8 | 3. 使用静态资源cdn分发,使得客户端通过最佳的网络链路获取资源 9 | 10 | #### gzip压缩工作流程 11 | gzip压缩通常可以减少70%网页内容的大小,包括脚本,样式表,图片等任何一个文本的响应 12 | - 客户端在请求Accept-Encoding中声明支持gzip 13 | - 服务器将请求文档压缩,并在Content-Encoding中声明该回复为gzip格式 14 | - 客户端收到后按照gzip解压缩 15 | 16 | #### 压缩 17 | 1. 前端使用uglify混淆压缩 18 | 2. 后端开启gzip 19 | 3. 对图片进行压缩,使用压缩比例更高的格式webP 20 | 21 | #### 缓存 22 | 1. 强缓存(200),不用请求服务器直接使用本地缓存 23 | 2. 协商缓存(304),使用时先请求服务器,若被告知缓存没过期,则使用本地缓存,不用下载资源 24 | 3. 使用localstorage对数据进行存储 25 | 26 | #### 针对首屏优化 27 | 对非关键资源进行延迟加载,异步加载,减少首屏加载资源大小 28 | 29 | ### 二. 关键资源连接数 30 | 31 | #### 合并请求 32 | 1. 使用http2.0的多路复用合并请求 33 | 2. 配置combo,在无法使用http2.0的时候作为一种资源合并的手段 34 | 35 | #### 减少图片请求数 36 | 1. 使用spilt图 37 | 2. 使用svg-symbol 38 | 39 | 参考链接 [前端性能优化指南](https://segmentfault.com/a/1190000003646305#articleHeader11) 40 | 参考链接 [前端性能优化相关](https://github.com/wy-ei/notebook/issues/34#issuecomment-266937246) 41 | 参考链接 [2017前端性能优化清单](http://web.jobbole.com/91025/) 42 | 参考链接 [2018前端性能优化清单](https://juejin.im/post/5a966bd16fb9a0635172a50a#heading-2) 43 | 44 | 明天要面试,今天先写一小部分,上面四个大佬的总结都写得很详细,明天面试完再去参悟下 45 | -------------------------------------------------------------------------------- /大学期间记录/腾讯二面机试.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 腾讯二面机试 3 | * 周三晚上突然接收到腾讯的电话,比较懵,白天面试了两场,很累,状态不太好,面了大概半个钟头,表现的一般,以为挂了, 4 | * 没想到周四上午打电话过来约下午机试,一点都没有准备,面完以后就血崩了,这里做点记录,免得又踩到坑里 5 | */ 6 | 7 | /** 8 | * 第一题,纯js封装一个拖拽的组件,要求代码整洁,高可用,考虑边界值 9 | */ 10 | 11 | function drag(elementId) { 12 | var element = document.getElementById(elementId); 13 | var position = { 14 | offsetX: 0, //偏移值X 15 | offsetY: 0, //偏移值Y 16 | state: 0 17 | } 18 | 19 | function getEvent(event) { 20 | return event || window.event; 21 | } 22 | 23 | element.addEventListener('mousedown', function(event) { 24 | var e = getEvent(event); 25 | position.offsetX = e.offsetX; 26 | position.offsetY = e.offsetY; 27 | position.state = 1; 28 | }, false) 29 | 30 | document.addEventListener('mousemove', function(event) { 31 | var e = getEvent(event); 32 | if (position.state) { 33 | position.endX = e.clientX; 34 | position.endY = e.clientY; 35 | 36 | // 设置绝对位置在文档中,鼠标当前位置-开始拖拽时的偏移位置 37 | element.style.position = 'absolute'; 38 | element.style.top = position.endY - position.offsetY + 'px'; 39 | element.style.left = position.endX - position.offsetX + 'px'; 40 | } 41 | }, false) 42 | 43 | element.addEventListener('mouseup', function(event) { 44 | position.state = 0; 45 | }, false) 46 | } -------------------------------------------------------------------------------- /大学期间记录/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 14 | 15 | 16 |
17 | 60 | 61 | -------------------------------------------------------------------------------- /简历/简历.md: -------------------------------------------------------------------------------- 1 | ## 刘红波 (node前端工程师) 2 | 电话:15779420412 3 | 邮箱:a15779420412@gmail.com 4 | github:[https://github.com/youkongling](https://github.com/youkongling) 5 | 6 | ## 教育背景 (2015-2019) 7 | ``` 8 | 华东交通大学 软件工程(本科) 在校成绩:2% 9 | 荣誉奖励:国家励志奖学金 10 | 2016.06-至今 技术研究员 前端负责人 华东交通大学和平研究院 11 | 2016.06-至今 技术中心网建经理 华东交通大学日新网 12 | ``` 13 | 14 | ## 工作技能 15 | - JavaScript 16 | 有一定的框架/源码阅读经历,阅读过node模块weixin-api(当初入门微信开发主要参考) 17 | 关注ES6,TypeScript等相关技术 18 | 熟悉Jquery的常用插件,underscore,swiper,monsary,lazyload,iScroll,fastClick等 19 | 使用mocha,should模块进行单元测试 20 | 使用node进行过简单的爬虫开发,使用superagent和cheerio编码爬虫和解析,使用async模块进行并发控制 21 | 了解angular1,vue2,使用react进行正式项目开发 22 | 对DOM原型有一定理解 23 | 24 | - CSS3 25 | 了解常规的流式布局和响应式布局,奉行内容至上的理念 26 | 有移动端页面开发经验,对多端适配和浏览器兼容处理有一定理解 27 | 对flex的弹性布局有一定理解,使用animate.css进行css3动画制作 28 | 对页面渲染有一定理解,了解css的重排和重绘 29 | 30 | - HTML5 31 | 喜欢使用语义化标签,对使用HTML5的data属性进行组件开发有一定理解 32 | 对jade,ejs等模板引擎有使用经验,对iframe的相应适配有一定了解 33 | 34 | - WebGL 35 | 追求前段炫酷效果的实现,尝试使用create.js,three.js进行前断2D和3D动画的制作,后续打算进一步学习WebGL底层的相关技术 36 | 使用HighChart,EChart等库进行UI可视化的开发操作 37 | 38 | ## 项目构建/其他 39 | 使用webpack作为构建工具,了解前端项目的自动化编译,合并,压缩,持续集成等一系列操作 40 | 使用npm和bower进行模块管理,使用git进行版本控制 41 | 使用Ubuntu作为日常工作环境(北京实习期间使用的是mac) 42 | 对Mongodb和MySQL会简单的CRUD操作 43 | 44 | ## 项目经历 45 | - 北京况客科技fof系统前端实习 46 | 技术栈:react + redux + es6 + antd + webpack + eslint 47 | 2017年寒假在北京况客科技实习,参与fof系统的前端开发工作,使用react+redux全家桶作为前端开发技术栈,使用webpack作为项目的构建工具,使用antd和react-bootstrap等前端框架组件,采用es6编写代码,使用babel编译,使用eslint作为代码检查,实习期间,实现了一个全局搜索的组件,使用highChart绘制可视化报表图等。 48 | 49 | - 上饶农商考试系统/上饶农商四扫系统 50 | 技术栈:node + express + amazeui + swiper + request + async + ejs 51 | 考试系统:一个基于微信端的web考试系统,分为考试模块和知识库两大模块,提供给业务员进行线上考试,系统随机组卷,定时交卷,自动阅卷。主要使用amazeui进行前端页面制作和ejs进行模板渲染,使用request模块和php后端进行交互,使用async模块并发多个接口数据,实现了一个基于swiper的单页答题组件,在进度条,答题卡,毛点出进行了dom通信。开发过程中兼负责交互设计,node服务部署,nginx反向代理配置等工作。 52 | 四扫系统:一个基于微信端的银行四扫业务系统,分为数据录入和数据营销两大模块,提供给业务员进行扫街业务。主要使用amazeui进行前端页面制作和ejs进行模板渲染,使用request模块和Java后端进行交互,使用async模块并发多个接口数据,更加深刻的理解了express中的router和request模块,加深了对http传输的理解。 53 | 54 | - 学校的成绩,饭卡,课表等查询功能 55 | 技术栈:node + express + bootstrap + animate + request + ejs 56 | 抓取学校教务处的数据重新整理格式提供给微信端,移动端使用。主要负责微信第三方的接入,前端页面的制作和模板渲染,使用node-weixin项目提供的node-weixin-api,使用request模块和python爬虫进行交互,开发过程中负责切图,node服务端部署。 57 | 58 | - 日新网产品前端代码维护和新服务上线 59 | 技术栈:jQuery + bootstrap + ajax + underscore + lazyload + masonry 60 | 大二至今,负责解决前端在各个平台下浏览器的兼容问题,已经进行前端页面的性能优化工作,如使用精灵图以减少图片的HTTP请求数和ajax实现局部更新,前端页面响应式改版更新,hr招新页面微信端上线,日新图说首屏图片的瀑布流和懒加载效果实现等。 61 | 62 | - 和平研究院项目参与 63 | 大一暑假,参与和平研究院户外运动旅游平台开发,负责后台页面编写,使用Ace Admin框架模板,使用iframe更新main区域,大二暑假,参与和平研究院教学工作管理系统开发,负责后台页面开发,使用jeesite和H+制作后台CMS,了解Java Web技术开发模式。 64 | 65 | ## 自我评价 66 | 本人对前端技术具有浓厚兴趣,喜欢逛掘金,Cnode等技术社区,同时具备良好的审美能力,在工作中,学习适应能力强,愿意不断学习新知识丰富自己,抗压能力强,有信心在不同的工作强度下进行开发工作,并且性格随和,具有良好的团队合作精神。 67 | -------------------------------------------------------------------------------- /leetcode学习/test.js: -------------------------------------------------------------------------------- 1 | // function mergeSort(arr) { 2 | // if (arr.length < 2) return arr 3 | 4 | // let middle = Math.floor(arr.length / 2) 5 | // let left = arr.slice(0, middle) 6 | // let right = arr.slice(middle) 7 | 8 | // return merge(mergeSort(left), mergeSort(right)) 9 | // } 10 | 11 | // function merge(left, right) { 12 | // let result = [] 13 | 14 | // while (left.length > 0 && right.length > 0) { 15 | // if (left[0] < right[0]) { 16 | // result.push(left.shift()) 17 | // } else { 18 | // result.push(right.shift()) 19 | // } 20 | // } 21 | 22 | // return result.concat(left).concat(right) 23 | // } 24 | 25 | // const num = [6, 10, 1, 4, 19, 8, 3, 7, 16] 26 | // console.log("num ", num) 27 | 28 | // const result = mergeSort(num) 29 | // console.log("result ", result) 30 | 31 | 32 | // function mergeSort(arr){ 33 | // if (arr.length < 2) return arr 34 | 35 | // let step = 1 36 | // let left, right 37 | // while (step < arr.length) { 38 | // left = 0 39 | // right = step 40 | 41 | // while (right + step <= arr.length) { 42 | // mergeArrays(arr, left, left + step, right, right + step) 43 | // left = right + step 44 | // right = left + step 45 | // } 46 | 47 | // if (right < arr.length) { 48 | // mergeArrays(arr, left, left + step, right, arr.length) 49 | // } 50 | 51 | // step *= 2 52 | // } 53 | // } 54 | 55 | // function mergeArrays(arr, startLeft, stopLeft, startRight, stopRight){ 56 | 57 | // let rightArr = new Array(stopRight - startRight + 1) 58 | // let leftArr = new Array(stopLeft - startLeft + 1) 59 | 60 | // k = startRight 61 | 62 | // for (let i=0; i < (rightArr.length - 1); ++i) { 63 | // rightArr[i] = arr[k] 64 | // ++k 65 | // } 66 | 67 | // k = startLeft 68 | // for (let i=0; i < (leftArr.length - 1); ++i) { 69 | // leftArr[i] = arr[k] 70 | // ++k 71 | // } 72 | 73 | // rightArr[rightArr.length - 1] = Infinity 74 | // leftArr[leftArr.length - 1] = Infinity 75 | // let m = 0 76 | // let n = 0 77 | 78 | // for (let k = startLeft; k < stopRight; ++k) { 79 | // if (leftArr[m] <= rightArr[n]) { 80 | // arr[k] = leftArr[m] 81 | // m++ 82 | // } 83 | 84 | // else{ 85 | // arr[k] = rightArr[n] 86 | // n++ 87 | // } 88 | // } 89 | // } 90 | 91 | // const num = [6, 10, 1, 4, 19, 8, 3, 7, 16] 92 | // console.log("num ", num) 93 | 94 | // const result = mergeSort(num) 95 | // console.log("result ", result) 96 | 97 | 98 | let quickSort = function(arr) { 99 | if (arr.length < 2) return arr 100 | 101 | let piovtIndex = Math.floor(arr.length / 2) 102 | let piovt = arr.splice(piovtIndex, 1)[0] 103 | let left = [] 104 | let right = [] 105 | 106 | for (let i = 0; i < arr.length; i++) { 107 | if (arr[i] < piovt) { 108 | left.push(arr[i]) 109 | } else { 110 | right.push(arr[i]) 111 | } 112 | } 113 | 114 | return quickSort(left).concat([piovt], quickSort(right)) 115 | } 116 | 117 | const num = [6, 10, 1, 4, 19, 8, 3, 7, 16] 118 | console.log("num ", num) 119 | 120 | const result = quickSort(num) 121 | console.log("result ", result) 122 | -------------------------------------------------------------------------------- /leetcode学习/排序算法.md: -------------------------------------------------------------------------------- 1 | ### 排序算法——归并排序 2 | #### 自顶向下的归并排序 3 | ``` 4 | function mergeSort(arr) { 5 | if (arr.length < 2) return arr 6 | 7 | let middle = Math.floor(arr.length / 2) 8 | let left = arr.slice(0, middle) 9 | let right = arr.slice(middle) 10 | 11 | return merge(mergeSort(left), mergeSort(right)) 12 | } 13 | 14 | function merge(left, right) { 15 | let result = [] 16 | 17 | while (left.length > 0 && right.length > 0) { 18 | if (left[0] < right[0]) { 19 | result.push(left.shift()) 20 | } else { 21 | result.push(right.shift()) 22 | } 23 | } 24 | 25 | return result.concat(left).concat(right) 26 | } 27 | 28 | const num = [6, 10, 1, 4, 19, 8, 3, 7, 16] 29 | console.log("num ", num) 30 | 31 | const result = mergeSort(num) 32 | console.log("result ", result) 33 | ``` 34 | 35 | #### 自底向上的归并排序 36 | 在网上找资料的时候还看到这种自底向上的归并排序,虽然没咋看懂,先记下来,下回再看 37 | ``` 38 | function mergeSort(arr){ 39 | if (arr.length < 2) return arr 40 | 41 | let step = 1 42 | let left, right 43 | while (step < arr.length) { 44 | left = 0 45 | right = step 46 | 47 | while (right + step <= arr.length) { 48 | mergeArrays(arr, left, left + step, right, right + step) 49 | left = right + step 50 | right = left + step 51 | } 52 | 53 | if (right < arr.length) { 54 | mergeArrays(arr, left, left + step, right, arr.length) 55 | } 56 | 57 | step *= 2 58 | } 59 | } 60 | 61 | function mergeArrays(arr, startLeft, stopLeft, startRight, stopRight){ 62 | 63 | let rightArr = new Array(stopRight - startRight + 1) 64 | let leftArr = new Array(stopLeft - startLeft + 1) 65 | 66 | k = startRight 67 | 68 | for (let i=0; i < (rightArr.length - 1); ++i) { 69 | rightArr[i] = arr[k] 70 | ++k 71 | } 72 | 73 | k = startLeft 74 | for (let i=0; i < (leftArr.length - 1); ++i) { 75 | leftArr[i] = arr[k] 76 | ++k 77 | } 78 | 79 | rightArr[rightArr.length - 1] = Infinity 80 | leftArr[leftArr.length - 1] = Infinity 81 | let m = 0 82 | let n = 0 83 | 84 | for (let k = startLeft; k < stopRight; ++k) { 85 | if (leftArr[m] <= rightArr[n]) { 86 | arr[k] = leftArr[m] 87 | m++ 88 | } 89 | 90 | else{ 91 | arr[k] = rightArr[n] 92 | n++ 93 | } 94 | } 95 | } 96 | 97 | const num = [6, 10, 1, 4, 19, 8, 3, 7, 16] 98 | console.log("num ", num) 99 | 100 | const result = mergeSort(num) 101 | console.log("result ", result) 102 | ``` 103 | 输出的结果是undefined,应该写的还有点问题,后面再看看 104 | 105 | ### 排序算法——快速排序 106 | 想知道原理基础概念看这[文章](https://juejin.im/post/5966f57051882568b20dc3e1) 107 | ``` 108 | let quickSort = function(arr) { 109 | if (arr.length < 2) return arr 110 | 111 | let piovtIndex = Math.floor(arr.length / 2) 112 | let piovt = arr.splice(piovtIndex, 1)[0] 113 | let left = [] 114 | let right = [] 115 | 116 | for (let i = 0; i < arr.length; i++) { 117 | if (arr[i] < piovt) { 118 | left.push(arr[i]) 119 | } else { 120 | right.push(arr[i]) 121 | } 122 | } 123 | 124 | return quickSort(left).concat([piovt], quickSort(right)) 125 | } 126 | 127 | const num = [6, 10, 1, 4, 19, 8, 3, 7, 16] 128 | console.log("num ", num) 129 | 130 | const result = quickSort(num) 131 | console.log("result ", result) 132 | ``` -------------------------------------------------------------------------------- /大学期间记录/支付宝前端面试.md: -------------------------------------------------------------------------------- 1 | # 支付宝前端面试 2017-02-27 2 | 头条失利面试后,特地来一趟杭州,26号上午去了滴滴,面试感觉还不错,让我等消息,希望感觉还是挺大的,下午去了支付宝面试,面试官人挺好的,整场面试下来,没啥太大压力,主要是自己的技术深度不够,应该是没过,不过还是有收获,写点东西记录一下 3 | 4 | ## 笔试部分 5 | 1. 说说对洗牌算法的理解和如何验证其正确性 6 | 洗牌算法之前没了解过,刚面到的时候好蒙,闲话不多说,这里说下洗牌算法的js实现 7 | 8 | Fisher-Yates 9 | 这是最经典的洗牌算法,其算法思想是从原数组中随机抽取一个新的元素到新数组中 10 | 11 | 从还没处理的数组(假如还剩n个)中,产生一个[0,n]之间的随机数random 12 | 13 | 从剩下的n个元素中把第random个元素取出到新数组中 14 | 15 | 删除原数组第random个元素 16 | 17 | 重复第2 3步直到所有的元素取完 18 | 19 | 最终返回一个新的打乱的数组 20 | 21 | 代码实现 22 | ``` 23 | function shufle(arr){ 24 | var result = [], 25 | random; 26 | while(arr.length > 0){ 27 | random = Math.floor(Math.random() * arr.length); 28 | result.push(arr[random]) 29 | arr.splice(random, 1) 30 | } 31 | return result; 32 | } 33 | ``` 34 | 这种算法的时间复杂度是O(n2) 35 | 36 | 参考链接 [洗牌算法的js实现](https://github.com/ccforward/cc/issues/44) 37 | 参考链接 [Fisher–Yates shuffle 洗牌算法](https://gaohaoyang.github.io/2016/10/16/shuffle-algorithm/) 38 | 39 | 2. 还有一道是求解一颗树的最大权重的路径,对算法真的是功底比较薄弱,没耽搁时间,直接说不会 40 | 41 | ## 面试部分 42 | 面试官人很好,问的也很全面,没过完全是自己的问题,自己的技术积累还不到家,这里就暂时不为每个题目解答了,先把记得的题目写一下 43 | 1. 说一说你对highChart和EChart的理解,以及两者的区别,除了这两个还用过别的插件吗,分别说下他们的不同? 44 | 45 | 2. 说一下你对事件委托和事件代理的理解? 46 | 什么是事件委托?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件,当我们需要对很多元素添加事件的时候,可以通过事件添加到他们的父节点二将时间委托给父节点来触发处理函数 47 | 48 | 为什么要使用事件委托? 49 | 一般来说,dom需要有事件处理程序,我们都会直接给它设置事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们这里有100个li,每个li都有相同的click事件,那么我们会用for循环的方法来遍历所有的li,然后给他们添加事件,那么这样会存在什么问题呢? 50 | 在JavaScript中,添加到页面上的事件处理程序的数量将直接关联到页面整体的运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数就越多,就会延长整个页面交互就绪时间,这就是为什么性能优化的主要思想是减少dom操作的原因,如果使用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能 51 | 每个函数都是一个对象,是对象就会占用内存,内存占用率就越大,自然性能就差了,比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,如果使用事件委托,那么我们就可以只对它的父级这一个对象(如果只有一个父级)进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好 52 | 53 | 事件委托的原理? 54 | 事件委托是利用事件的冒泡机制来实现的,何为事件冒泡呢?这里介绍下浏览器dom事件处理的过程,dom2.0模型将事件流程分为三个阶段:事件捕获阶段,事件目标阶段,事件冒泡阶段。 55 | 事件捕获:当某个元素触发某个事件,顶层对象document就会发出一个事件流,随着dom树的节点向目标元素节点流去,直到到达事件真正发生的目标元素,在这个过程中,事件相应的监听函数是不会被触发的 56 | 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数,如果没有绑定监听函数,那就不执行 57 | 事件冒泡:从目标元素开始,往顶层元素传播,途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发,如果想阻止事件冒泡,可以使用event.stopPropgation()或者event.cancelBubble=true来阻止事件的冒泡传播 58 | 59 | 事件委托怎么实现: 60 | Event对象提供了一个属性叫target,可以返回事件的目标节点,我们称为事件源,也就是说,target就可以表示为当前事件操作的dom,但是不是真正操作的dom,当然,这个是有兼容性的,标准浏览器用event.target,IE浏览器用event.srcElement,此时知识获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,一般转化为小写再进行比较 61 | 如果你想将事件委托给父元素来处理,但每个子元素的事件内容又不相同时,这里我们可以给每个子元素添加一个唯一的key来作标识,然后在父元素中对其进行分别的处理 62 | ``` 63 | const list = document.querySelector('#list) 64 | const lists = list.querySelector('#list > li') 65 | for(let i=0; i 60 | 61 | - flex-grow定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大 62 | flex-grow:<`number`> 63 | 如果所有项目的flex-grow属性都为1,则他们将等分剩余空间(如果有的话) 64 | 65 | - flex-shrink定义项目的缩小比例,默认为1,即如果空间不足,该项目将缩小 66 | flex-shrink: <`number`> 67 | 如果一个项目的flex-shrink属性为0,其他项目为1,则空间不足时,前者不缩小 68 | 69 | - flex-basis定义项目在分配多余空间之前,项目占据的主轴空间,默认为auto,可以设置为width或height一样的值 70 | flex-basis:<`length`> | `auto` 71 | 72 | - flex属性是flex-grow,flex-shrink,flex-basis的简写,默认为0 1 auto 73 | 默认存在两个快捷值auto(1,1,auto)和none(0,0,auto) 74 | 75 | - align-self允许单个项目和其他项目不一样的对齐方式,可覆盖align-items属性,默认值为auto 76 | align-self:auto | flex-start | flex-end | center | baseline | stretch 77 | 78 | 参考链接 [flex布局教程:语法篇](http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html) 79 | 参考链接 [flex布局教程:实战篇](http://www.ruanyifeng.com/blog/2015/07/flex-examples.html) 80 | 81 | ### 说一下一个未知宽高元素怎么上下左右垂直居中 82 | 1. position+absolute 83 | ``` 84 | position: absolute; 85 | top: 50%; 86 | left: 50%; 87 | -webkit-transform: translate(-50%, -50%); 88 | transform: translate(-50%, -50%); 89 | ``` 90 | 2. flex 91 | ``` 92 | display: flex; 93 | align-items: center; 94 | justify-content: center; 95 | ``` 96 | 3. table-cell 97 | ``` 98 | display: table;(父) 99 | 100 | display: table-cell;(子) 101 | text-align: center; 102 | vertical-align: middle; 103 | ``` 104 | 4. position+margin 105 | ``` 106 | position: absolute; 107 | top: 0; 108 | left: 0; 109 | right: 0; 110 | bottom: 0; 111 | margin: auto; 112 | ``` 113 | 114 | 参考链接 [未知宽高元素水平居中](http://www.cnblogs.com/shytong/p/4959287.html) 115 | 116 | ### 说一下原型链,对象,构造函数之间的一些联系 117 | 1. javascript函数的new关键字到底是干什么的 118 | 不用创建临时对象,因为new会帮你做 119 | 不用绑定原型,因为new会帮你做 120 | 不用return临时对象,因为new会帮你做 121 | 不要给原型想名字了,因为new指定名字为prototype 122 | 123 | 2. 对象与原型链(__proto__和prototype) 124 | 每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法 125 | 对象__proto__属性的值就是他所对应的原型对象 126 | 只有函数才有prototype属性,当你创建函数时,JS会为这个函数自动添加prototype属性,值是一个有constructor属性的对象,不是空对象,而一旦你把这个函数当作构造函数调用时,那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法 127 | 对象的__proto__指向自己构造函数的prototype 128 | Object.prototype是原型链的顶端,Object本身是构造函数,继承了Function.prototype,Function也是对象,继承了Object.prototype 129 | Object.prototype.__proto__ === null,说明原型链到Object.prototype终止 130 | null表示‘没有对象’,即此处不该有值 131 | Function本身就是函数,Function.__proto__是标准的内置对象Function.prototype,而Function.prototype.__proto__是标准的内置对象Object.prototype 132 | 133 | 3. 构造函数和原型 134 | 原型:每一个JS对象(除null外)在创建的时候就会与之关联另一个对象,这个对象就是我们说的原型,每个对象都会从原型继承属性 135 | __proto__:每一个JS对象(除null外)都具有的一个属性,叫__proto__,这个属性会指向该对象的原型 136 | constructor:每一个原型都有一个constructor属性指向关联的构造函数 137 | 138 | 139 | 参考链接 [js的new到底是干什么的](https://zhuanlan.zhihu.com/p/23987456?utm_medium=social&utm_source=wechat_session) 140 | 参考链接 [从__proto__和prototype来深入理解JS对象和原型链](https://github.com/creeperyang/blog/issues/9) 141 | 参考链接 [javascript深入之从原型到原型链](https://github.com/mqyqingfeng/Blog/issues/2) 142 | 参考链接 [从探究Function.__proto__===Function.prototype过程中的一些收获](https://github.com/jawil/blog/issues/13) 143 | 144 | ### DOM事件绑定的几种方式 145 | 1. html中直接绑定 146 | html中绑定事件叫做内联绑定事件,不利于分离 147 | 148 | 2. js中直接绑定 149 | js中直接绑定称为赋值绑定函数,缺点是只能绑定一次 150 | 151 | 3. addEventListener 152 | target.addEventListener(type, listener[, useCapture]) 153 | target表示要监听事件的目标对象,可以是一个文档上的元素DOM本身,Window或者XMLHttpRequest 154 | type表示事件类型的字符串 155 | listener为当指定的事件类型发生时被通知到的一个对象 156 | useCapture为设置事件的捕获或者冒泡 157 | true为捕获,false为冒泡(默认) 158 | addEventListener可以给同一个dom元素绑定多个函数,并且执行顺序按照绑定顺序执行,且执行顺序与useCapture无关 159 | 给一个dom元素绑定同一个函数,最多只能绑定useCapture类型不同的两次 160 | addEventListener只支持到IE9,为兼容性考虑,在兼容IE8及一下浏览器可以用attachEvent函数,和addEventListener函数表现一样,但它绑定函数的this会指向全局 161 | 162 | 4. 事件的解绑 163 | 通过dom的on***属性设置的事件,可以用`dom.onclick = null`来解绑 164 | 通过addEventListener绑定的事件可以使用removeEventListener来解绑,接受参数一样 165 | 对于使用removeEventListener函数解绑事件,需要传入的listener,useCapture和addEventListener完全一致才可以解绑事件 166 | 167 | 5. 事件冒泡 168 | 事件开始时由最具体的元素接受,然后逐级向上传播到较为不具体的节点 169 | 170 | 6. 事件捕获 171 | 事件捕获的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件,与事件冒泡顺序相反 172 | 173 | 7. DOM事件流 174 | DOM事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截获事件提供机会,然后是实际的目标接受事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件作出响应 175 | 176 | 8. stopPropagation()和stopImmediatePropagation() 177 | stopPropagation()既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段 178 | stopImmediatePropagation()既可以阻止事件冒泡,也可以阻止事件捕获,还会阻止该元素其他事件的发生 179 | 180 | 参考链接 [从一个事件绑定说起-DOM](https://qiutc.me/post/binding-event-of-dom.html) 181 | 182 | ### 有没有了解http2,websocket,https,说一下你的理解以及你了解的特性 183 | 1. http2.0和http1.1的区别 184 | - 多路复用 185 | 多路复用允许单一的http2连接同时发起多重的请求-响应信息 186 | http性能优化的关键并不在于高带宽,而是低延迟,TCP连接会随着时间进行自我调谐,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度,这种调谐则称之为TCP慢启动,由于这种原因,让原本就具有突发性和短时性的http连接变得十分低效 187 | http2通过让所有数据流共用同一个连接,可以更有效的使用TCP连接,让高带宽也能真正服务于http的性能提升 188 | 小总结:多路复用技术,单连接多资源的方式,减少服务端的链接压力,内存占用更少,连接吞吐量更大,由于减少TCP慢启动时间,提高传输的速度 189 | 190 | 因为所有的http2的请求都在一个TCP连接上,所以在http1中的自动化合并文件和Sprite合图等资源合并减少请求的优化手段对于http2来说是没有效果的 191 | 192 | - 二进制分帧 193 | http2在应用层和传输层之间增加一个二进制分帧层,http2会将所有传输的信息分割成更小的消息和帧,并对他们采用二进制格式的编码,其中http1的首部信息会被封装成Headers帧,而我们的request body则封装到Data帧里面 194 | 195 | - 首部压缩 196 | http请求和响应都是由状态行,请求/响应头部,消息主题三部分组成,一般而言,消息主题都会经过gzip压缩,或者本身传输的就是压缩后的二进制文件,但状态行和头部却没有经过任何压缩,直接以纯文本传输,浪费流量资源 197 | 原理:头部压缩需要在支持http2的浏览器和服务端之间,维护一份相同的静态字典,包含常见的头部名称与值的组合,维护一份相同的动态字典,可以动态的添加内容,支持基于静态哈夫曼码表的哈夫曼编码 198 | 199 | - http2支持服务器推送 200 | 服务端推送是一种在客户端请求之前发送数据的机制,当代网页使用了许多资源:html,样式表,脚本等,在http1.x中这些资源每一个都必须明确的请求,这可能是一个很慢的过程,因为服务器必须等待浏览器做的每一个请求,网络经常是空闲和未充分使用的 201 | 为了改善延迟,http2引入了server push,它允许服务端推送资源给浏览器,在浏览器明确请求之前,一个服务器经常知道一个页面需要更多的附加资源,在他响应浏览器第一个请求时,可以开始推送这些资源,这允许服务端去完全充分利用一个可能空闲的网络,改善页面加载的时间 202 | 有了http2的服务端推送,http1时代的内嵌资源的优化手段也变得没有意义了,使用服务端推送更高效,因为客户端可以缓存起来,甚至可以不同页面之间共享 203 | 204 | - 并行双向字节流的请求和响应 205 | 在http2上,客户端和服务端可以把http消息分解成回不依赖的帧,然后乱序发送,最后再在另一端把她们重新组合起来,同一链接上可以有多个不同方向上的数据在传输,客户端可以一边乱序发送stream,也可以一边接收着服务端的响应,在服务端同理 206 | 把http消息分解为独立的帧,交错发送,然后在另一端重新组装是http2最重要的一项增强,这个机制会在整个web技术栈中引发一系列的连锁反应,从而带来巨大的性能提升,因为 207 | 1. 可以并行交错的发送请求,请求之间互不影响 208 | 2. 可以并行交错的发送响应,响应之间互不干扰 209 | 3. 只使用同一个连接即可并行的发送多个请求和响应 210 | 4. 消除不必要的延迟,从而减少页面加载的时间 211 | 也就是说‘域名分区’的优化手段对于http2来说是无用的,因为资源都是并行交错发送,且没有限制,不需要额外的多域名并行下载 212 | 213 | - http2的请求优先级 214 | 每个http2流里面有个优先值,这个优先值确定着客户端和服务端处理不同的流采取不同的优先级策略,高优先级的流应该优先发送,但又不是绝对的准守,可能又会引入首队阻塞的问题,高优先级的请求慢导致阻塞其他文件的交付,分配处理资源和客户端与服务器间的带宽,不同优先级的混合是必须的 215 | 216 | 2. https 217 | http协议传输的数据都是未加密的,也就是明文的,因此使用http协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL协议用于对http协议传输的数据进行加密,从而诞生了https,现在的https使用的都是TSL协议 218 | 219 | https在传输数据之前需要客户端和服务端之间进行一次握手,在握手的过程中将确立双方加密传输数据的密码信息,TSL/SSL协议不仅仅是一套加密传输的协议,TSL/SSL中使用了非对称加密,对称加密以及hash算法 220 | 221 | 握手过程: 222 | - 浏览器将自己支持的一套加密规则发送给网站 223 | 224 | - 网站从中选出一组加密算法和hash算法,并将自己的身份信息以证书的形式发回给浏览器,证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息 225 | - 获得网站证书后浏览器要做以下工作 226 | 1. 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致)如果证书受信任,则浏览器栏里会显示一个小锁头,否则会给出证书不受信的提示 227 | 2. 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密 228 | 3. 使用约定好的hash计算握手信息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给网站 229 | 230 | - 网站接收浏览器发来的数据之后要做以下工作 231 | 1. 使用自己的私钥将信息解密取出密码,使用密码解密浏览器发来的握手信息,并验证hash是否与浏览器发来的一致 232 | 2. 使用密码加密一段握手信息,发送给浏览器 233 | 234 | - 浏览器解密并计算握手信息的hash,如果与服务端发来的hash一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密 235 | 236 | 这里浏览器与网站互相发送加密的握手信息并验证,目的是为了保证双发都获得了一致的密码,并且可以正常的加密解密数据 237 | 238 | 其中非对称加密算法用于在握手过程中加密生成的密码,对称加密算法用于对真正传输的数据进行加密,而hash算法用于验证数据的完整性 239 | 240 | 由于浏览器生成的密码是整个数据加密的关键,因此在传输的时候使用了非对称加密算法对其进行加密,非对称加密算法会生成公钥和私钥,公钥只能用于加密数据,因此可以随意传输,而网站的私钥用于对数据进行解密,所以网站都会非常小心的保管自己的私钥,防止泄漏 241 | 242 | TSL握手的过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私数据的传输,正是由于https非常的安全,攻击者无法从中找到下手的地方,于是更多的是采用了假证书的手法来欺骗客户端,从而获取明文信息 243 | 244 | 3. webSocket概述 245 | http协议是一种无状态的协议,要实现有状态的会话必须借助一些外部机制如session和cookie,这或多或少或带来一些不便,尤其是服务端和客户端需要实时交换数据的时候 246 | webSocket允许服务器和客户端进行全双工通信,传统的http是单工通信的,它只允许客户端向服务端发出请求,服务端被动返回数据,而不能主动向客户端传递数据 247 | webSocket的请求头部 248 | ``` 249 | Connection: Upgrade //通信协议提升 250 | Upgrade: websocket //传输协议升级为websocket 251 | Sec-WebSocket-Key: ********** //握手协议密钥,base64位编码的16字节的随机字符串 252 | ``` 253 | webSocket的响应头部 254 | ``` 255 | Connection: Upgrade //通信协议提升 256 | Upgrade: websocket //传输协议升级为websocket 257 | Sec-WebSocket-Accept: ********** //将客户上报的Sec-WebSocket-Key和一段GUID(258EAFA5-E914-47DA-95CA-C5AB0DC85B11)进行拼接,再将这个拼接的字符串做SHA-1 hash计算,然后再把得到的结果通过base64加密,最后再返回给客户端 258 | ``` 259 | WebSocket,ajax轮询和long poll 260 | 261 | 参考链接 [http2.0协议你应该准备的面试题](https://www.toutiao.com/i6491669443721036302/) 262 | 参考链接 [面试时如何优雅的谈论http](https://www.jianshu.com/p/52d86558ca57) 263 | 参考链接 [http2.0的奇妙日常](http://www.alloyteam.com/2015/03/http2-0-di-qi-miao-ri-chang/) 参考链接 [浅谈WebSocket协议及其实现](http://geocld.github.io/2017/10/21/websocket/) 264 | 265 | ## 一轮技术面 266 | ### webpack的入口文件怎么配置,多个入口怎么分割 267 | 1. 配置文件 268 | webpack.config.js就是webpack的配置文件,这个文件需要自己在项目根目录下面手动建立,先看一个没有内容的标准webpack配置模版 269 | ``` 270 | module.exports = { 271 | entry: {}, //配置入口文件的地址,可以是单一入口,也可以是多入口 272 | output: {}, //配置出口文件的地址,在webpack2.x的版本之后,支持多出口配置 273 | module: {}, //配置模块,主要是解析css和图片转换压缩等功能 274 | plugins: [], //配置插件,根据你的需要配置不同功能的插件 275 | devServer: {} //配置开发服务功能 276 | } 277 | ``` 278 | 2. 多入口,多出口配置 279 | ``` 280 | module.exports = { 281 | entry: { 282 | index1: './src/index1.js', 283 | index2: './src/index2.js , 284 | }, 285 | output: { 286 | path: path.resolve(__dirname, 'dist'), 287 | filename: '[name].js', 288 | }, 289 | module: {}, 290 | plugins: [], 291 | devServer: {}, 292 | } 293 | ``` 294 | 给entry参数传入一个对象,对象的key在webpack中相当于此入口的name,既可以用来拼接生成文件的路径,也可以用来作为此入口的唯一标识 295 | 296 | 参考链接 [webpack配置文件](https://segmentfault.com/a/1190000011333071) 297 | 参考链接 [webpack配置常用部分有哪些](https://segmentfault.com/a/1190000011333071) 298 | --------------------------------------------------------------------------------