前端菜鸡在进阶
斜体内容我是一名在读研究生,但是码代码能力较弱,除了完成作业从不主动敲代码。在三四月份两个月,疯狂投简历面试,面试岗位为web前端,五月份成功入职。
在找实习的这段时间,投过很多公司,包括BAT、今日头条、美团等,走过坑、趟过水,每个公司的每次面试我都总结了一些面经。现在先说一下
【笔试】
分为内推和网申,有渠道的同学可以进行内推,免笔试,直接面试,但是今日头条的面试是视频面试(目前面试前端,只遇到过头条是视频面试)
我走的内推,大家需要的话,这是牛客网的链接,今日头条2017前端工程师实习生笔试题
https://www.nowcoder.com/test/1649297/summary
【面试】 在校学生基本采取的是电面或者视频面。 一面:视频面试了一个多小时,头条很注重计算机的基础知识:数据结构、计算机网络、数据库、计算机组成原理。然后开始是专业知识:(视频面试一般都是敲代码的)下面是一些问题,我把找的答案也附在里面了,有点多,会有彩蛋的~ 一、js的继承 JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // 定义一个动物类 function Animal (name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function(){ console.log(this.name + '正在睡觉!'); } } // 原型方法 Animal.prototype.eat = function(food) { console.log(this.name + '正在吃:' + food); }; 1、原型链继承 核心: 将父类的实例作为子类的原型 特点: 1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例 2.父类新增原型方法/原型属性,子类都能访问到 3.简单,易于实现 缺点: 1.要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中 2.无法实现多继承 3.来自原型对象的引用属性是所有实例共享的(详细请看附录代码: 示例1) 4.创建子类实例时,无法向父类构造函数传参 推荐指数:★★(3、4两大致命缺陷) (prototype属性的引入:这个属性包含一个对象(以下简称"prototype对象"),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。) 2、构造继承 核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型) 特点: 1.解决了1中,子类实例共享父类引用属性的问题 2.创建子类实例时,可以向父类传递参数 3.可以实现多继承(call多个父类对象) 缺点: 1.实例并不是父类的实例,只是子类的实例 2.只能继承父类的实例属性和方法,不能继承原型属性/方法 3.无法实现函数复用,每个子类都有父类实例函数的副本,影响性能 推荐指数:★★(缺点3) 3、实例继承 核心:为父类实例添加新特性,作为子类实例返回 function Cat(name){ var instance = new Animal(); instance.name = name || 'Tom'; return instance; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // false 特点: 1.不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果 缺点: 1.实例是父类的实例,不是子类的实例 2.不支持多继承 推荐指数:★★ 4、拷贝继承 特点: 1.支持多继承 缺点: 1.效率较低,内存占用高(因为要拷贝父类的属性) 2.无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到) 推荐指数:★(缺点1) 5、组合继承 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用 function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true 特点: 1.弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法 2.既是子类的实例,也是父类的实例 3.不存在引用属性共享问题 4.可传参 5.函数可复用 缺点: 1.调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了) 推荐指数:★★★★(仅仅多消耗了一点内存) 6、寄生组合继承 核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点 function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 创建一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例作为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); //true 特点: 1.堪称完美 缺点: 1.实现较为复杂 推荐指数:★★★★(实现复杂,扣掉一颗星) 附录代码: 示例一: function Animal (name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function(){ console.log(this.name + '正在睡觉!'); } //实例引用属性 this.features = []; } function Cat(name){ } Cat.prototype = new Animal(); var tom = new Cat('Tom'); var kissy = new Cat('Kissy'); console.log(tom.name); // "Animal" console.log(kissy.name); // "Animal" console.log(tom.features); // [] console.log(kissy.features); // [] tom.name = 'Tom-New Name'; tom.features.push('eat'); //针对父类实例值类型成员的更改,不影响 console.log(tom.name); // "Tom-New Name" console.log(kissy.name); // "Animal" //针对父类实例引用类型成员的更改,会通过影响其他子类实例 console.log(tom.features); // ['eat'] console.log(kissy.features); // ['eat'] 原因分析: 关键点:属性查找过程 执行tom.features.push,首先找tom对象的实例属性(找不到), 那么去原型对象中找,也就是Animal的实例。发现有,那么就直接在这个对象的 features属性中插入值。 在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么去原型上找。 刚好原型上有,就直接返回,但是注意,这个原型对象中features属性值已经变化了。 二、原型链 css水平垂直居中 方案一: div绝对定位水平垂直居中【margin:auto实现绝对定位元素的居中】, 兼容性:,IE7及之前版本不支持 div{ width: 200px; height: 200px; background: green; position:absolute; left:0; top: 0; bottom: 0; right: 0; margin: auto; } 方案二: div绝对定位水平垂直居中【margin 负间距】 这或许是当前最流行的使用方法。 div{ width:200px; height: 200px; background:green; position: absolute; left:50%; top:50%; margin-left:-100px; margin-top:-100px; } 方案三: div绝对定位水平垂直居中【Transforms 变形】 兼容性:IE8不支持; div{ width: 200px; height: 200px; background: green; position:absolute; left:50%; / *定位父级的50%* / top:50%; transform: translate(-50%,-50%); /*自己的50%* /(translate(x,y) 水平方向和垂直方向同时移动) } 方案四:(不说) css不定宽高水平垂直居中 .box{ height:600px; display:flex; justify-content:center; align-items:center; / *aa只要三句话就可以实现不定宽高水平垂直居中。* / } .box>div{ background: green; width: 200px; height: 200px; } 方案五: 将父盒子设置为table-cell元素,可以使用text-align:center和vertical-align:middle实现水平、垂直居中。比较完美的解决方案是利用三层结构模拟父子结构 tableCell /*table-cell实现居中 将父盒子设置为table-cell元素,设置 text-align:center,vertical-align: middle; 子盒子设置为inline-block元素* / .tableCell{ display: table; } .tableCell .ok{ display: table-cell; text-align: center; vertical-align: middle; } .tableCell .innerBox{ display: inline-block; } 方案六: 对子盒子实现绝对定位,利用calc计算位置 calc /*绝对定位,calc计算位置*/ .calc{ position: relative; } .calc .innerBox{ position: absolute; left:-webkit-calc((500px - 200px)/2); top:-webkit-calc((120px - 50px)/2); left:-moz-calc((500px - 200px)/2); top:-moz-calc((120px - 50px)/2); left:calc((500px - 200px)/2); top:calc((120px - 50px)/2); } (对于calc(),总结以下要点: 1.兼容性:在IE9+、FF4.0+、Chrome19+、Safari6+支持较好,移动端支持不理想; 2.表达式支持加、减、乘、除运算,同时也支持单位的混合使用(%、px、em等); 2.表达式中有“+”,“-”运算符的,前后必须要有空格) Html5新特性,CSS3新特性 HTML5新特性 HTML5 中的一些有趣的新特性: 用于绘画的 canvas 元素 用于媒介回放的 video 和 audio 元素 对本地离线存储的更好的支持 新的特殊内容元素,比如 article、footer、header、nav、section 新的表单控件,比如 calendar、date、time、email、url、search 三、CSS3新特性 1\. CSS3实现圆角(border-radius),阴影(box-shadow), 2\. 对文字加特效(text-shadow、),线性渐变(gradient),旋转(transform) 3\. transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);// 旋转,缩放,定位,倾斜 4\. 增加了更多的CSS选择器 多背景 rgba 5\. 在CSS3中唯一引入的伪元素是 ::selection. 6\. 媒体查询,多栏布局 7\. border-image [https://blog.csdn.net/chandoudeyuyi/article/details/69206236](https://blog.csdn.net/chandoudeyuyi/article/details/69206236) Ajax实现原理 [https://www.cnblogs.com/jackson0714/p/AJAX.html](https://www.cnblogs.com/jackson0714/p/AJAX.html) [https://blog.csdn.net/fuxiaohui/article/details/72725500](https://blog.csdn.net/fuxiaohui/article/details/72725500) 8\. 创建XMLHttpRequest对象,也就是创建一个异步调用对象XHR 9\. 创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息 10\. 设置响应HTTP请求状态变化的函数 11\. 发送HTTP请求 12\. 获取异步调用返回的数据 13\. 使用JavaScript和DOM实现局部刷新 四、闭包 1.闭包是什么? 闭包是指有权访问另一个函数作用域中的变量的函数。 特性: (1).函数嵌套函数 (2).函数内部可以引用外部的参数和变量 (3).参数和变量不会被垃圾回收机制回收 2.如何创建? 在一个函数内部创建另一个函数。 【注意】:通常,函数的作用域及其所有变量都会在函数执行结束后被销毁 但是当函数返回到一个闭包时,这个函数的作用域将会一直在内存中存在到闭包不存在为止; 内部函数执行完成后,其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。 即:当内部函数被返回后,其执行环境作用链会被销毁,但它的活动对象仍然会留在内存中,直到匿名函数被销毁后,内层函数的活动对象才会被销毁。 6 //创建函数 var comparNames = createComparisonFunction("name"); //调用函数 var result = comparNames((name:"mimi"),(name:"haha")); //解除对匿名函数的引用(以便释放内存) compareNames = null; 3.闭包与变量 闭包只能取得包含函数中任何变量的最后一个值。 function createFunctions(){ var result = new Array(); for(var i=0; i<10;i++){ result[i] == function(){ return i ; } } return result; } ( 结果返回10 ) 解决办法:创建另一个匿名函数强制让闭包的行为达到预期。 function createFunctions(){ var result = new Array(); for(i=0;i<10;i++){ result[i]=function(num){ return function(){ return num; }; }(i); } return result; } ( 结果返回0~9 ) 4.关于this对象 (1):全局函数中:this等于window; (2):匿名函数的执行环境具有全局性,因此其this对象通常指向window. var name = "The Window"; // 创建全局name var object = { //创建包含name属性的对象 name:"My name"; getNameFunc:function(){ //包含一个方法 getNameFunc() return function(){ //返回一个匿名函数 return this.name; //匿名函数返回this.name } } }; alert(objext.getNameFunc(){}); ( 返回外部环境中的name ----The Window) 原因: 内部函数在搜索this和arguments时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数的这两个变量; 解决方法:把外部作用域的this对象保存在一个闭包能够访问到的变量里。 var name = "The Window"; var object = { name:"My name"; getNameFunc:function(){ var that = this; return function(){ return that.name; } } }; alert(objext.getNameFunc(){}); ( 返回匿名函数中的name ----My name) 说明: 定义匿名函数前,我们把this 对象赋值给that变量,在定义了闭包之后,闭包也可以访问之歌变量,因为它是我们在包含函数中特意声明的一个变量,及时函数返回,that仍然引用object,所以返回了“ My name” 测试下自己是否真正了解闭包: var foo = ( function() { var secret = 'secret'; // “闭包”内的函数可以访问 secret 变量,而 secret 变量对于外部却是隐藏的 return { get_secret: function () { // 通过定义的接口来访问 secret return secret; }, new_secret: function ( new_secret ) { // 通过定义的接口来修改 secret secret = new_secret; } }; } () ); foo.get_secret (); //得到? foo.secret; //得到? foo.new_secret ('a new secret'); foo.get_secret (); //得到? 答案: foo.get_secret (); // 得到 'secret' foo.secret; // Type error,访问失败 foo.new_secret ('a new secret'); // 通过函数接口,我们访问并修改了 secret 变量 foo.get_secret (); // 得到 'a new secret' 五、跨域 [https://www.cnblogs.com/roam/p/7520433.html](https://www.cnblogs.com/roam/p/7520433.html) 六、浮动,清除浮动 七、Es6(廖雪峰网站),会一个框架,打包(gulp,webpack) 八、css预处理 1、什么是CSS预处理器 CSS预处理器定义了一种新的语言,基本的思想是用一种专门的编程语言,开发者只需要使用这种语言进行编码工作,减少枯燥无味的CSS代码的编写过程的同时,它能让你的CSS具备更加简洁、适应性更强、可读性更加、层级关系更加明显、更易于代码的维护等诸多好处。 CSS预处理器种类繁多,本次就以Sass、Less、Stylus进行比较。 2、语法 在使用CSS预处理器之前最重要的是了解语法,我只写过stylus,就从网上找了下另外两种语法的格式,与大家对比分享。 首先Sass和Less都是用的是标准的CSS语法,因此你可以很方便的把已完成的CSS代码转为预处理器识别的代码,Sass默认使用 .sass扩展名,而Less默认使用.Less扩展名。 3、变量 你可以在CSS预处理中声明变量,并在整个样式单中使用,支持任何类型的变量,例如:颜色、数值(是否包含单位)、文本。然后你可以任意的调取和使用该变量。Sass的变量是必须$开始,然后变量名和值要冒号隔开,跟CSS属性书写格式一致。 Stylus对变量名没有任何限定,你可以是$开始,也可以是任意字符,而且与变量值之间可以用冒号、空格隔开,需要注意的是 Stylus (0.22.4) 将会编译 @ 开始的变量,但其对应的值并不会赋予该变量,换句话说,在 Stylus 的变量名不要用 @ 开头。 mainColor = #0982c1 siteWidth = 1024px $borderStyle = dotted body color mainColor border 1px $borderStyle mainColor max-width siteWidth 上面三种不同的CSS写法,最终将会生成相同结果: body { color: #0982c1; border: 1px dotted #0982c1; max-width: 1024px; } 最容易体现它的好处的是,假设你在CSS中使用同一种颜色数十次,如果你要修改显色,需要找到并修改十次相同的代码,而有了CSS预处理器,修改一个地方就够了。 4、嵌套 如果你需要在CSS中相同的parent引用多个元素,你需要一遍一遍的去写parent。例如: section { margin: 10px; } section nav { height: 25px; } section nav a { color: #0982C1; } section nav a:hover { text-decoration: underline; } 然而如果用CSS预处理器,就可以少些很多单词,而且父节点关系一目了然。 section { margin: 10px; nav { height: 25px; a { color: #0982C1; &:hover { text-decoration: underline; } } } } stylus还可省略花括号,书写更加方便,根据个人喜好还可删除中间冒号。 section margin: 10px; nav height: 25px; a color: #0982C1; &:hover text-decoration: underline; 最终生成CSS结果是: section { margin: 10px; } section nav { height: 25px; } section nav a { color: #0982C1; } section nav a:hover { text-decoration: underline; } 九、双栏布局 /*方法一: BFC(块级格式化上下文)*/ .container{ width:1000px;height:400px;border: 1px solid red; } .left{ width:200px;height:100%;background: gray; float: left; } .rigth{ overflow:hidden; / *触发bfc* / background: green; } /*方法二: flex布局* / .container{ width:1000px;height:400px;border:1px solid red; display:flex; /*flex布局*/ } .left{ width:200px; height:100%;background:gray; flex:none; } .right{ height:100%;background:green; flex:1; /*flex布局*/ } / *方法三: table布局* / .container{ width:1000px;height:400px;border:1px solid red; display:table; /*table布局*/ } .left{ width:200px; height:100%;background:gray; display:table-cell; } .right{ height:100%;background:green; display: table-cell; } /*方法四: css计算宽度calc*/ .container{ width:1000px;height:400px;border:1px solid red; } .left{ width:200px;height:100%;background:gray; float:left; } .right{ height:100%;background:green; float:right; width:calc(100% - 200px); } 十、HTTP强缓存和协商缓存 强缓存 强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。· Expires 该字段是http1.0时的规范,它的值为一个绝对时间的GMT格式的时间字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。 Cache-Control Cache-Control是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。***-control除了该字段外,还有下面几个比较常用的设置值: no-***:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。 no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。 public:可以被所有的用户缓存,包括终端用户和CDN等中间***服务器。 private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。 Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。 协商缓存 协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。 十一、线性结构和非线性结构 线性结构是什么呢?有什么特点呢? 线性结构有唯一的首元素(第一个元素) 线性结构有唯一的尾元素(最后一个元素) 除首元素外,所有的元素都有唯一的“前驱” 除尾元素外,所有的元素都有唯一的“后继” 数据元素之间存在“一对一”的关系 例如:数组A1,A2,A3,........An,首元素就是A1,尾元素就是An 什么结构属于线性结构呢? 顺序表(一维数组),堆,栈,队列,链表 那非线性结构是什么呢? 数据元素之间是一对多,或者是多对一的关系 非线性结构有什么呢? 图(群结构),树(层次结构),***数组 十二、网络层的七层协议: tips:如果不是自己比较熟悉领域的问题不要强行扯那么多,说不知道并且虚心向面试官求教也可以(我的面试官一般人都挺好,还带讲解的)。 二面:简历内容必须十分熟悉,简历里的项目要做好准备,面试官会问细节,一般也会让你挑一个有挑战的项目,遇到的问题以及如何解决的。 tips: 准备好简历,一份好的简历还是挺重要的
彩蛋就是:
tips:
1.如果电面,可以进行录音,记录一下面试过程
2.面完马上总结,记不清的听录音
3.在牛客网之类的应用上刷题和问问题,一般都会有人解答,也会有一些内推渠道
祝顺利!