前端面试题(下)

简介: 前端面试题(下)

什么是垂直外边距合并?说说合并后的几种情况?


什么是垂直外边距合并


外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。

合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。

实际工作中,垂直外边距合并问题常见于第一个子元素的margin-top会顶开父元素与父元素相邻元素的间距,而且只在标准浏览器下(FirfFox、Chrome、Opera、Sarfi)产生问题,IE下反而表现良好。


合并后的几种情况


相邻块元素垂直外边距的合并

当上下相邻的两个块元素相遇时,如果上面的元素有下外边距margin-bottom,下面的元素有上外边距margin-top,则他们之间的垂直间距不是margin-bottom与margin-top之和,而是两者中的较大者。

这种现象被称为相邻块元素垂直外边距的合并(也称外边距塌陷)。


解决方案:


尽量只给一个盒子添加margin值。

嵌套块元素垂直外边距的合并

对于两个嵌套关系的块元素,如果父元素没有上内边距及边框,则父元素的上外边距会与子元素的上外边距发生合并,合并后的外边距为两者中的较大者,即使父元素的上外边距为0,也会发生合并。


解决方法:

父盒子可以加个边框

用overflow(加了这句话在浏览器中可以看到也是自动加了1px的边框)。

可以为父元素定义上内边距。


什么是强缓存和协商缓存?


什么是强缓存

服务器通过设置http中hdader的Expires和cache-control字段告诉浏览器换存的有效期。这种方法会有一个固定时间,所带来的问题是如果服务器数据进行了更新,但是还没有到强缓存的过期时间,则数据无法更新


3.1Expires

Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

Expires的值是GMT格式的绝对时间,在设置的时间前浏览器会直接使用本地缓存。


3.2 cache-control

cache-control有12个值,其中的max-age值定义缓存的有效期,单位是秒,例如:cache-control:max-age=700,它表示缓存有效期为700秒,以消息的生成日期为基准,也就是header中的Date字段。


cache-control与Expires的区别在于cache-control的值是相对时间,而Expires是绝对时间,如果我们人为的修改了本地的时间,那么此时本地的时间与服务器上的时间不一致,就会导致缓存不能正确的被使用;而如果用相对时间,不管怎么改变本地的时间,缓存的有效期都不会改变。


什么是协商缓存


简单的说,协商缓存就是通过服务器来判断缓存是否可用。

4.1Last-Modified:

表示这个响应资源的最后修改时间,web服务器在响应请求时,告诉浏览器资源的最后修改时间。

If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。


4.1 Etag/If-None-Match

Etag/If-None-Match也要配合Cache-Control使用。


Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。


If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。


useEffect的依赖为引用类型如何处理?


useEffect的依赖为引用类型的时候,可能会导致监听不出发,原因就是监听的统一个地址的时候,对象本身地址没变,所以监听的结果就是认为数据并没有改变从而不直径调用 解决方案

1.如果数据是对象的话,可以监听对象的里面的值,值是基本类型,如果值改变了,那么可以监听执行

2.在去修改对象和数据的时候,使用参拷贝或者浅拷贝,这样地址发生改变可以监听执行

3.可以转成字符串,通过JSON.stringify() ,监听字符串这样的,这样改变也会执行


说说你对@reduxjs/toolkit的理解?和react-redux有什么区别?


react-redux react官方推出的redux绑定库,react-redux将所有组件分为两大类:UI组件和容器组件,其中所有容器组件包裹着UI组件,构成父子关系。容器组件负责和redux交互,里面使用redux API函数,UI组件负责页面渲染,不使用任何redux API。容器组件会给UI组件传递redux中保存对的状态和操作状态的方法

@reduxjs/toolkit Redux 官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,使用 Redux Toolkit 都可以优化你的代码,使其更可维护


知道react里面的createPortal么,说说其使用场景?


react.createPortal 是用来制作弹窗组件,它 在Modal 组件位置进行 fixed 定位,可以任意的挂载到某个dom元素上,使用后的管理更方便,但是注意需要预留html的挂载元素

createPortal应用场景:body外层遮罩 弹出框遮罩


Provider和connect的底层原理实现,写出其核心代码?


connect()

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

import { connect } from 'react-redux'
const VisibleTodoList = connect()(TodoList);


上面代码中,TodoList是 UI 组件,VisibleTodoList就是由 React-Redux 通过connect方法自动生成的容器组件。


但是,因为没有定义业务逻辑,上面这个容器组件毫无意义,只是 UI 组件的一个单纯的包装层。为了定义业务逻辑,需要给出下面两方面的信息。


输入逻辑:外部的数据(即state对象)如何转换为 UI 组件的参数

输出逻辑:用户发出的动作如何变为 Action 对象,从 UI 组件传出去。


因此,connect方法的完整 API 如下。

import { connect } from 'react-redux'
const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)


上面代码中,connect方法接受两个参数:mapStateToProps和mapDispatchToProps。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。


Provider组件

connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。


一种解决方法是将state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。


React-Redux 提供Provider组件,可以让容器组件拿到state。

import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'
let store = createStore(todoApp);
render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)


上面代码中,Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了。

它的原理是React组件的context属性,请看源码。

class Provider extends Component {
  getChildContext() {
    return {
      store: this.props.store
    };
  }
  render() {
    return this.props.children;
  }
}
Provider.childContextTypes = {
  store: React.PropTypes.object
}


上面代码中,store放在了上下文对象context上面。然后,子组件就可以从context拿到store,代码大致如下。

class VisibleTodoList extends Component {
  componentDidMount() {
    const { store } = this.context;
    this.unsubscribe = store.subscribe(() =>
      this.forceUpdate()
    );
  }
  render() {
    const props = this.props;
    const { store } = this.context;
    const state = store.getState();
    // ...
  }
}
VisibleTodoList.contextTypes = {
  store: React.PropTypes.object
}



React-Redux自动生成的容器组件的代码,就类似上面这样,从而拿到store。


说说webpack中常见的loader?解决了什么问题?


常见的loader如下:


style-loader: 将css添加到DOM的内联样式标签style里

css-loader :允许将css文件通过require的方式引入,并返回css代码

less-loader: 处理less

sass-loader: 处理sass

postcss-loader: 用postcss来处理CSS

autoprefixer-loader: 处理CSS3属性前缀,已被弃用,建议直接使用postcss

file-loader: 分发文件到output目录并返回相对路径

url-loader: 和file-loader类似,但是当文件小于设定的limit时可以返回一个Data Url

html-minify-loader: 压缩HTML

babel-loader :用babel来转换ES6文件到ES


说说如何借助webpack来优化前端性能?


1、压缩代码

删除多余代码,注释,简化代码的写法等等方式。可以利用webpack的uglifyJsPlugin和ParallelUglifyPlugin来压缩js文件,利用cssnano来压缩css资源。


2、利用CDN加速:

在构建过程中,将引用的静态资源修改为CDN上对应的路径。我们想引用一个库,但是又不想让webpack打包,并且又不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置externals。

configureWebpack: {
    externals: {
        "vue": "Vue",
        "vue-router": "VueRouter",
        "axios": "axios",
        "moment": "moment",
        "element-ui": "ELEMENT",
    }
}


3、Tree shaking:

将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现。

4、Code Splitting:

将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存。例如vue中的异步组件就是按需加载。

5、提取公共第三⽅库:

提取公共第三⽅库:来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码。


说说javascript内存泄漏的几种情况?


  1. 对象没有被正确地销毁或释放

在JavaScript中,如果一个对象没有被正确地销毁或释放,它将一直占用内存。这种情况通常发生在使用全局变量或闭包时,因为这些变量或闭包会一直存在于内存中,直到程序结束。


  1. 循环引用

循环引用是指两个或多个对象之间相互引用,导致它们无法被垃圾回收器自动清除。这种情况通常发生在对象之间的相互引用,例如在JavaScript中的事件处理程序中。


  1. DOM元素未被正确地移除

如果DOM元素没有被正确地从页面中移除,它将一直存在于内存中。这种情况通常发生在使用jQuery或其他DOM操作库时,因为这些库可能会缓存DOM元素并延迟它们的删除。


  1. 定时器未被正确地清除

如果定时器没有被正确地清除,它将一直存在于内存中,导致内存泄漏。这种情况通常发生在使用setTimeout()和setInterval()函数时,因为这些函数会在后台运行并持续触发回调函数。


  1. 全局变量未被正确地声明或初始化

如果全局变量没有被正确地声明或初始化,它们将一直存在于内存中,导致内存泄漏。这种情况通常发生在使用全局变量时,因为这些变量会一直存在于内存中,直到程序结束。


说说你对react的理解?有哪些特性?


React,用于构建用户界面的 JavaScript 库,只提供了 UI 层面的解决方案

遵循组件设计模式、声明式编程范式和函数式编程概念,以使前端应用程序更高效使用虚拟 DOM 来有效地操作 DOM,遵循从高阶组件到低阶组件的单向数据流

帮助我们将界面成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,构成整体页面

react 类组件使用一个名为 render() 的方法或者函数组件return,接收输入的数据并返回需要展示的内容


React 特性有很多,如:

JSX 语法

单向数据绑定

虚拟 DOM

声明式编程

Component


React 存在的优势:

高效灵活

声明式的设计,简单使用

组件式开发,提高代码复用率

单向响应的数据流会比双向绑定的更安全,速度更快


说说React生命周期有哪些不同的阶段?每个阶段对应的方法是?


挂载阶段

constructor:再react组件挂在之前会调用这个函数

componentWillmount:在调用render方法之前调用 并且在初始挂载及后续更新都会调用

componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用


更新阶段

componentWillReceiveProps: 在接受父组件改变后的props需要重新渲染组件时用到的比较多,外部组件传递频繁的时候会导致效率比较低


  • shouldComponentUpdate():用于控制组件重新渲染的生命周期,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
  • render(): render() 方法是 class 组件中唯一必须实现的方法。
  • *componentWillUpdate(): shouldComponentUpdate返回true以后,组件进入重新渲染完成之前进入这个函数。
  • **componentDidUpdate(): 每次state改变并重新渲染页面后都会进入这个生命周期
    卸载阶段
    componentWillUnmount (): 在此处完成组件的卸载和数据的销毁。


说说React中setState执行机制?


一个组件的显示形式可以由数据状态和外部参数决定 而数据状态就是state当需要修改里面的值的状态需要通过调用setState来改变 从而达到更新组件内部数据的作用

setState第一个参数可以是一个对象,或者一个函数 而第二个参数是一个回调函数 用于可以实时的获取到更新之后的数据

在使用setState更新数据的时候 setState的更新类型分为 同步更新 异步更新

在组件生命周期 或者react合成事件中 setState是异步

在setTimeout或者原生dom事件中,setState是同步

对同一个值进行多次setState setState的批量更新策略会对其进行覆盖 取最后一次的执行结果


说说react的事件机制?


React事件机制

React基于浏览器事件机制实现了一套自己的事件机制,包括:事件注册、事件合成、事件冒泡、事件触发等。


说说你对受控组件和非受控组件的理解?应用场景?


受控组件:受控制强度较高的组件 例如 我们使用input框的时候 我们如果给input绑定一个value那么我们会发现当前的input无法修改的了 所以我们还需要给input加一个onChange事件 当我们修改input里面的值的时候 去修改input绑定的值 应用场景 : 表单数据提交 一次性验证 强制输入格式 动态输入 一次性取值

非受控组件:不受控制的组件 例如 我们使用ref的时候 绑定给input一个ref 然后我们使用ref.current就可以来获取到我们想要的属性或者参数 应用场景: 一次性取值 提交时验证


如何使用css实现一个三角形,写出两种以上方案得满分?


1.div宽高法

我们定义一个div 然后设置border的颜色然后

<style>
    div{
        width: 0;
        height: 0;
        border: 100px solid;
        border-color: red blue gray yellowgreen;
    }
</style>


2.使用line-gradient

<style>
    .second{
        background: linear-gradient(45deg, deeppink, deeppink 50%, transparent 50%, transparent 100%);
    }
</style>


3.使用 clip-path

<style>
    div{
        width: 100px;
        height: 100px;
        background: gold;
        clip-path: polygon(0 0, 0 100%, 100% 100%);
    }
</style>


说说React jsx转换成真实DOM的过程?


react中的jsx语法会通过babel转化为 js代码,以React.createElement函数形式存在,createElement函数返回一个ReactElement函数,ReactElement函数返回一个的虚拟节点,虚拟节点中嵌套虚拟节点,就形成了虚拟DOM,最后通过ReactDOM.render方法转化为真实DOM。babel在转化jsx过程中,会判断首字母的大小写当首字母为小写的时候,会被认为是原生DOM标签, 那么createElement中的第一个参数就是一个字符串,表示标签的名称当首字母为大写的时候,会被认为是组件,那么createElement中的第一个参数就是组件的名称,


如何通过原生js实现一个节流函数和防抖函数,写出核心代码,不是简单的思路?


防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。如果n秒内高频事件再次被触发,则重新计算时间。


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>防抖</title>
</head>
<body>
  <button id="debounce">点我防抖!</button>
  <script>
    window.onload = function() {
      // 1、获取这个按钮,并绑定事件
      var myDebounce = document.getElementById("debounce");
      myDebounce.addEventListener("click", debounce(sayDebounce));
    }
    // 2、防抖功能函数,接受传参
    function debounce(fn) {
      // 4、创建一个标记用来存放定时器的返回值
      let timeout = null;
      return function() {
        // 5、每次当用户点击/输入的时候,把前一个定时器清除
        clearTimeout(timeout);
        // 6、然后创建一个新的 setTimeout,
        // 这样就能保证点击按钮后的 interval 间隔内
        // 如果用户还点击了的话,就不会执行 fn 函数
        timeout = setTimeout(() => {
          fn.apply(this, arguments);
        }, 1000);
      };
    }
    // 3、需要进行防抖的事件处理
    function sayDebounce() {
      // ... 有些需要防抖的工作,在这里执行
      console.log("防抖成功!");
    }
  </script>
</body>
</html>


节流:指定时间间隔内只会执行一次任务。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>节流</title>
</head>
<body>
  <button id="throttle">点我节流!</button>
  <script>
    window.onload = function() {
      // 1、获取按钮,绑定点击事件
      var myThrottle = document.getElementById("throttle");
      myThrottle.addEventListener("click", throttle(sayThrottle));
    }
    // 2、节流函数体
    function throttle(fn) {
      // 4、通过闭包保存一个标记
      let canRun = true;
      return function() {
        // 5、在函数开头判断标志是否为 true,不为 true 则中断函数
        if(!canRun) {
          return;
        }
        // 6、将 canRun 设置为 false,防止执行之前再被执行
        canRun = false;
        // 7、定时器
        setTimeout( () => {
          fn.apply(this, arguments);
          // 8、执行完事件(比如调用完接口)之后,重新将这个标志设置为 true
          canRun = true;
        }, 1000);
      };
    }
    // 3、需要节流的事件
    function sayThrottle() {
      console.log("节流成功!");
    }
  </script>
</body>
</html>


说说webpack中代码分割如何实现?


代码分割方法一:将原来的单入口文件改为多入口文件

将不同的文件例如js代码文件分为入口文件和测试文件,这个时候打包出来的代码就会根据不同的文件单独打包成属于他们自己的文件


使用splitChunks分离代码

当我们在文件当中引入了node_modules的包时,在打包之后可能打包工具会自动将node_modules当中的包打包进文件当中,这个时候使用以下代码:可以将引入的这些包单独打包,从而减小打包的体积


总的来说,功能就是:

1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk


通过js代码,让某个文件被单独打包成一个chunk

import动态导入语法:能将某个文件单独打包


说说你对React中虚拟dom的理解


Virtual DOM是一种编程概念。通俗点理解,虚拟DOM是一棵虚拟的JavaScript对象树,画重点,”虚拟的“、”JS对象“,指的是它把真实的网页文档节点,虚拟成一个个的js对象,并以树型结构,保存在内存中。


原理

React虚拟DOM的实现原理,通过JS模拟网页文档节点,生成JS对象树(虚拟DOM),然后再进一步生成真实的DOM树,再绘制到屏幕。如果后面有内容发生改变,React会重新生成一棵全新的虚拟DOM树,再与前面的虚拟DOM树进行比对diff,把差异的部分打包成patch,再应用到真实DOM,然后渲染到屏幕浏览器。


说说你对react hook的理解?

说说react 中jsx语法糖的本质?

说说AMD、CMD、commonJS模块化规范的区别?

说说package.json中版本号的规则?

说说你对koa中洋葱模型的理解?

pops和state相同点和不同点?render方法在哪些情况下会执行?

redux本来是同步的,为什么它能执行异步代码?实现原理是什么?中间件的 实现原理是什么?

redux中同步action与异步action最大的区别是什么?

redux-saga和redux-thunk的区别与使用场景?

在使用redux过程中,如何防止定义的action-type的常量重复?

Vuex的实现原理是什么,写出其实现的核心代码

为什么for循环比forEach性能高?

React的路由的原理是什么,写出其实现的核心代码?

React render方法的原理,在什么时候会触发?

说说reduce方法的作用?自己手动封装一个reduce,写出其核心代码?

什么是发布订阅模式,写出其核心实现代码?

大文件的断点续传如何实现,写出其核心思路代码,前后端都要写?

React中”栈调和”Stack Reconciler过程是怎样的?

目录
相关文章
|
3月前
|
缓存 前端开发 中间件
[go 面试] 前端请求到后端API的中间件流程解析
[go 面试] 前端请求到后端API的中间件流程解析
|
21天前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
55 1
|
2月前
|
Web App开发 前端开发 Linux
「offer来了」浅谈前端面试中开发环境常考知识点
该文章归纳了前端开发环境中常见的面试知识点,特别是围绕Git的使用进行了详细介绍,包括Git的基本概念、常用命令以及在团队协作中的最佳实践,同时还涉及了Chrome调试工具和Linux命令行的基础操作。
「offer来了」浅谈前端面试中开发环境常考知识点
|
3月前
|
存储 XML 移动开发
前端大厂面试真题
前端大厂面试真题
|
1月前
|
Web App开发 JavaScript 前端开发
前端Node.js面试题
前端Node.js面试题
|
3月前
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
【8月更文挑战第18天】
52 2
|
3月前
|
存储 JavaScript 前端开发
2022年前端js面试题
2022年前端js面试题
39 0
|
3月前
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
44 个 React 前端面试问题
|
3月前
|
存储 JavaScript 前端开发
|
3月前
|
Web App开发 存储 缓存