前端回答(1)

1.浏览器的重绘(repaint)和重排(reflow)

- 当改变元素颜色等,不会影响布局的一些变化,就会触发重绘,即重新绘制

- 当改变元素宽高等,会影响布局的一些行为,就会触发重排。整个页面布局重新排列

会导致重排的一些行为:

1.重新设置width,height,padding,margin,字体大小的设置等

2.读取offsetHeight/Width/Top/Left

   clientHeight/Width/Top/Left

   scrollHeight/Width/Top/Left

   width,height等属性 

3.DOM结构的变化

4.窗口大小的变化resize

5.元素的显示隐藏等

重排一定伴随重绘,但是重绘不一定会重排。

重绘和重排会带来很大的性能上的问题

如何减少重排?

1.把对样式修改的操作集中到一起,最好一次性改变style

2.对width,height,offset等这些数据的读取,在读取之后用一个变量来存储起来,后面需要的时候就使用,避免多次读取

3.尽量避免循环操作DOM,嵌套操作DOM,减少操作DOM的次数(虚拟DOM)

4.对resize,scroll等事件进行防抖节流

5.对不可避免的重复布局变化,可以使用硬件加速的方式。让重复变化的部分单独在一个图层,这样他的变化造成的影响就只影响他所在的图层(比如动画的实现,就可以通过translate3D,实现硬件加速)

 

2.实现懒加载

为什么要使用懒加载?

设想我们在刷微博的时候,点击了一个热搜有很多图片,但是我们点进去了之后才发现我们根本不感兴趣。如果不做懒加载,即使我们不想继续浏览后面的图片,他也给我请求了,浪费了我们的流量,也占用了请求资源。

懒加载的原理:对于我们可能会看到但是还没有看到的图片或者其他,先暂时使用一个默认图片,或者一个空来替代。

然后监听视口,当我们将要滑动到,或者滑动到某个图片时才去做请求。

滚动区域的宽高 + 视口的宽高 >= 图片到顶部的宽高

document.documentElement.scrollTop

document.docuentElement.clientHeight

e.getBoundingClientRect

e.offsetTop

可以用这三种方式获取高度

通过监听scroll事件,来监听图片到视口的位置

但是特别注意scroll事件的监听是会导致重排的,可以通过节流来减少scroll事件触发的频率

还有一种方法交叉观察器intersectionObserver

 

3.防抖 节流 

上面的图片懒加载就可以通过节流来减少事件的触发

为什么是节流而不是防抖呢?

在懒加载的时候,我们希望不要一滚动就触发scroll事件,我们希望他在一段时间触发一次

在一段时间内只触发一次,就是节流

而防抖就是多次触发,以最后一次触发为准,开始计时(就类似于英雄回城的效果,多次点击,只以最后一次点击为准)

手撕防抖节流(这里只实现简单的防抖节流,如果后面有遇到这种问题,就再深入实现)

 1 function throttle(fn, time) {       // 节流
 2     var start = 0
 3     return function () {
 4         var _this = this
 5         var args = arguments
 6         var curr = +new Date()
 7         if (curr - start > time) {
 8             fn.call(_this, ...args)
 9             start = curr
10         }
11     }
12 }
13 function debounce(fn, time) {      // 防抖
14     var timer 
15     return function () {
16         var _this = this
17         var args = arguments
18         clearTimeout(timer)
19         timer = setTimeout(function () {
20             fn.call(_this, ...args)
21         }, time)
22     }
23 }

 

具体的注意点请参考(https://www.cnblogs.com/kkkllo/p/13413993.html

 

4.JavaScript中的arguments 

arguments是函数的参数列表,是一个类数组,但是可以通过解构赋值来解构,还可以用for of 来遍历,因为它具有Iterator接口

类数组的特点:是以数字作为属性值,是从0开始的,还有长度属性

除了arguments这个类数组之外,还有DOMnodeList(我们通过document.getElementByClassName()获取到的节点类数组)

 

5.“==”和“===”的区别 

==两个值之间的比较存在一个隐式类型转换的行为

===这就是最直接的相等,不存在转化

参考文章(https://www.cnblogs.com/kkkllo/p/13502701.html

 

6.EventLoop事件循环 

事件分为异步任务和同步任务

同步任务在主线程上执行,形成一个执行栈,事件触发线程管理着一个事件队列。如果异步任务运行有了结果,就将这个异步任务添加到事件队列中。

如果是一个定时器,就会开启一个定时的线程,当定时器时间到了,就将其放入事件队列中。

当执行栈中任务执行完之后,就会将事件队列中的事件放入执行栈中,然后执行。

异步任务又分为宏任务和微任务

同步任务执行完之后,会先执行在这个过程中产生的所有微任务,然后再执行一个宏任务。如果在这个宏任务执行的过程中产生了微任务,就先执行微任务,然后再执行下一个宏任务。

常见的宏任务:setTimeout,setInterval

常见的微任务:then

这也就可以解释为什么setTimeout用作倒计时为何会产生误差

setTimeout是异步宏任务,即使他的事件执行时间到了,但是他前面的同步任务和微任务还没执行完,他就不能执行

 

7.let、const和var的概念与区别

let,const是es6引入的,作用在块级作用域中。解决var变量提升带来的问题

let.const是没有变量提升的,所以如果在let,const声明之前使用,是会形成暂时性死区的,会报错。(不能在声明前使用)

let和const的区别:let用来声明变量,const用来声明常量,是不可以修改的,修改了会报错。

         但是如果const声明的常量是一个object,只是修改上面的某个属性是不会报错的 (这就是引用类型原理)

关于var的变量提升

在预编译的过程中,变量声明,函数声明会提升到最顶部,然后在是代码执行,函数的执行过程,形参与实参相统一。

 

8.JS中的String、Array和Math方法 

Array方法

会修改原数组的方法:pop,push,unshift,shift,splice,sort,reverse(7种)

遍历数组的方法:map,some,filter,reduce,forEach

其他方法:slice,join,contact,isArray等

map,reduce的参数

关于map和forEach的区别

map和forEach都是对数组的遍历,都是通过return等没办法中断的。

但是map是会返回一个新的数组的,但是forEach只会返回undefined

相对来说forEach更像for循环一点,就是对数组中每一项的遍历。而map是得到对每一项操作之后的结果。

Math方法

向上取整Math.ceil   向下取整 Math.floor  四舍五入Math.round 随机数Math.random  等

String方法

split, indexOf, charAt,charCodeAt,match,replace

字符串截取的几种方式 slice(与数组中的slice很相似)

          substring(与slice的语法很类似)

 

 

9.

console.log(add(1)(2)(3)) // 6;
console.log(add(1, 2, 3)(4)) //10;
console.log(add(1)(2)(3)(4)(5)) // 15;

这道题获取参数的原理是柯理化,但是其实最根本的还是考察toString和value

function add() {
  let arg = [].slice.call(arguments)   // 用闭包的方式来存储参数
  // 用a函数来获取参数
  function a() {
     arg.push(...argumens)
     return a             
  }
  a.toString = function (){
      return arg.reduce(function(a, b) {
         return a + b
    })    
  }
  return a
}    

用a函数来获取参数的方式,就是柯理化的原理

当console.log的时候就需要调用a.toString上的方法

参考文章(https://www.jianshu.com/p/5e1899fe7d6b

 

10.Ajax的请求过程 

var xhr = new XMLHttpRequest()

xhr.open('GET', url, null)

xhr.send(null)

xhr.onreadystatechange = function(){

  if (xhr.readystate == 4 && xhr.status == 200) {

    console.log(xhr.responseText)

  }

}

posted @ 2020-10-06 15:01  kkkllo  阅读(211)  评论(0)    收藏  举报