瓜子二手车 前端工程师面试题
Vue生命周期
Vue何时构建真实dom
Vue的Render函数生成虚拟dom,然后会通过dom diff,生成真实dom
这个步骤是patch方法实现的,也就是在mounted之前或者updated之前完成的
我认为面试官说是在beforeMount完成的是错误的
CSS选择器优先级
- !important优先级最高,无法被覆盖
- 内联样式的优先级是1000,
- ID选择器的优先级是0100
- class选择器(伪类选择器、属性选择器)的优先级是0010
- 标签选择器(伪对象选择器)的优先级是0001
- 通配符
- inherit
- 浏览器定义
下面test的文字的颜色是:
<style>
#outer {
color: blue;
}
.inner{
color: yellow;
}
</style>
<div class="outer" id="outer">
<div class="inner">test</div>
</div>
注意blue颜色是继承而来,优先级是低于yellow的类选择器的
CSS属性选择器
- [attr]:选取带有指定属性attr的元素
- [attr=value]:选取带有指定属性,并且属性值唯一等于value的元素
- [attr~=value]:选取带有指定属性,并且属性值包含value的元素
<div class="a b c">123</div>
<div class="d b c">123</div>
想要利用属性选择器选择同时包含类a和类b的元素:
div[class~=b][class~=a]{
background: red;
}
不用属性选择器:
.a.b{
background: forestgreen;
}
原理:没有空格时是对一个元素的多重约束,有空格是对子元素的约束
当时我回答错了,不能使用[attr=value1 value2]的形式选择同时包含两个属性值的元素,面试官竟然也不清楚,不清楚你别问啊
HTTP常用状态码
1xx : 这些状态代码表示临时的响应。客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应。
- 100 - 继续。
- 101 - 切换协议。
2xx : 成功,这类状态代码表明服务器成功地接受了客户端请求。
- 200 - 确定。客户端请求已成功 ,请求所希望的响应头或数据体将随此响应返回。
- 201 - 表示请求成功并且服务器创建了新的资源,且其 URI 已经随Location 头信息返回。
- 202 - 服务器已接受请求,但尚未处理。
3xx : 重定向,后续的请求地址(重定向目标)在本次响应的 Location 域中指明。
- 301 - 被请求的资源已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
- 302 - 请求的资源临时从不同的URI响应请求,但请求者应继续使用原有位置来进行以后的请求
- 304 - 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
4xx : 客户端错误,发生错误,客户端似乎有问题。例如,客户端请求不存在的页面,客户端未提供有效的身份验证信息。
- 401 - 访问被拒绝,请求要求身份验证。
- 403 - 服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。
- 404 - 请求失败,请求所希望得到的资源未被在服务器上发现。
- 405 - 用来访问本页面的 HTTP 动作不被允许(方法不被允许)
5xx : 服务器错误 ,服务器由于遇到错误而不能完成该请求。
- 500 - 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。
- 503 - 由于临时的服务器维护或者过载,服务器当前无法处理请求。通常,这个是暂时状态,一段时间会恢复。
tap事件点透的解决方法
- 使用fastclick库
- 使用click代替tap事件
- 使用touchend代替tap事件,在touchend结束前组织默认行为e.preventDefault()
- 延时消失上层元素
- 在下层元素上使用CSS3的属性pointer-events: none
图片lazyload的具体细节
- HTML中需要lazyload的图片不填写真实src,而是用展位图代替
- 站位图尺寸最好与真实图片相同
- 监听scroll事件
- 监听时考虑应用函数节流
- 移动端的X水平方向也需要监听
- 判断图片是否出现在屏幕中,如果是则将src替换为data-original中的真实的地址
img[i].offset().top < parseInt($(window).height()) + parseInt($(window).scrollTop())
关于动态规划和最大子序列
不理解,以后再说吧
Vue双向绑定如何实现
可以这样理解双向绑定:双向数据绑定就是在单向绑定的基础上给可数元素(input、textarea)等添加了change事件,来动态修改model和view。
实现数据绑定的做法大概有如下几种:
1、发布者-订阅者模式(backbone.js)
我们可以使用自定义的data属性在HTML代码中指明绑定。所有绑定起来的JavaScript对象以及DOM元素都将“订阅”一个发布者对象。任何时候如果JavaScript对象或者一个HTML输入字段被侦测到发生了变化,我们将代理事件到发布者-订阅者模式,这会反过来将变化广播并传播到所有绑定的对象和元素。
监听事件使用了message事件。
详细细节的可以参考这篇文章。
2、脏值检查(angular.js)
angular.js是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过setInterval()定时轮询检测数据变动
angular.js只有在指定的事件触发时进入脏值检测,大致如下:
- DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
- XHR响应事件 ( $http )
- 浏览器Location变更事件 ( $location )
- Timer事件( timeout,interval )
- 执行 digest()或apply()
3、数据劫持(vue.js)
vue.js则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
细节可以参考 https://www.cnblogs.com/kidney/p/6052935.html?utm_source=gold_browser_extension
ES6新增基本数据类型
Symbol是ES6中引入的原始数据类型,表示独一无二的值。
call/apply/bind的区别
call和apply都是为了改变函数运行时的上下文(也就是为了改变函数内部this的指向)
可以用来令一个类型数据获得或使用另一种数据类型的方法
// 获取最大值
Math.max.apply(null, [1,3,5]);
// 让类数组拥有数组的方法(比如arguments对象)
Array.prototype.slice.call(arguments)
[].slice.call(arguments)
bind也是为了改变函数体内this的指向,bind会创建一个新的函数(绑定函数),bind()方法的第一个参数会作为新函数的this,后面的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数调用原函数
bind和apply、call的最大区别是,它返回的是一个函数,不会立即被调用,而另外两个会立即调用
对象拷贝
- Object.assing():第一层是深拷贝,后续是浅拷贝
- JSON.stringify:不能拷贝方法
- 递归 + for…in:真正意义的深拷贝
- 赋值:浅拷贝
如何将伪数组转换为数组
伪数组实际上是一个对象,键名是由0开始的正整数,具有length属性:
let fakeArray = {
0: 100,
1: 200,
length: 2
};
最典型的就是函数的arguments对象
function test(a, b) {
console.log(arguments)
}
test(1, 2)
(())
伪数组对象不具备数组的方法,比如slice等
将伪数组转换为数组,可以利用遍历实现
for (let key in arguments) {
if (key !== 'length') {
realArray.push(arguments[key])
}
}
更简单的方法是使用Array.prototype.slice.call,使伪数组对象调用slice方法:
let realArray = Array.prototype.slice.call(arguments);
也可以写为:
let realArray =[].slice.call(arguments);
在理论上第一种写法速度更快,但是网上有资料说,由于浏览器的优化,第二种速度回更快一些。
也可以使用ES6新增的数组方法Array.from,它可以将类数组对象(例如arguments对象)和科比那里的对下四姑娘(比如Set对象和Map对象)转换为真正的数组
let realArray =Array.from(arguments);
Array.from如果作用于真正的数组,会深拷贝(一层)原数组
$.extend()的实现原理
当时懵了,其实$.extend()就是实现了递归拷贝
自适应正方形
- CSS3 vw 单位,但是浏览器兼容性不好
- 设置垂直方向padding,当内部填充内容时设置height:0,但是会导致max-height无效
- 利用伪元素撑开高度,伪元素的padding-top:100%即可,此时父元素的max-height有效
.box{
width:30%;
}
.box:after{
content:'';
display: block;
padding-top:100%;//相对于box的宽度的
}
实现左侧定宽右侧自适应的两列布局
首先要明确一点:块级元素默认宽度是撑满父容器的==
- flex布局
- display:inline-block + calc属性,这种方法要注意,在display:inline-block后,两个div之间的空格会在布局中产生间隙,所以要令父元素的font-size:0,消除这个间隙
- float + margin-left
- 绝对定位 + margin-left
- float:left + float:right + 负的margin-right + 正的子元素的margin-left,这种方法比较复杂,令左侧向左浮动同时,给负的右边距,右侧向右浮动,宽度100%,子元素给正的左边距
- grid布局
组合继承
组合继承值得就是利用call或者apply实现方法内部的属性继承,同时给子类的原型赋值为父构造函数的实例
所谓的寄生组合继承,就是声明一个空函数,令空函数的prototype等于父函数的prototype,令子类的prototype赋值为空函数的实例,节省一个实例的内存,同时避免子类的原型污染父类的原型
SSR
SSR指的是服务端渲染? – Sever Side Render
可以参考Vue的教程
可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记”混合”为客户端上完全交互的应用程序。
使用SSR的好处有:
更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
- 更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记,所以你的用户将会更快速地看到完整渲染的页面。通常可以产生更好的用户体验,并且对于那些「内容到达时间(time-to-content)与转化率直接相关」的应用程序而言,服务器端渲染(SSR)至关重要。