前端面试题整理(一)

2019-07-23  本文已影响0人  宋乐怡

1.父元素伸缩,自元素自适应,10像素间距
2.选择器优先级
3.浏览器对用户呈现出一个页面的过程
4.prevent default
5.事件的属性和方法
6.this指向
7.es5实现继承
8.prototype和构造函数调用关系
9.promise并行三个,将结果存入数组,滑动窗口
10.eventloop对set timeout和promise的处理
11.vue 样式模块化
12.怎样区分伪类和伪元素
13.web存储方式
14.简述instanceOf为什么不是绝对安全?
15.String对象的方法
16.实现千位分隔符 1234567->1,234,567
17.写出3个以上能改变DOM的js native函数
18.call和apply的区别
19.浏览器实现js多线程,提供原生对象是?
20.快速排序
21.二分查找
22.实现布局,子元素宽占父元素的50%,高和宽相等,自适应。
23.keep-alive原理 TCP原理,VUE<keep-alive>组件原理
24.vue tab页跳转时, 保存之前的滚动位置
25.window load event和document DOMContentLoaded event的区别
26.给定两个排序好的数组a,b,长度分别为n,m,给出一个高效算法,查找A中的哪些元素存在于B中。
27.实现一个函数,入参是一个字符串,判断是否有重复字母,如果包含,返回第一个重复字母的下标,不包含返回-1。
28.对象数组a=[{x:7,y:6} , {x:1,y:2} , {x:3,y:4}],按照x的大小进行排序。
瓜子二手车
29.阶乘函数
30.call() apply()和bind()的区别?
31.实现tooltip, css画钝角三角形
32.判断一个对象是函数的几种方法。
33.实现商品列表,一行3个,屏幕宽度不定,商品元素间距50px,距离父元素边距50px。
34.向一个数组增加元素的方法
35.盒子模型有哪几种, width100padding10的盒子, 占据宽度是多少?


1.父元素伸缩,子元素自适应,10像素间距

答:https://www.jianshu.com/p/19538a0ffb8c

2.选择器优先级

答:
内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器,!important 的属性拥有最高优先级

html

3.浏览器对用户呈现出一个页面的过程

答:dns解析-》tcp链接-》发送HTTP请求-》服务器处理请求并且返回报文-》浏览器解析渲染页面-》链接结束

DNS解析:

是一个将网址解析成IP 地址的过程。
首先从本地域名服务器中查找,如果找不到就继续向上根域名服务器查找,直到顶级域名,这个过程中存在dns优化有的环节。当查找资源时, 会先找缓存,(浏览器缓存-》系统缓存-》路由器缓存等等),也会根据机器的负载量和距离用户的位置进行dns负载均衡。


image.png
建立TCP连接:

A.客户端发送syn到服务器要求连接
B.服务端向客户端发送ack
C.客户端收到ack并确认后,向服务端发送ack,连连接建立。

发送HTTP请求:

tcp连接建立之后,开始通过HTTP协议传输资源,根据情况判断是否使用HTTPS,HTTP包括请求行,请求报头,请求正文(post,put客户端向服务器传输数据的情况)。keepalive什么的可以在请求头里添加。

服务器处理请求并返回HTTP报文:

服务端接到请求开始对tcp进行处理,对http进行解析,按照报文格式封装成HTTP request对象。响应报文码(1xx:请求已接受,2XX:成功,3xx:重定向,4xx:客户端错误,5xx:服务端错误)

浏览器渲染页面:

边解析边渲染,解析html,构建dom树,解析css,构建cssom。
如果dom构建的过程中遇到了css的link,那就会先去加载并构建cssom,这个过程不是一次性的。css和同步的js文件都是阻塞DOM树渲染的,但不阻塞DOM解析,直到js加载并且执行完毕。遇到阻塞的css也会延迟js的执行和dom构建。(因为js可能会修改dom或者cssom),css同样,当cssom构建时,js也会停止被阻塞,等待cssom构建完成。
CSS阻塞吗?
1.CSS会阻塞DOM的渲染,不会阻塞DOM树的解析。
2.CSS会阻塞js的执行。

defer & async
1.正常模式
<script src="script.js"></script>
遇到这样的js标签,浏览器会立即加载并执行,不等待后续载入的文档元素。

2.async模式
<script async src="script.js"></script>
有async的js文件会和后续的DOM解析渲染并行执行,当js加载完成,立即执行,这时html解析暂停。因此不会按照标签引入顺序执行。

3.defer模式
<script defer src="script.js"></script>
有defer的js文件的加载,也会和文档的解析构建并行。这一点与async一致。
不同的是,defer的js文件加载完不会立即执行, 会等到所有文档解析完成后,DOMContentLoaded事件触发之前完成, 因此会按照引入顺序执行。

DOMContentLoaded & onload
DOM解析完(阻塞DOM的内容解析完,DOM才真正解析完)会触发DOMContentLoaded事件。如果在DOMContentLoaded之后引入css样式表,DOMContentLoaded可能无法获取样式表里的样式,此时DOM树已经构建完成,但外部css文件还没加载完成,这也是css文件放在头部的原因

onLoad
页面的所有资源被加载以后触发onLoad事件,会在DOMContentLoaded之后触发。

这个过程中有两个重要的过成是回流和重绘。计算盒模型的大小位置还有解析颜色字体等 属性,这些都确定下来的时候开始repain,合成一个rendertree渲染树,render-tree中必须同时存在dom和cssom,浏览器开始布局并渲染到屏幕上。首次加载必然会经历回流和重绘的过程。

重排(回流)和重绘

// DOM重构,浏览器重排重绘

无论何时总会有一个初始化的页面布局伴随着一次绘制。(除非你希望你的页面是空白的:))之后,每一次改变用于构建渲染树的信息都会导致以下至少一个的行为:

部分渲染树(或者整个渲染树)需要重新分析并且节点尺寸需要重新计算。这被称为重排。注意这里至少会有一次重排-初始化页面布局。

由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新。这样的更新被称为重绘。

重排和重绘代价是高昂的,它们会破坏用户体验,并且让UI展示非常迟缓。

什么情况会触发重排或重绘?

一些重排可能开销更大。想象一下渲染树,如果你直接改变body下的一个子节点,可能并不会对其它节点造成影响。但是当你给一个当前页面顶级的div添加动画或者改变它的大小,就会推动整个页面改变-听起来代价就十分高昂。

每次重排重绘浏览器都会立即执行吗?

浏览器一直致力于减少这些消极的影响,浏览器会创建一个变化的队列,浏览器可以向队列添加或变更这些变化,在一个特定的时间或达到一定的数量时,执行一次重排或重绘,通过这种方式,多次重排或重绘会整合起来最终减少重排或重绘的次数,以节省浏览器渲染的开销。

所以 ,同时set和get样式是非常糟糕的做法

// no-no!
el.style.left = el.offsetLeft + 10 + "px";
如何减少重排重绘呢?
一个问题,为什么会遇到浏览器展示页面开始没有样式,过一会样式才可用的情况?

看到的一个答案,有可能是这个原因,但是我不确定。
开发环境会把css都打包到js里,所以要等js加载好了才有样式,因此会出现这种情况;但是在生产环境下,css会生成css文件,并插入到<style />里,因此就不会出现这种情况了。

两个优化点:css先加载,js后加载
js尽量不要修改dom树。

js

4.prevent default

答:取消事件的默认行为,cancelable为true可以使用这个方法。

5.事件的属性和方法

答:type/target/currentTarget/cancancelable/bubbles/defaultPrevented/detail/eventPhace/trusted/view
preventDefault()/stopPropagation()/stopImmediatePropagation()

6.this指向

答:在运行时基于函数的执行环境绑定的,
在事件中,this始终指向currentTarget,
执行环境的层层嵌套形成了作用域链,在作用域链中访问变量只能自底向上搜索。

7.es5实现继承
答:

构造函数,原型,实例之间的关系?

每个构造函数都有一个原型对象,每个原型对象都有一个指向构造函数的指针,每个实例有一个指向原型的指针。继承本质上是重写原型对象,将原型代之以另一个类型的实例。

A.父类构造函数

function SuperType(name){
this.name = name;
this.numbers = [1,2,3,4];
}

B.父类原型添加原型方法

SuperType.prototype.superFunction = function() {
alert (this.name);
}

C.子类构造函数,在构造函数中用call调用父类构造函数,并且定义子类的构造 函数属性

function SubType(name,age){
SuperType.call(this,' nick');
this.age = age;
}

D.改写子类原型对象,使之指向父类的实例,创建链条。

SubType.prototype = new SuperType();

E.子类的构造函数自己定义,断开与父类构造函数的关系

SubType.prototype.constructor = SubType();

F.子类定义自己的原型方法

SubType.prototype.subFunction = function(){
alert (this.age);
}

G.创建子类实例

var instance = new SubType('anne','10');

8.prototype和构造函数调用关系

答:每个构造函数都有一个原型对象,每个原型对象都有一个指向构造函数的指针,每个实例有一个指向原型的指针。继承本质上是重写原型对象,将原型代之以另一个类型的实例。

9.promise并行三个,将结果存入数组,滑动窗口

Promise.all() 并行且按照参数传入顺序输出
/////
var promiseArr = [p1,p2,p3,p4,p5,p6,p7,p8];
var resultArr = [];
for(let i = 0; i < promiseArr.length; i++){
let tempArr = [promiseArr[i * 3] , promiseArr[i * 3+1] , promiseArr[i*3+2]];
resultArr.push(promise.all(tempArr))
}

10.eventloop对set timeout和promise的处理

js是单线程语言,他作为浏览器脚本语言,与用户互动, 以及操作dom,这决定了它只能是单线程语言,否则会有非常麻烦的同步问题。

H5提出了WebWorker标准。允许js脚本创建多个线程。但是子线程完全受主线程控制。且不得操作DOM,所以这个标准并没有改变js单线程的本质。

js执行过程中, 所有的任务分为两种,同步任务和异步任务,同步任务在主线程上形成一个执行栈按顺序执行, 遇到异步任务就将这个异步任务添加到任务队列(task queue)中,一旦执行栈中所有的同步任务执行完毕,系统就会去读task queue,拿到执行栈中执行。异步任务的task queue 分为宏任务队列(macrotask)和微任务队列(microtask),不同的异步任务会进入不同的队列,宏任务包括常见的settimeout,setinterval,setImmediate,UI rendering,requestAnimationFrame等,microtask包括promise ,node 的process.nextTick,等。同步任务执行完毕后,js引擎会先去查看microtask queue,若有待执行的微任务就会先执行所有microtask,然后再去执行一个宏,再去执行所有微。
settimeout会被放进宏任务队列(macrotask队列)一次取出一个执行
Promise会被放进微任务队列(microtask队列)每次循环执行所有microtask。

  1. vue 样式模块化
image.png

12.怎样区分伪类和伪元素

答:针对作用选择器的效果,伪类需要添加类来达到效果,而伪元素需要增加元素,所以一个叫伪类,另外一个叫伪元素。

13.web存储方式
大搜车

答:web存储目的是在设备不能上网的情况下依然可以运行应用。
熟知的有cookie,sessionStorage,localStorage,indexDB。

第一步 离线检测

开发离线应用的第一步是要确定设备在线还是离线。h5为此定义navigator.online属性,但是存在兼容性问题,h5还定义了两个事件,online和offline,网络状态变化时触发。为了检测设备是否离线,在页面加载后,最好先通过navigator.onLine取得初始状态,然后通过online和offline事件来确定网连接状态是否变化。

第二步 HTML5的应用缓存(application cache),(manifest)

appCache是专门为开发离线web应用而设计的。是从浏览器缓存分出来的一块区域,想要在这个缓存中保存数据,可以使用描述文件(manifest file)列出需要缓存和下载的资源。要将描述文件与页面关联起来,可以在<html>中的manifest属性中指定这个文件的路径。例如:
<html manifest="/offline.manifest"></html>
描述文件的扩展名以前是.manifest,现在推荐使用.appcache。
applicationCache对象的status属性可以查看appcache当前的状况。

第三步 数据存储
1. cookie(键值对)

限制

1.cookie是绑定在特定域名下,这个限制确保了存储在cookie中的信息只能让批准的接受者访问,其他域不能访问。

2.每个域的cookie总数是有限的。不同浏览器各有不同,超过单个域名的限制个数后,就会清除以前的cookie。

3.浏览器对cookie的尺寸也有限制。大约都是4kb,如果你尝试创建超过最大尺寸的cookie,会被悄无声息地丢掉。

cookie的构成:
名,值,域,路径,失效时间,安全标志。

Set-Cookie:name=value;domain=.wrox.com;path=/;22-Jan-07 07:10:24 GMT;secure

只有名值对会发送给服务器。所有的名值对都是经过URL编码的,所以必须使用decodeURIComponent()来解码。
server设置cookie,有效时间内, client每次访问相同域名都会携带这个cookie,默认情况下,当浏览器关闭时cookie会被删除,不过也可以自己设置过期时间,因此, cookie可以在浏览器关闭之后依然保存在用户的机器上。为了绕开浏览器单域名下的cookie个数限制, 产生了子cookie,子cookie是存在单个cookie中的更小段的数据。cookieUtil对象操作cookie的存储方法。

2. Web Storage

以window对象的属性存在。包含session storage和local storage。可以使用length属性判断有多少键值对存在于storage中,IE8提供了一个remainingSpace属性,用于获取还可以使用的存储空间的字节数。storage是保存在磁盘上的。

sessionStorage

sessionStorage对象用于存储特定于某个会话的数据,也就是该数据只保存到浏览器关闭, 可以跨越页面刷新存在,如果浏览器支持, 浏览器重启后依然可用。大小大约都是2.5MB。

localStorage

sessionStorage对象主要用于仅针对会话的小段数据的存储,如果需要跨越会话存储数据,localStorage更合适。要访问同一个localStorage对象,页面必须来自同域名(子域名无效)同协议,同端口。数据保留到通过JS删除或者用户主动清除浏览器缓存。大小大约都是5MB。

3. INdexedDB

Indexed Database API简称IndexedDB。是浏览器中保存结构化数据的数据库。大多数操作是以异步请求的方式进行的,差不多每一次IndexedDB操作,都需要你注册onerror或onseccess事件处理程序。

14.简述instanceOf为什么不是绝对安全?
BOM

答:因为在使用框架的情况下,浏览器会存在多个global对象。每个框架中定义的全局变量,会自动成为框架中window对象的属性。由于每个window对象都包含原生类型的构造函数,因此每个框架都有一套自己的构造函数,这个问题会影响到对跨框架传递的对象使用instanceOf操作符。

  1. String对象的方法

答:方法名---返回值---参数

  1. charAt()--给定位置的字符串--一个参数(字符位置)
  2. charCodeAt()--给定位置的字符编码--一个参数(字符位置)
  1. concat()--新--任意多个参数拼接
  2. slice()--新--一或两个参数(开始位置,结束位置后一个)
  3. substring()--新--一或两个参数(开始位置,结束位置后一个)
  4. substr()--新--一或两个参数(开始位置,个数)
  1. indexOf()--index--1或2个参数(str, index)
  2. lastIndexOf()--index--1或2个参数(str,index)从后向前
  1. toLowerCase()--新
  2. toLocaleLowerCase()--新
  3. toUpperCase()--新
  4. toLocaleUpperCase()--新
  1. match()--array--一个参数(正则表达式或RegExp对象)
  2. search()--第一个匹配项的索引--一个参数(正则表达式或RegExp对象)
  3. replace()--新--两个参数(RegExp/str , str/function)
  4. split()--指定分隔符的array(可将string转为数组)--(RegExp/str , number)

16.实现千位分隔符 1234567->1,234,567
彩视

答:

  1. /(?=(\B\d{3})+$)/g
    https://juejin.im/post/5abb5b01f265da237f1e5a92
  2. (123456789).toLocaleString('en-US')(骚操作)

17.写出3个以上能改变DOM的js native函数

独到科技

答:appendChild() / insetBefore() / replaceChild() / removeChild() / createElement()

18.call和apply的区别

答: 这两个函数都是非继承而来的方法,用途是在特定的作用域中调用函数,设置函数体内this对象的值。
apply()
接收2个参数,第一个是函数运行的作用域,第二个是参数数组,其中,第二个参数可以是Array的实例,也可以是arguments对象。
call()
和apply()区别仅仅是接收参数的方式不同,第二个参数必须逐个列出来。

func.apply(this,[num1,num2]);
func.apply(this,arguments);
func.call(this,num1,num2);

19.浏览器实现js多线程,提供原生对象是?

答:js实现多线程的方式有很多种, ajax,异步回调函数,settimeout setinterval,webworker,多线程webworker是h5标准的一部分,worker是window对象的一个方法。
这一套标准定义了一系列api,允许一段js程序运行在主线程之外的另一个线程中,把一些一步操作交给worker线程,在主线程工作时,worker线程在后台运行,互不干扰,等到worker完成后再将结果返回给主线程。
实例化worker对象并传入要执行的js文件名就可以创建一个新的web worker。

var worker = new Worker("stufftodo.js");

这行代码会导致浏览器下载这个js文件,但只有worker收到消息才会执行文件中的代码。要给worker传递消息,可以使用postMessage()方法,消息内容可以是任何能够被序列化的值,可以序列化为JSON结构的任何值都可以作为参数传递给postMessage(),这就意味着传入的值时被复制过去的,不是直接传递过去的。
worker返回的也是任何能够被序列化的值。

worker是通过message和error事件与页面通信的。

Worker全局作用域

关于web worker最重要的是,他所执行的js代码完全在另一个作用域中,与当前网页的代码不共享作用域。worker中的代码不能访问DOM,也不能通过任何形式影响页面的外观。
worker的全局对象是worker本身,web worker本身是一个最小化的运行环境。

webworker存在两个限制:
同源限制:worker运行的脚本必须与主线程脚本文件同源。
访问限制:worker的全局对象和主线程的全局对象不是同一个上下文环境,无法使用document,window,parent等,window改写成self.

20.快速排序
彩视
https://blog.csdn.net/zhao529670074/article/details/80776253

答:
1.选基准,pivot,就选数组最左边元素
2.小于的放pivot左边,大于的放pivot右边
3.递归
时间复杂度为O(nlogn)

var arr=[5,7,2,9,3,8,4,7,1];
// 每次选择最左边的数作为基数
function quickSort(arr){
  if (arr.length<2) { return arr; }
  // 定义左指针
  var left=0;
  // 定义右指针
  var right=arr.length-1;
  //开启每一轮的排序
  while(left<right){
    // 寻找右边比arr[0]小的数的下标
    while(arr[right]>=arr[0] && left<right){
      right=right-1;
    }
    // 寻找左边比arr[0]大的数的下标
    while(arr[left]<=arr[0] && left<right){
      left++;
    }
    //当左边指针与右边指针相遇后,交换arr[0]与当前两个指针所在的元素
    if (right==left) {
      let mid=arr[right];
      arr[right]=arr[0];
      arr[0]=mid;
      break;
    }
    // 当左指针小于右指针的位置,交换两个指针当前位置的元素
    let tem=arr[right];
    arr[right]=arr[left];
    arr[left]=tem;
  }
  //递归实现
  return quickSort(arr.slice(0,left)).concat(arr.slice(left,right+1)).concat(quickSort(arr.slice(right+1)));
}
//对数组进行排序
console.log(quickSort(arr));

21.二分查找
彩视

答:有序查找
1.找到有序数组的中间元素
2.比较key和中间元素的大小,大于去右边找,小于去左边找
3.大于的情况,把边界low设置为中间元素往后一个,小于的情况,把边界high设置为中间元素往前一个。
O(nlogn)

function binarySearch(arr,key){
    var low = 0 , high = arr.length-1;
    while(low <= high){
        let mid = parseInt((low + high)/2);
        if(key > arr[mid]){
            low = mid+1;
        }else if(key < arr[mid]){
            high = mid-1;
        }else {
            return mid;
        }
    }
    return -1;
}
var arr = [1,2,3,4,5,6,7,8,9];
console.log(binarySearch(arr , 9));

22.实现布局,子元素宽占父元素的50%,高和宽相等,自适应。
跟谁学

答:原理:padding-top,padding-bottom是根据父元素的宽度计算而不是height。

<div class="a">
  <div class="b">

  </div>
  <div class="b">

  </div>
</div>

.a{
  width:300px;
  height:600px;
  background:pink;
  font-size:0;
}
.b{
  width:40%;
  background:#f13a70;
  padding-top:40%;
  display:inline-block;
}
  1. keep-alive原理
    TCP keep-alive
    VUE <keep-alive>组件原理
    北明软件

答:

HTTP1.0中默认是关闭的,需要在HTTP头加入"Connection: Keep-Alive",才能启用Keep-Alive;HTTP1.1中默认启用Keep-Alive,加入"Connection: close ",才关闭。

const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)

由于keep-alive只获取第一个子节点,所以一般搭配看component动态组件或者router-view使用。
接下来,判断组件名字和include,exclude的关系。
这里match函数做匹配的逻辑兼容了数组,字符串,和正则的情况。
include的情况,去找缓存。
命中缓存,就从缓存中拿VNode实例,并且调整key的顺序排在最后一个。
未命中,就把VNode设置进缓存,如缓存数量超过了配置的max值, 就删掉缓存队列中的第一个。这里有个判断,就是删掉的节点是不是当前的tag,是就直接删掉,不是的话,要调用缓存的组件实例 的$destroy钩子。
如果是exclude的情况,就直接返回VNode。
<keep-alive>组件也观测include和exclude的情况,对cache做遍历,如果缓存的节点名和新的规则不匹配,就把缓存的节点删除。


VUE<keep-alive>.png

24.vue tab页跳转时, 保存之前的滚动位置

答:有两种方式:vue-router的滚动行为和keep-alive
在源码中,对于浏览器默认行为,调用自定义的scrollBehavior函数后传参的savedPosition为保存的position,对于跳转这种则传参的savedPosition为null。
基本我们可以提炼出:通过跳转的是需要进行数据刷新的;而通过默认浏览器行为的是不需要进行浏览器刷新的。

const router = new VueRouter({
  routes: [],
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition;
    } else {
      return {x:0,y:0}
    }
  }
})

也可以模拟滚动到锚点的行为

scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash
    }
  }
}

可以返回一个promise得到预期位置的描述
因为scrollBehavior 在组件生命周期的mounted后beforeUpdated前执行,mounted时期发出的异步请求并没有等到返回,滚动事件已经触发,所以等数据请求回来时会发现滚动 位置不准确。所以必须使用settimeout将滚动事件加到异步队列中,位于异步请求之后。(settimeout是加在了本轮主线程的末尾,但是settimeout中的异步事件放到了和异步请求同一个队列中。)

scrollBehavior (to, from, savedPosition) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ x: 0, y: 0 })
    }, 500)
  })
}

每次切换新标签时, vue都创建了一个新的currentTabComponent。

路由跳转时,vue-router不保存被切换组件的状态,旧的会被销毁,新组建被创建,走一遍完整的生命周期流程。

要求被包裹的组件有自己的名字,注意不是路由名字。

keep-alive是个抽象组件(或称为功能型组件),存在于initLifeCycle中,实际上不会被渲染在DOM树中。它的作用是在内存中缓存组件(不让组件销毁),等到下次再渲染的时候,还会保持其中的所有状态,并且会触发activated钩子函数。因为缓存的需要通常出现在页面切换时,所以常与router-view一起出现。

可以只缓存一些组件

如果只想渲染某一些页面/组件,可以使用keep-alive组件的include/exclude属性。include属性表示要缓存的组件名(即组件定义时的name属性),接收的类型为string、RegExp或string数组;exclude属性有着相反的作用,匹配到的组件不会被缓存。假如可能出现在同一router-view的N个页面中,我只想缓存列表页和详情页,那么可以这样写:

<keep-alive :include="['ListView', 'DetailView']">
  <router-view />
</keep-alive>
可以实现条件渲染

上面include的写法不是常用的,因为它固定了哪几个页面缓存或不缓存,假如有下面这个场景:

现有页面:首页(A)、列表页(B)、详情页(C),一般可以从:A->B->C;
B到C再返回B时,B要保持列表滚动的距离;
B返回A再进入B时,B不需要保持状态,是全新的。
具体细节:
https://juejin.im/post/5b407c2a6fb9a04fa91bcf0d

scrollbehavior和keepalive标签有什么区别?

我的理解是,从本质上讲,scrollbehavior是在缓存里记录了上一个页面的滚动位置信息,而keepalive是把不活动的组件保存在内存中, 而不是直接销毁。
scrollbehavior只能控制浏览器的返回前进,没法处理tab切换这种,而keepalive可以。

25.window load event和document DOMContentLoaded event的区别
独到科技

答:
load事件在整个页面全部加载完才会触发,包括所有以来的资源,样式,图片。
load,页面上所有的资源(图片,音频,视频等)被加载以后才会触发load事件,简单来说,页面的load事件会在DOMContentLoaded被触发之后才触发。

不同于DOMContentLoaded,一旦DOM加载完,就会触发。
在这里我们可以明确DOMContentLoaded所计算的时间,当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件;如果文档中包含脚本,则脚本会阻塞文档的解析,而脚本需要等位于脚本前面的css加载完才能执行。在任何情况下,DOMContentLoaded 的触发不需要等待图片等其他资源加载完成。

26.给定两个排序好的数组a,b,长度分别为n,m,给出一个高效算法,查找A中的哪些元素存在于B中。
彩视

答:

var a = [1,3,5,7,9];
var b = [1,5,6,8,10];
let c = [];
c = a.filter(i => b.includes(i));
var a = [1,3,5,5,7,9,9,10,10];
var b = [1,5,5,6,8,10];
let c = [];
let aSet = new Set(a);
let bSet = new Set(b);
c = Array.from(aSet).filter(i => bSet.has(i))
console.log(c);
let a = [1,3,5,5,7,9,9,10,10,'s',NAN];
let b = [1,5,5,6,8,10,'s',NAN];
let ahasNAN = a.some(i => isNAN(i));
let bhasNAN = b.some(i => isNAN(i));
let c = [];
c = (a.filter((i) => b.indexOf(i)>-1)).concat(ahasNAN && bhasNan ? [NAN] : []);//考虑NAN
c = a.filter((i) => b.indexOf(i)>-1);//不考虑NAN

我没成功


image.png

27.实现一个函数,入参是一个字符串,判断是否有重复字母,如果包含,返回第一个重复字母的下标,不包含返回-1。
大搜车

答:

let a = [1, 2, 2, 3, 3, 4, 5]
let b = [];
let res = -1;
for (let i = 0; i < a.length; i++) {
  if (b.includes(a[i])) {
    res = i;
    break;
  } else {
    b.push(a[i]);
  }
}
console.log(res);
console.log(b);
image.png

28.对象数组a=[{x:7,y:6} , {x:1,y:2} , {x:3,y:4}],按照x的大小进行排序。
瓜子二手车

答:
js page113,Function类型,比较函数,一个函数返回另一个函数

function compare(x) {
  return function(obj1, obj2) {
    var value1 = obj1.x;
    var value2 = obj2.x;
    if (value1 < value2) {
      return -1;
    } else if (value1 > value2) {
      return 1;
    } else {
      return 0;
    }
  }
}
 var objArr = [{x:4,y:10},{x:12,y:2},{x:-3,y:9}];
 console.log(objArr.sort(compare('x')));
image.png

29.阶乘函数
未经优化的版本

function factorial(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * factorial(num - 1);
  }
}
 console.log(factorial(5));

但问题是这个函数的执行与函数名factorial紧紧耦合了,为了消除这种紧密耦合的现象,可以使用arguments.callee。
arguments对象有个callee属性,callee是个指针,指向拥有这个arguments对象的函数。
但是严格模式下访问arguments.callee会报错

function factorial(num) {
  if (num <= 1) {
    return 1
  } else {
    return num * arguments.callee(num-1);
  }
}
 console.log(factorial(5));

使用具名函数,这种方式在严格模式和非严格模式下都行得通。

var factorial = function f(num){
    if(num <=1){
        return 1;
    }else{
        return num * f(num-1);
    }
};
  1. call() apply()和bind()的区别?

答:call和apply改变了函数的this上下文之后立即执行函数,而bind则是返回改变了上下文后的一个函数。

31.实现tooltip, css画钝角三角形
瓜子二手

答:操作边的宽度就可以实现钝角锐角三角形


image.png

32.判断一个对象是函数的几种方法。

1.typeof操作符
typeof func == "function" ; //true
typeof操作符一般用来检测基本类型,返回小写字符串,检测引用类型时,除了function返回‘function’之外,其余都返回object,因此不适合检测引用类型。

  1. toString(最佳)
    Object.prototype.toString.call(fn)=== '[object Function]';

  2. Constructor构造函数法


    image.png

    null和undefined没有构造函数,如果不能确定类型,不能用此方法检测。

  3. instanceof操作符
    instanceof操作符假定只有一个全局环境,如果有多个框架,就会有多个不同版本的构造函数,instanceof就不会生效。


    image.png

33.实现商品列表,一行3个,屏幕宽度不定,商品元素间距50px,距离父元素边距50px。
瓜子二手车

<div class='a'>
  <div class='b-wrap'>

    <div class='b'>

    </div>
    <div class='b'>

    </div>
    <div class='b'>

    </div>
    <div class='b'>

    </div>
  </div>

</div>
.a {
  width: 500px;
  height: 500px;
  background: #3c3c3c;
  padding: 50px;
}

.b-wrap {
  width: 100%;
  height: 100%;
  background: pink;
}

.b {
  float: left;
  background: #aaaa12;
  margin-bottom: 50px;
// 此处注意,减号左右要有空格, 否则计算属性不生效
  width: calc((100% - 100px)/3);
  padding-top: calc((100% - 100px)/3);
}

.b:nth-child(2) {
  margin: 0 50px;
}
image.png

然后我发现这个方法不对。。。。


image.png

用flex:
这是个遗留问题,我不会了。

34.向一个数组增加元素的方法
瓜子二手车

答:以下三个方法都修改原数组

35.盒子模型有哪几种, width100padding10的盒子, 占据宽度是多少?
微店

答:当文档布局时,浏览器渲染引擎会把元素都表示为矩形的盒子。
box-sizing属性有三个值

上一篇下一篇

猜你喜欢

热点阅读