1.对象方法
2.新建对象时,new操作符干了什么?var a = new A;
3.bem,bfc
4.永久性重定向(301)和临时性重定向(302)对 SEO 有什么影响?
5.一个div,左边固定,右边、自适应,有几种方法?
6.清除浮动
7.div水平垂直居中
8.VUE双向绑定原理,对MVVM的理解
9.diff算法时间复杂度及原理
10.webpack打包时如何优化减少打包时间?webpack loader和plugin有什么区别?
11.尾递归优化,尾调用优化?
12.遇到过哪些兼容性问题?
13.深度优先遍历
14.嵌套数组展开
15.跨域
16.文本溢出显示省略号,一行或多行的情况分别处理
17.Git命令,从指定分支新建分支。
18.找出数组中重复次数最多的元素
19.Linux命令,打印执行过的命令
20.proxy
21.将数字反转,63->36
1.对象方法
答:
- Object.defineProperty() 修改对象属性的默认特性,创建新属性
- Object.defineProperties() 多个
- Object.getOwnPropertyDescriptor() 取得给定属性的描述符
- instanseOf()检测对象类型
- a.isPrototypeOf(b) a是否是b的原型
- Object.getPrototypeOf(a) 找到a的原型
- hasOwnProperty()返回实例属性
- in 操作符 存在原型链上的属性
- hasPrototypeProperty() 返回原型属性
- Object.keys()返回实例上的可枚举属性
- Object.getOwnPropertyNames()返回实例上的所有属性,无论是否可枚举
2.新建对象时,new操作符干了什么?var a = new A;
答:这种方式调用构造函数,实际经历了以下4个步骤:
(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象;(因此this就指向了新对象)
(3)执行构造函数中的代码;(为这个新对象添加属性)
(4)返回新对象。
- bem,bfc
瓜子二手车、微店
答:原文链接:https://juejin.im/post/5909db2fda2f60005d2093db
BFC(Block Formatting Context)翻译为块级格式化上下文,它其实就是一个css布局的概念,是一个上下文环境, 是一块区域,是一个隔离的独立容器,容器里的子元素不会影响到外面的元素, 反之亦然。
formatting context 是一个决定如何渲染的容器。
-
BFC布局规则:
(1)内部的box会在垂直方向一个接一个的放置。
(2)box之间垂直间距由margin决定,属于同一个BFC的两个相邻的box的margin会重叠。
(3)每个元素的marginbox的左边与包含块borderbox的左边相接触,即使存在浮动也如此。???
(4)BFC的区域不会与floatbox重叠。
(5)BFC就是页面上的一个独立区域,区域里面的子元素布局不会影响到外面的布局排列,反之亦然。
(6)计算BFC高度时,浮动元素也参与计算。
(7)位于不同BFC下的元素不会发生margin重叠。 -
BFC有哪些用途?
(1)自适应两栏布局
(2)可以阻止元素被浮动元素覆盖,把不浮动的元素添加overflow:hidden ,触发该元素的bfc,让自己免受外界影响。
(3)可以清除内部浮动(清除浮动的原理是两个div都位于同一个浮动的BFC区域之中。)
(4)分属于不同的BFC 可以阻止margin重叠。
(5)解决浮动问题。给父元素加overflow:hidden触发bfc,形成一个独立的渲染区域,所以内部的元素不会影响外面的布局,bfc把浮动子元素的高度算作自己的高度处理溢出,所以外界不会受到影响。 -
触发BFC有哪些方式?
(1)根元素HTML
(2)float不为none
(3)display为inline-block或table-cell
(4)overflow不为visible
(5)position不为static
(6)flex-boxes
概括来说就是脱离了文档流的元素 -
文本环绕?
image.png
image.png
div会被float覆盖而文本不会,这是因为float当初设计的时候就是为了让文本在浮动对象周围。
BEM( Block,Element和Modifier的缩写)是一个高可用的,强大的,而且简单的命名规范,它可以使得你的前端代码更加易读和理解,容易与他人协作,容易扩展,更加强壮和明确,关键是更加严谨
- 永久性重定向(301)和临时性重定向(302)对 SEO 有什么影响?
github 124
答:从SEO角度出发,301优于302。
- 301:(Permanently Moved),从搜索引擎优化角度来讲, 301是转移网址最好的办法,因为当网站的域名改变后,搜索引擎只对新网址进行搜索,旧网址下的所有外部链接全部转移到新网址下, 旧网址排名清零作废,从而不会让网站的排名受到影响。另外,使用301命令让多个域名指向网站主域时,也不会对网站的排名产生负面影响。
- 302:(Temporarily Moved ),使用302重定向时, 绝大部分浏览器会把链接成绩向多个域名分摊,因此就会削弱网站主站的链接总量,作为网站排名的关键因素之一的外链数量受到影响,网站排名自然会降低。目前为止, 只有谷歌对302的这个行为进行了优化,当其他域名指向主域时,会把其他域名的链接成绩计入主域。
5.一个div,左边固定,右边、自适应,有几种方法?
博彦科技
bfc、左边position:absolute,右边margin-left、flex、计算属性、table
(1)bfc方法(最优,左边菜单拖拽的情况下,可以监听左边元素的宽度,右边什么值都不用改)
<div class="aside"></div>
<div class="text">
<div class="main">aaaaa</div>
</div>
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
overflow: hidden;
background: #fcc;
}
.text {
width: 100%;
}
注意:是右边部分的父元素宽度100%,让main自己形成一个bfc,bfc的区域不会与float-box重叠。
image.png
(2)左边position:absolute,右边margin-left,这个方式和让左边float-left同理。
<div class="parent">
<div class="l-child">左边固定1 左边固定2 左边固定3</div>
<div class="r-child">右边自适应1 右边自适应2 右边自适应3</div>
</div>
.parent {
display: relative;
background: #ddd
}
.l-child {
position: absolute;
width: 100px;
background: #bbb
}
.r-child {
margin-left: 100px;
background: #999
}
image.png
(3)flex
body{
display: flex;
}
.right{
flex:1
}
(4)table布局
body{
display: table;
width:100%;
}
.left{
display: table-cell;
}
.right{
display: table-cell;
}
6.清除浮动
大搜车、微店、
https://juejin.im/post/59e7190bf265da4307025d91
答:clear、父元素前加空标签做clear、在parent上加一个伪类,让这个伪类清除浮动、浮动元素的父元素增加overflow不为visible的属性(BFC)。
(1)在被float影响的元素上添加clear:both;
如下图,浮动元素导致text元素和下面的other被遮挡。父元素高度撑不开。
image.png
解决办法:
image.png
不过这种办法也有漏洞,假如浮动元素在text后面,父元素高度依然撑不开,other依然会被影响。
(2)父元素结束标签之前插入清除浮动的块级元素
原理同上。
image.png
(3)在parent上加一个伪元素,让这个伪元素清除浮动,原理和上面两种相同。
image.png
(4)浮动元素的父元素增加overflow不为visible的属性,原理是,这样会触发BFC,而BFC高度包含浮动元素。
image.png
7.div水平垂直居中
作业帮、大搜车、
答:
- 未知父元素,未知子元素宽高
(1) flex
.parent {
display: flex;
justify-content: center;
align-items: center;
}
(2)table cell
子元素设置为inline或inline-block时,父元素display:table-cell
.parent {
border: 1px solid black;
display: table-cell;
width: 500px;
height: 500px;
vertical-align: middle;
text-align: center;
}
.child {
width: 100px;
height: 100px;
border: 1px solid red;
display: inline-block;
}
(3)绝对定位+子元素transform:translate(-50%,-50%);
.parent {
border: 1px solid black;
width: 500px;
height: 500px;
position: relative;
}
.child {
width: 100px;
height: 100px;
border: 1px solid red;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
- 已知子元素宽高,未知父元素宽高
(1)子元素绝对定位,top和left都设为50%,然后margin-top和margin-left设为负数自身的一半。
.parent {
width: 500px;
height: 500px;
border: 1px solid black;
position: relative;
}
.child {
height: 100px;
width: 100px;
border: 1px solid red;
position: absolute;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px;
}
(2)子元素绝对定位,top,bottom,right,left值均为0,margin设为auto。
.parent {
border: 1px solid black;
position: relative;
}
.child {
width: 100px;
height: 100px;
border: 1px solid red;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
}
8.VUE双向绑定原理,对MVVM的理解
酷家乐,博彦科技
答:VUE双向绑定是通过Object.defineProperty的数据劫持能力,结合发布者订阅者模式实现的。
vue中的data实际上是一个带有访问器属性(getter和setter)的对象。
什么是访问器属性?
JS对象有两种属性:数据属性和访问器属性,访问器属性不能直接定义,必须通过Object.defineProperty()来定义,它包含一对getter,setter函数,在读取访问器属性时,会调用getter,在写入访问器属性时,会调用setter 并传入新值。setter这个函数负责如何处理数据。
VUE 就是通过这个Object.defineProperty来实现数据劫持的。
VUE 的双向绑定包括两个方面,view更新data,data更新view。
view更新data比较简单,通过事件监听即可,比如input标签绑定input事件。
比较困难的是data更新view。
这里面有两个点:
1.如何知道数据变了?
2.数据变了如何更新DOM?
对以上两点做出一些解答:
1.如何知道数据变了?
其实上面已经给出答案了,就是通过Object.defineProperty()对属性设置一个set函数,数据改变时就会触发这个函数,我们将一些更新view的方法放在set函数的逻辑里,就可以实现data更新view了。
image.png
实现过程
(1)实现数据的双向绑定,首先要对数据进行劫持监听,所以第一步需要设置一个监听器Observer,用来监听所有属性。
(2)如果属性发生变化了,就要告诉订阅者watcher看是否需要更新。
(3)因为订阅者watcher有很多个,所以需要一个消息订阅器Dep来专门收集这些订阅者,在监听器Observer和订阅器Watcher之间进行统一管理。
(4)接着,为了解析view上的指令, 我们需要一个指令解析器Compiler,对页面每个节点和元素进行扫描和解析,将相关指令初始化成一个订阅者watcher。通过解析指令绑定相应的函数。
(5)此时,当watcher收到来自Observer的通知,就会执行对应的更新view的函数。
如果要自己实现一个双向绑定也就大致需要以下三个步骤:
1.实现一个监听器Observer,用来劫持监听所有的属性,有变动就通知watcher。
2.实现一个watcher,可以收到监听器传来的属性变化通知,并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描解析每个节点的指令,并初始化末班数据和初始化订阅器。
以下详细思考每个步骤如何实现?
1.实现Observer
Observer是一个数据监听器,其实现的核心方法就是前文所说的Object.defineProperty(),如果要对所有的属性都进行监听的话,可以用递归的方法遍历所有属性值,对其进行Object.defineProperty处理。
image.png还需要创建一个容纳所有Watcher的订阅器Dep,订阅器主要负责收集订阅者,然后属性变化的时候,执行对应订阅者的更新函数,所以显然订阅者需要有一个容器,这个容器就是list,将上面的代码稍微改造下,植入Dep。
image.png
在get里面添加一个订阅器是为了初始化触发,所以初始化时要判断是否需要添加watcher,这个要具体情况具体考虑。
接下来实现watcher.
2.实现监听器watcher
9.diff 算法时间复杂度及原理
大搜车、作业帮
https://user-gold-cdn.xitu.io/2019/8/1/16c49afec13e0416
10.webpack打包时如何优化减少打包时间?webpack loader和plugin有什么区别?
北明软件、瓜子二手车、博彦科技、滴滴
11.尾递归优化,尾调用优化?
https://www.jianshu.com/p/0ed8ed003fe0
12.遇到过哪些兼容性问题?
答:
- js
(1)DOM2级定义的深度优先遍历器NodeIterator 和 TreeWalker在IE中没有对应的类型和方法,所以使用遍历的跨浏览器解决方案非常少见。 - css
13.深度优先遍历
- 递归
function deepTraversal(node,nodeList) {
if (node) {
nodeList.push(node);
var children = node.children;
for (var i = 0; i < children.length; i++)
deepTraversal(children[i],nodeList);
}
return nodeList;
}
var root = document.getElementById('root')
console.log(deepTraversal(root,nodeList=[]))
- 非递归
function deepTraversal(node) {
var nodeList = [];
if (node) {
var stack = [];
stack.push(node);
while (stack.length != 0) {
var childrenItem = stack.pop();
nodeList.push(childrenItem);
var childrenList = childrenItem.children;
for (var i = childrenList.length - 1; i >= 0; i--)
stack.push(childrenList[i]);
}
}
return nodeList;
}
var root = document.getElementById('root')
console.log(deepTraversal(root))
- 嵌套数组展开
- 递归
function flattenMd(arr) {
var result = [];
for(var i = 0; i < arr.length; i++){
if(arr[i] instanceof Array) {
result = result.concat(flattenMd(arr[i]));
}
else {
result.push(arr[i]);
}
}
return result;
}
var arr=[1, [2, 3, [4, 5], 6], 7, 8]
console.log(flattenMd(arr));
- 非递归
function flattenDeep(arr){
const res = [];
const stack = [...arr];
while(stack.length){
let item = stack.shift();
Array.isArray(item)?stack.unshift(...item):res.push(item);
}
return res;
}
var arr = [1,[2,[3,[[5]]],[4]]];
console.log(flattenDeep(arr))
15.跨域解决办法?同源策略是什么?
博彦科技,大搜车,酷家乐,滴滴,贝壳
答: 通过XHR实现ajax的一个主要限制就来源于跨域安全策略。
默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源。
以下简要说明常用方法:
- CORS
- IE和其他浏览器对CORS的实现
- Preflighted Request
- withCredentials 带凭据的请求
- 跨浏览器的CORS
CORS(Cross-Origin Resource Sharing)
CORS背后的思想是,使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应应该是成功还是失败。
CORS的使用方法:
在发送请求时,需要给它附加一个额外的Origin头部,其中包含请求页面的信息(协议,域名,端口),以便服务器根据这个信息决定是否给予响应。
Origin: http://www.nczonline.net
如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部中回发相同的源信息。
Access-Control-Allow-Origin:http://www.nczonline.net
如果没有这个头部,或者有这个头部但是源信息不匹配,浏览器就会驳回请求,正常情况下,浏览器会处理请求。
请求和响应都不包含cookie信息。
IE对CORS 的实现:
微软在IE8中引入了XDR(XDomainRequest)类型,与XHR相似,但是能实现跨域通信。
XDR使用方法和XHR类似,
(1)创建一个XDomainRequest对象
(2)open() //与XHR不同的是XDR只接受两个参数,请求类型和URL
(3)send()
缺点:
(1)所有的XDR都是异步的,不能用来创建同步请求。
(2)收到响应后,只能访问响应的原始文本,没有办法确定响应的状态码。成功触发onload,响应数组放在xhr.responseText中,失败触发onerror,但是除了错误本身之外,没有其他信息可以用。
XDR也支持
onerror()检测错误
abort()在请求返回前终止请求
timeout属性 超时设定
ontimeout()事件处理程序 超时处理程序
其他浏览器对CORS的实现
Firefox3.5+,Sarafi4+,Chrome,ios版Safari和Android平台中的webkit都通过XHR对象实现了对CORS的原生支持。
使用方法:
要请求另一个域中的资源,使用标准的XHR对象,并在open()方法中传入绝对的URL即可。
对比IE中XDR的优点:
(1)XHR可以访问status和statusText属性
(2)可以发送同步请求
但是出于安全考虑也有一些限制:
(1)不能使用setRequestHeader自定义头部信息。
(2)不能发送接收cookie
(3)调用getAllResponseHeaders()总是返回空字符串。
因为同源请求和跨域请求使用相同的接口,所以建议本地资源使用相对URL,远程资源使用绝对URL,这样能消除歧义,避免出现 限制访问头部或本地cookie信息等问题。
Preflighted Request
支持Preflight请求的浏览器有Firefox3.5+,Safari4+,Chrome
CORS 通过Preflighted Request的透明服务器验证机制支持开发人员使用自定义的GET或POST之外的方法,以及不同类型的主题内容。浏览器向服务器通过高级选项发送一个Preflight请求,服务器可以决定是否允许这种类型的请求。
withCredentials 带凭据的请求
支持withCredentials的浏览器有Firefox3.5+,Safari4+,Chrome,IE10及更早版本都不支持。
默认情况下,跨源请求不提供凭据,(cookie,HTTP认证及客户端SSL等),
通过将withCredentials设置为true,可以指定某个请求应该发送凭证。如果服务器接收带凭据的请求,会用下面的HTTP头部来响应。
Access-Control-Allow-Credentials: true
16.文本溢出显示省略号,一行或多行的情况?
答:
- 一行:
overflow: hidden;
text-overflow: ellipsis;
white-space:nowrap;
}
- 多行
.a {
display: inline-block;
width: 200px;
height: 200px;
overflow: hidden;
position: relative;
}
.a::after {
content: '...';
position: absolute;
right: 0;
bottom: 0;
}
17.Git命令,从指定分支新建分支。
git branch [branch name] [from branch name ]
18.找出数组中重复次数最多的元素
答:
var arr = [1];
var res = {};
var most = -1;
var ele = -1;
function findMost(arr) {
if (!arr.length) {
return
} else if (arr.length == 1) {
return arr[0];
} else if (arr.length > 1) {
for (let i = 0; i < arr.length; i++) {
res[arr[i]] ? res[arr[i]]++ : res[arr[i]] = 1;
if (res[arr[i]] > most) {
most = res[arr[i]];
ele = arr[i];
}
}
}
console.log(ele);
}
findMost(arr);
19.Linux命令,打印执行过的命令
history [n] //n是数字,要打印的条数
20.proxy
VUE3.0的双向数据绑定
proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对 编程语言进行编程。
Proxy可以理解成在目标对象前架设一个拦截层,外界对该对象的访问必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。Proxy这个词的愿意是代理,用在这里表示由他来”代理“某些操作,可以译为代理器。
21.将数字反转
答:
function reverseNum(n){
console.log(n.toString().split("").reverse().join("")) | 0;
}
reverseNum(123);
网友评论