先笔试(4页纸),笔试过程前台小姐姐会帮你倒一杯咖啡(贴心),再面试(三个面试官轰炸式提问)
1.js实现数组归并排序:
归并排序算法是一种分治算法。其主要思想是将原始的数组切分为较小的数组,直到每个数组中的元素只有一个位置,接着讲小数组归并为一个而大的数组,直到最后只有一个大数组。
其算法的时间复杂度为O(nlogn),是一种比较优越的排序算法。
slice() 方法可从已有的数组中返回选定的元素 ;
Math.floor(x) 方法是向下取整计算,它返回的是小于或等于x,并且与x最接近的整数;
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值;
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度;
concat() 方法用于连接两个或多个数组(该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本)。
1 //辅助函数(用来合并和排序小数组来产生大数组) 2 function merge(left, right) { 3 var result = []; 4 while (left.length > 0 && right.length > 0) { 5 if (left[0] < right[0]) { 6 result.push(left.shift()); 7 } else { 8 result.push(right.shift()); 9 } 10 } 11 return result.concat(left).concat(right); 12 } 13 //主要函数(递归调用) 14 function mergeSort(arr) { 15 if (arr.length == 1) { 16 return arr; 17 } 18 var middle = Math.floor(arr.length / 2), 19 left = arr.slice(0, middle), 20 right = arr.slice(middle); 21 return merge(mergeSort(left), mergeSort(right)); 22 }
23 var array = [9,8,7,6,5,4];
24 console.log(mergeSort(array));
2.从用户输入URL到页面渲染都经历了什么:(经典中的经典)
+DNS解析(实现了网址到IP地址的转换)
+TCP连接
+发送HTTP请求(构建HTTP请求报文并通过TCP协议中发送到服务器指定端口。HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文)
+服务器处理请求并返回HTTP报文(HTTP响应报文也是由三部分组成: 状态码, 响应报头和响应报文)
+浏览器解析渲染页面(浏览器在收到HTML,CSS,JS文件后,边解析边渲染)
reflow(回流)--DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;
repain(重绘)--当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。
页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。
+连接结束
3.前端如何优化页面性能:
+DNS优化(设置DNS多级缓存,DNS负载均衡)
+HTTP(减少HTTP请求)
合并CSS文件,合并JS文件,雪碧图(将一些小图片制作成雪碧图,只会请求一次),缓存(将一些CSS文件或者JS文件缓存下来),减少cookie中不必要的信息
+Web优化
CSS--尽量不要在行内写CSS ,使用link代替@import ,压缩CSS,避免使用CSS表达式,CSS写在HTML文件上部;
JavaScript--JS以外部文件形式引入 ,避免重复的JS代码,减少JS对DOM的操作,避免无谓的循环,JS代码(引入连接)放在页面下部 ,压缩JS代码
HTML--如果可能减少页面中的DOM元素
+图片(图片使用适当的格式,比如小图片用GIF PNG8等这样会减少图片的大小)
4.如何制作雪碧图:
photoshop(工作效率太低)
利用在线生成工具生成雪碧图(https://www.toptal.com/developers/css/sprite-generator)
自动合成法:gulp、fis3、webpack打包合成 (面试官应该想让你用回答这个)
+webpack打包合成:安装webpack-spritesmith插件对文件进行打包即可生产css文件和png图片
安装webpack-spritesmith(npm i webpack-spritesmith –save-dev)
在webpack.config.js中配置plugins
1 //声明插件 2 const SpritesmithPlugin = require('webpack-spritesmith'); 3 4 //配置插件 5 plugins:[ 6 new SpritesmithPlugin({ 7 src: { 8 cwd: path.resolve(__dirname,'src/ico'), 9 glob: '*.png' 10 }, 11 target: { 12 image: path.resolve(__dirname,'src/assets/sprites.png'), 13 css: path.resolve(__dirname, 'src/assets/_sprites.css') 14 }, 15 apiOptions: { 16 cssImageRef: './sprites.png' 17 } 18 }) 19 ]
webpack执行打包生成文件路径‘src/assets’下有两个文件sprites.png、_sprites.css即为所得
5.你会切图吗
因为公司有美术组,所以不用自己做雪碧图啊,切图啊等等(自己真的好想忘记怎么切图了!),不过我还是义正言辞的说:会!(反正只是面试。。。)
6. vue的双向数据绑定是怎么实现的
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调
7. 讲一下ES5的原型
在 JavaScript 中,每个函数对象都有一个prototype属性,这个属性指向函数的原型对象。而原型对象他本身就是一个普通对象。
只有函数对象才会拥有prototype属性,但是每个对象都拥有__proto__属性(null除外)
不论是普通对象还是函数对象,都有一个叫做__proto__
的内置属性,用于指向创建它的构造函数的原型对象。当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去__proto__里去找这个属性,这个__proto__又会有自己的__proto__,于是就这样一直找下去,这就是原型链的概念 (原型链的形成是真正是靠__proto__而非prototype)
Object.prototype
对象也有__proto__
属性,但它比较特殊,为 null 。因为 null 处于原型链的顶端,这个只能记住。
所有函数对象的__proto__都是指向Function.prototype,它是一个空函数;
在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype属性所在的函数
8.你了解浏览器的兼容吗?(百年老题)
常见兼容性问题:
不同浏览器的标签默认的外补丁( margin )和内补丁(padding)不同 == css 里增加通配符 * { margin: 0; padding: 0; }
IE6双边距问题;在 IE6中设置了float , 同时又设置margin , 就会出现边距问题 == 设置display:inline;
当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度 == 超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度
图片默认有间距 == 使用float 为img 布局
IE9以下浏览器不能使用opacity == opacity: 0.5;filter: alpha(opacity = 50);filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);
边距重叠问题;当相邻两个元素都设置了margin 边距时,margin 将取最大值,舍弃最小值 == 为了不让边重叠,可以给子元素增加一个父级元素,并设置父级元素为overflow:hidden;
hand 显示手型在safari 上不支持 == 统一使用 cursor:pointer
两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative ;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;== 父级元素设置position:relative
9.你平常自己封装组件吗?
作为一名前端工程师,写组件的能力至关重要(其实就是 面向对象 的能力)
10.你研究过jq源码吗?
我没看过。。。呜呜呜,但是我会装逼啊(我还没搞懂,看来我就是初级前端渣渣):
+ jQuery 整体框架(结构十分清晰,采用的是总--分的结构)
阅读源码很重要的一点是,摒弃面向过程的思维方式,不要刻意去追求从上至下每一句都要在一开始弄明白。很有可能一开始你在一个奇怪的方法或者变量处卡壳了,很想知道这个方法或变量的作用,然而可能它要到几千行处才被调用到。如果去追求这种逐字逐句弄清楚的方式,很有可能在碰壁几次之后阅读的积极性大受打击。
+ jQuery 闭包结构
jQuery 具体的实现,都被包含在了一个立即执行函数构造的闭包里面,为了不污染全局作用域,只在后面暴露 $ 和 jQuery 这 2 个变量给外界,尽量的避开变量冲突。
+ jQuery 无new构造
jQuery.fn.init.prototype = jQuery.fn(这句真的算是 jQuery 的绝妙之处)
jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;
new jQuery.fn.init() 相当于 new jQuery() ;
jQuery() 返回的是 new jQuery.fn.init(),而 var obj = new jQuery(),所以这 2 者是相当的,所以我们可以无 new 实例化 jQuery 对象。
+ jQuery 方法的重载(方法的重载即是一个方法实现多种功能)
当解读一个方法的时候感觉到了明显的困难,尝试着跳出卡壳的那段代码本身,站在更高的维度去思考这些复杂的逻辑是为了处理或兼容什么,是否是重载,为什么要这样写,一定会有不一样的收获。
+ jQuery.fn.extend 与 jQuery.extend
extend 方法在 jQuery 中是一个很重要的方法,jQuey 内部用它来扩展静态方法或实例方法,而且我们开发 jQuery 插件开发的时候也会用到它。
区分这两个 extend 方法是理解 jQuery 的很关键的一部分。
jQuery.extend(object) 为扩展 jQuery 类本身,为类添加新的静态方法;
jQuery.fn.extend(object) 给 jQuery 对象添加实例方法,也就是通过这个 extend 添加的新方法,实例化的 jQuery 对象都能使用,因为它是挂载在 jQuery.fn 上的方法(jQuery.fn = jQuery.prototype )。
+ jQuery 的链式调用及回溯(在要实现链式调用的方法的返回结果里,返回 this ,就能够实现链式调用了)
回溯是通过 end() 方法终止在当前链的最新过滤操作,返回上一个对象集合。依靠添加了 prevObject 这个属性(prevObject 保存了上一步的jQuery对象集合)
+ jQuery 正则与细节优化
+ jQuery 变量冲突处理
当需要处理冲突的时候,调用静态方法 noConflict(),让出变量的控制权
11.js的变量提升与函数提升
变量提升即将变量声明提升到它所在作用域的最开始的部分
函数提升(函数声明式和函数字面量式)只有函数声明式才存在函数提升!
12.有用ES6做项目吗
13.css3动画的两个属性
14.会不会用小程序
15. call和apply的区别
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法
apply:最多只能有两个参数——新this对象和一个数组argArray
call:它可以接受多个参数,第一个参数与apply一样,后面则是一串参数列表
16. 前端三层分别是
结构层 HTML 从语义的角度描述页面的结构
样式层 CSS 从审美的角度装饰页面
行为层 JavaScript 从交互的角度提升用户体验