前几天参加了一次我们公司的面试,第一次面试别人完全不知道问啥,全程主面试官在问,在这儿做一个总结
简单介绍下你自己(一分钟)
姓名+学校+专业+学历+家乡,然后话峰一转,这时切记不要拖泥带水,要精简、准确、流畅的表达一下自己在大学最那得出手的实践经历或实习经历或项目成果或学习成果等都可以,但切记你引用的素材(1到2个即可,按照你主要做了什么?结果是怎样的?你从中学到了什么?这样的黄金法则来叙述!)是与你所面试的职位所需要的条件是相关的!以此来突出自己的优势或强项。
(就最近的一个项目)你认为哪个项目做得最好,这个项目主要哪些人组成,你在中间担任什么样的角色,项目成果如何,项目中遇到的最大的问题是什么?你是怎么样解决的?
平时是如何学习前端开发的?
js相关
get 和post 区别
1、get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些
2、get相对post安全性低
3、get有缓存,post没有
4、get体积小,post可以无限大
5、get的url参数可见,post不可见
6、get只接受ASCII字符的参数数据类型,post没有限制
7、get请求参数会保留历史记录,post中参数不会保留
8、get会被浏览器主动catch,post不会,需要手动设置
9、get在浏览器回退时无害,post会再次提交请求
HTTP 协议 未规定 GET 和POST的长度限制
GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度,不同的浏览器和WEB服务器,限制的最大长度不一样
要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte
IE 和 Safari 浏览器 限制 2k
Opera 限制4k
Firefox 限制 8k(非常老的版本 256byte)
get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。
post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。
按HTML查找 vs 按选择器查找
- 返回值: 按HTML查找: 返回动态集合:
优: 效率高!只需返回需要的数据即可,不需要返回完整数据
缺: 造成反复查找
按选择器查找: 返回非动态集合
优: 不会反复查找
缺: 首次执行效率低 - 易用性: 当查找条件复杂时
按HTML查找: 繁琐
按选择器查找: 简洁
总结:
如果根据一个条件就可获得想要的元素:
首选按HTML查找
如果查找条件复杂时
首选按选择器查找
new一个对象发生了什么?
- 创建一个新的空对象
2. 让新对象继承构造函数的原型对象
3. 用空对象调用构造函数: 调用构造函数,将this自动指向新对象,并通过强行赋值的方式,为新对象添加新属性和方法
4. 返回新对象的地址保存到变量中
什么是闭包?
函数A 里面包含了 函数B,而 函数B 里面使用了 函数A 的变量,那么 函数B 被称为闭包。又或者:闭包就是能够读取其他函数内部变量的函数
函数内再嵌套函数
内部函数可以引用外层的参数和变量
参数和变量不会被垃圾回收制回收
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中
闭包的另一个用处,是封装对象的私有属性和私有方法
解决方法是:在退出函数之前,将不使用的局部变量全部删除
闭包形成:外层函数的函数作用域对象AO无法释放
闭包的经典解决方法:
使用let
for(let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
复制代码在这里,每个 let 和代码块结合起来形成块级作用域,当 setTimeout() 打印时,会寻找最近的块级作用域中的 i,所以依次打印出 0 1 2
如果这样不明白,我们可以执行下边这段代码
for(let i = 0; i < 3; i++) {
console.log("定时器外部:" + i);
setTimeout(function() {
console.log(i);
}, 1000);
}
复制代码此时浏览器依次输出的是:
定时器外部:0
定时器外部:1
定时器外部:2
0
1
2
复制代码即代码还是先执行 for 循环,但是当 for 结束执行到了 setTimeout 的时候,它会做个标记,这样到了 console.log(i) 中,i 就能找到这个块中最近的变量定义
第二种方法
使用立即执行函数解决闭包的问题
for(let i = 0; i < 3; i++) {
(function(i){
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
什么叫作用域链
一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值。
但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链
原型和原型链
每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去
JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变
当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的
就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象
谈谈你对组件化和模块化的理解
有时候页面代码量太大,逻辑太多或者同一个功能组件在许多页面均有使用,维护起来相当复杂,这个时候,就需要组件化开发来进行功能拆分、组件封装,已达到组件通用性,增强代码可读性,维护成本也能大大降低
组件化开发的优点
很大程度上降低系统各个功能的耦合性,并且提高了功能内部的聚合性。这对前端工程化及降低代码的维护来说,是有很大的好处的,耦合性的降低,提高了系统的伸展性,降低了开发的复杂度,提升开发效率,降低开发成本
模块化:早期的javascript版本没有块级作用域、没有类、没有包、也没有模块,这样会带来一些问题,如复用、依赖、冲突、代码组织混乱等,随着前端的膨胀,模块化显得非常迫切
1、函数封装 2、立即执行函数表达式(IIFE)
mouseover和mouseenter的区别
mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave
怎么解决异步回调地狱
promise、generator、async/await
谈谈你对This对象的理解
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
es6 的特有的类型
① let const 两者都有块级作用域
② 箭头函数
③ 模板字符串
④ 解构赋值
⑤ for of循环
⑥ import 、export 导入导出
⑦ set数据结构
⑧ ...展开运算符
⑨ 修饰器 @
⑩ class类继承
⑪ async、await
⑫ promise
⑬ Symbol
⑭ Proxy代理
vue相关
v-show与v-if区别
MVVM
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑
V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来
VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View
computed和watch有什么区别?
- computed是计算属性,也就是计算值,它更多用于计算值的场景
- computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
- computed适用于计算比较消耗性能的计算场景
watch: - 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作
- 无缓存性,页面重新渲染时值不变化也会执行
小结: - 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
- 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化
组件中的data为什么是函数?
为什么组件中的data必须是一个函数,然后return一个对象,而new Vue实例里,data可以直接是一个对象?
因为组件是用来复用的,JS里对象是引用关系,这样作用域没有隔离,而new Vue的实例,是不会被复用的,因此不存在引用对象问题
vue的单项数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改
vue双向绑定原理
通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
Vue2.0和Vue3.0的区别
1.项目目录结构 vue-cli2.0与3.0在目录结构方面,有明显的不同
vue-cli3.0移除了配置文件目录,config和build文件夹
同时移除了static静态文件夹,新增了public文件夹,打开层级目录还会发现,index.html移动到public中
2.配置项 3.0 config文件已经被移除,但是多了.env.production和env.development文件,除了文件位置,实际配置起来和2.0没什么不同
没了config文件,跨域需要配置域名时,从config/index.js 挪到了vue.config.js中,配置方法不变
3.渲染 Vue2.x使用的Virtual Dom实现的渲染
Vue3.0不论是原生的html标签还是vue组件,他们都会通过h函数来判断,如果是原生html标签,在运行时直接通过Virtual Dom来直接渲染,同样如果是组件会直接生成组件代码
4.数据监听 Vue2.x大家都知道使用的是es5的object.defineproperties中getter和setter实现的,而vue3.0的版本,是基于Proxy进行监听的,其实基于proxy监听就是所谓的lazy by default,什么意思呢,就是只要你用到了才会监听,可以理解为‘按需监听’,官方给出的诠释是:速度加倍,同时内存占用还减半。
5.按需引入 Vue2.x中new出的实例对象,所有的东西都在这个vue对象上,这样其实无论你用到还是没用到,都会跑一变。而vue3.0中可以用ES module imports按需引入,如:keep-alive内置组件、v-model指令,等等。
v-model 的原理
v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件;
v-if和v-for的优先级
v-for中key的理解
key的作用主要是为了高效的更新虚拟DOM,是因为Virtual DOM 使用Diff算法实现的原因。
父子组件如何传值
父组件主动调用子组件:$refs
子组件主动调用父组件:$parent
另外还有props 和$emit 这两种比较常用
vue生命周期
breforeCreate():实例创建前,这个阶段实例的data和methods是读不到的。
created():实例创建后,这个阶段已经完成数据观测,属性和方法的运算,watch/event事件回调,mount挂载阶段还没有开始。$el属性目前不可见,数据并没有在DOM元素上进行渲染。
created完成之后,进行template编译等操作,将template编译为render函数,有了render函数后才会执行beforeMount()
beforeMount():在挂载开始之前被调用:相关的 render 函数首次被调用
mounted():挂载之后调用,el选项的DOM节点被新创建的 vm.$el 替换,并挂载到实例上去之后调用此生命周期函数,此时实例的数据在DOM节点上进行渲染
后续的钩子函数执行的过程都是需要外部的触发才会执行
有数据的变化,会调用beforeUpdate,然后经过Virtual Dom,最后updated更新完毕,
当组件被销毁的时候,会调用beforeDestory,以及destoryed。
webpack相关
webpack打包原理
webpack只是一个打包模块的机制,只是把依赖的模块转化成可以代表这些包的静态文件。webpack就是识别你的 入口文件。识别你的模块依赖,来打包你的代码。至于你的代码使用的是commonjs还是amd或者es6的import。webpack都会对其进行分析。来获取代码的依赖。webpack做的就是分析代码。转换代码,编译代码,输出代码。webpack本身是一个node的模块,所以webpack.config.js是以commonjs形式书写的(node中的模块化是commonjs规范的)
如何提高webpack构建速度
1、通过externals配置来提取常用库
2、利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来
3、使用Happypack 实现多线程加速编译
要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下
4、使用Tree-shaking和Scope Hoisting来剔除多余代码
5、使用fast-sass-loader代替sass-loader
6、babel-loader开启缓存
babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率 可以加上cacheDirectory参数或使用 transform-runtime 插件试试
不需要打包编译的插件库换成全局"script"标签引入的方式
8、优化构建时的搜索路径
在webpack打包时,会有各种各样的路径要去查询搜索,我们可以加上一些配置,让它搜索地更快
比如说,方便改成绝对路径的模块路径就改一下,以纯模块名来引入的可以加上一些目录路径
还可以善于用下resolve alias别名 这个字段来配置
还有exclude等的配置,避免多余查找的文件,比如使用babel别忘了剔除不需要遍历的
webpack的缺点
webpack的缺点是只能用于采用模块化开发的项目
什么样的前端代码是好的?
高复用低耦合,这样文件小,好维护,而且好扩展
你的职业生涯规划是什么?
最保险的回答应该先说明你要发展或进取的专业方向,并表明你脚踏实地的工作态度。“我的职业规划是勇于进取,所做的事情必须是能够将我的全部精力与专业知识融入到我所从事的工作中去,首先我会选择进入到一个公司的某个职位,接着通过这个职位不断学习和锻炼自己,并通过努力争取给公司带来更大的利润价值,然后希望在今后几年中,成为一名内行的专业人士,很清楚地理解自己的行业、公司、及最大的挑战以及机会之所在。到那时,我想我未来的发展目标便会清晰地显露出来。”类似于这样的应答会使你远远地高于你的同龄人。
你对加班的看法
如果是工作需要我会义不容辞加班,我现在单身,没有任何家庭负担,可以全身心的投入工作。但同时,我也会提高工作效率,减少不必要的加班。