A-A+

前端面试题

2020年10月08日 JavaScript 暂无评论 阅读 7 次

css基础

HTML+CSS布局与兼容性

HTML5+CSS3移动端布局(remempx区别 dpi的描述)

如何将一个元素设置为不可见

css盒模型的两种模式

提升页面性能的方法有哪些

reflow和repaint的理解 (减少dom重绘的操作)哪些属性会造成

水平垂直居中

calc, support, media各自的含义及用法

1rem、1em、1vh、1px各自代表的含义

CSS居中布局有哪些,适用于什么场景,举例说明?

一、CSS居中:margin设为auto
做法:把要居中的元素的margin-left和margin-right都设为auto
场景:只能进行水平的居中,且对浮动元素或绝对定位元素无效。
二、CSS居中:使用 text-align:center
场景:只能对图片,按钮,文字等行内元素(display为inline或inline-block等)进行水平居中。但要说明的是在IE6、7这两个奇葩的浏览器中,它是能对任何元素进行水平居中的。
三、CSS居中:使用line-height让单行的文字垂直居中
做法:把文字的line-height设为文字父容器的高度
场景:适用于只有一行文字的情况。
四、CSS居中:使用表格
做法:td/th元素设置align="center"、valign="middle"即可处理单元格里面内容的水平和垂直居中问题
场景:必须是table
五、CSS居中:使用display:table-cell来居中
做法:通过display:table-cell 模拟表格单元格,这样就可以利用表格那很方便的居中特性了。
场景:IE6、IE7都无效。
六、CSS居中:使用绝对定位进行居中
场景:只适用于宽度或高度已知的元素。
原理:通过把这个绝对定位元素的left或top的属性设为50%,这个时候元素并不是居中的,而是比居中的位置向右或向左偏了这个元素宽度或高度的一半的距离,所以需要使用一个负的margin-left或margin-top的值来把它拉回到居中的位置,这个负的margin值就取元素宽度或高度的一半。
七、CSS居中:使用绝对定位进行居中
场景:只适用于宽度或高度已知的元素。且只支持IE9+,谷歌,火狐等符合w3c标准的现代浏览器。
原理:这里如果不定义元素的宽和高的话,那么他的宽就会由left,right的值来决定,高会由top,bottom的值来决定,所以必须要设置元素的高和宽。同时如果改变left,right , top , bottom的值还能让元素向某个方向偏移。
八、CSS居中:使用浮动配合相对定位来进行水平居中
场景:不用知道要居中的元素的宽度,缺点是需要一个多余的元素来包裹要居中的元素。
原理:把浮动元素相对定位到父元素宽度50%的地方,但这个时候元素还不是居中的,而是比居中的那个位置多出了自身一半的宽度,这时就需要他里面的子元素再用一个相对定位,把那多出的自身一半的宽度拉回来,而因为相对定位正是相对于自身来定位的,所以自身一半的宽度只要把left 或 right 设为50%就可以得到了,因而不用知道自身的实际宽度是多少。

标准模型和IE模型的区别?

标准模型的宽高为content的宽高
IE模型的宽高包括border

calc, support, media各自的含义及用法?

@support主要是用于检测浏览器是否支持CSS的某个属性,其实就是条件判断,如果支持某个属性,你可以写一套样式,如果不支持某个属性,你也可以提供另外一套样式作为替补。
calc() 函数用于动态计算长度值。 calc()函数支持 "+", "-", "*", "/" 运算;
@media 查询,你可以针对不同的媒体类型定义不同的样式。

提升页面性能的方法有哪些?

资源压缩合并,减少HTTP请求
非核心代码异步加载
使用浏览器缓存
使用CDN
预解析DNS
HTML优化,如使用语义化标签,避免重定向等
CSS优化,如布局代码写前面,根据需求加载的网络字体,避免使用表达式

js基础

跨域的JS运行错误可以捕获么?错误提示是什么,应该怎么处理?

可以捕获,提示“Script error”,具体错误信息无法获得 解决方案:
客户端:在script标签增加crossorigin属性
服务端:设置JS资源响应头Access-Control-Allow-Origin

防抖 节流

1)防抖
原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
适用场景:
按钮提交场景:防止多次提交按钮,只执行最后提交的一次
搜索框联想场景:防止联想发送请求,只发送最后一次输入
简易版实现
function debounce(func, wait) {
    let timeout;
    return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }
}
立即执行版实现
有时希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。
// 有时希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。
function debounce(func, wait, immediate) {
  let timeout;
  return function () {
    const context = this;
    const args = arguments;
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      const callNow = !timeout;
      timeout = setTimeout(function () {
        timeout = null;
      }, wait)
      if (callNow) func.apply(context, args)
    } else {
      timeout = setTimeout(function () {
        func.apply(context, args)
      }, wait);
    }
  }
}
返回值版实现
func函数可能会有返回值,所以需要返回函数结果,但是当 immediate 为 false 的时候,因为使用了 setTimeout ,我们将 func.apply(context, args) 的返回值赋给变量,最后再 return 的时候,值将会一直是 undefined,所以只在 immediate 为 true 的时候返回函数的执行结果。
function debounce(func, wait, immediate) {
  let timeout, result;
  return function () {
    const context = this;
    const args = arguments;
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      const callNow = !timeout;
      timeout = setTimeout(function () {
        timeout = null;
      }, wait)
      if (callNow) result = func.apply(context, args)
    }
    else {
      timeout = setTimeout(function () {
        func.apply(context, args)
      }, wait);
    }
    return result;
  }
}
2)节流
原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
适用场景
拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
缩放场景:监控浏览器resize
使用时间戳实现
使用时间戳,当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 ),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。
function throttle(func, wait) {
  let context, args;
  let previous = 0;

  return function () {
    let now = +new Date();
    context = this;
    args = arguments;
    if (now - previous > wait) {
      func.apply(context, args);
      previous = now;
    }
  }
}
使用定时器实现
当触发事件的时候,我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,然后执行函数,清空定时器,这样就可以设置下个定时器。
function throttle(func, wait) {
  let timeout;
  return function () {
    const context = this;
    const args = arguments;
    if (!timeout) {
      timeout = setTimeout(function () {
        timeout = null;
        func.apply(context, args)
      }, wait)
    }

  }
}

说一下宏任务和微任务?

宏任务:当前调用栈中执行的任务称为宏任务。(主代码快,定时器等等)。
微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务为微任务。(可以理解为回调事件,promise.then,proness.nextTick等等)。
宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。

深浅拷贝

浅拷贝:浅拷贝通过ES6新特性Object.assign()或者通过扩展运算法...来达到浅拷贝的目的,浅拷贝修改 副本,不会影响原数据,但缺点是浅拷贝只能拷贝第一层的数据,且都是值类型数据,如果有引用型数据,修改 副本会影响原数据。 
深拷贝:通过利用JSON.parse(JSON.stringify())来实现深拷贝的目的,但利用JSON拷贝也是有缺点的, 当要拷贝的数据中含有undefined/function/symbol类型是无法进行拷贝的,当然我们想项目开发中需要 深拷贝的数据一般不会含有以上三种类型,如有需要可以自己在封装一个函数来实现。

数组常用方法

map: 遍历数组,返回回调返回值组成的新数组
forEach: 无法break,可以用try/catch中throw new Error来停止
filter: 过滤 
some: 有一项返回true,则整体为true 
every: 有一项返回false,则整体为false
join: 通过指定连接符生成字符串
push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项【有误】
unshift / shift: 头部推入和弹出,改变原数组,返回操作项【有误】 
sort(fn) / reverse: 排序与反转,改变原数组 concat: 连接数组,不影响原数组, 浅拷贝
slice(start, end): 返回截断后的新数组,不改变原数组 
splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组
indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标 
reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)

跨域理解

因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名或者端口有一个不同就是跨域,Ajax 请求会失败。 为来防止CSRF攻击
 1.JSONP JSONP 的原理很简单,就是利用 <script> 标签没有跨域限制的漏洞。 通过 <script> 标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。 <script src="http://domain/api?param1=a&param2=b&callback=jsonp"></script> <script> function jsonp(data) { console.log(data) } </script> JSONP 使用简单且兼容性不错,但是只限于 get 请求。 
2.CORS CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。
3.document.domain 该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。 只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同就可以实现跨域 
4.webpack配置proxyTable设置开发环境跨域
5.nginx代理跨域
6.iframe跨域 
7.postMessage 这种方式通常用于获取嵌入页面中的第三方页面数据。一个页面发送消息,另一个页面判断来源并接收消息

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。  解决来之前在请求中回调请求产生的回调地狱,使得现在的代码更加合理更加优雅,也更加容易定位查找问题。

webpack

webpack有哪些常见 loader 和 plugin,你用过哪些

file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
eslint-loader:通过 ESLint 检查 JavaScript 代码
define-plugin:定义环境变量
commons-chunk-plugin:提取公共代码
uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
1、通过externals配置来提取常用库
2、利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来
3、使用Happypack 实现多线程加速编译
要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下
4、使用Tree-shaking和Scope Hoisting来剔除多余代码 5、使用fast-sass-loader代替sass-loader 6、babel-loader开启缓存
babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率 可以加上cacheDirectory参数或使用 transform-runtime 插件试试

react

key

1. 简单列表项 不带key的情况下可能性能更好
2. key的作用判断两个节点是否相同,更快的复用已有组件

React 中 refs 的作用是什么?

Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回:
class CustomForm extends Component {
  handleSubmit = () => {
    console.log("Input Value: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}
上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用。另外值得一提的是,refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值:
function CustomForm ({handleSubmit}) {
  let inputElement
  return (
    <form onSubmit={() => handleSubmit(inputElement.value)}>
      <input
        type='text'
        ref={(input) => inputElement = input} />
      <button type='submit'>Submit</button>
    </form>
  )
}

受控组件 非受控组件

1. 没有维持自己的状态 1. 保持着自己的状态
2.数据由父组件控制 2.数据由 DOM 控制
3. 通过 props 获取当前值,然后通过回调通知更改 3. Refs 用于获取其当前值

vue

computed和watch有什么区别?

computed:

1. computed是计算属性,也就是计算值,它更多用于计算值的场景
2. computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
3. computed适用于计算比较消耗性能的计算场景
复制代码
watch:

1. 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作
2. 无缓存性,页面重新渲染时值不变化也会执行
复制代码
小结:

1. 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
2. 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化

组件之间的传值通信

父子 使用props,父组件可以使用props向子组件传递数据
子组件向父组件通信
父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件

非父子,兄弟组件之间通信
可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递

1、父组件向子组件传递状态使用props属性实现。
2、子组件向父组件传递参数使用子组件触发事件,父组件监听发出的事件的方式来实现( $emit)。
3、兄弟组件之间使用事件总线的方式(eventBus),其中一个组件使用$emit触发,另一个组件使用$on监听。

网络

https 和 http 的区别

1、https 协议需要到 ca 申请证书,http 是基于 tcp/ip 协议的,传输的内容都是明文,https 在基于 tcp/ip 协议的基础上多了一层 ssl/tls 加密,传输内容都是通过加密,因此https 可以做到防劫持;
2、http使用的是80端口,https 使用的是443端口;
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

缓存的分类有哪些?(跟缓存相关的HTTP头部有哪些?)

1. 强缓存
特点:不请求,直接使用缓存
相关的HTTP头部字段:
Expires:过期时间,是个绝对时间,下发的是服务器时间,比较用的是客户端的时间,所以会有偏差
Cache-Control:过期时间,是个相对时间,优先级高,以客户端的相对时间为准,浏览器拿到资源之后的多少时间内都不会再去服务器请求
2. 协商缓存
特点:浏览器不确定备份是否过期,需与服务器请求确认
相关的HTTP头部字段:
Last-Modified/If-Modified-Since:服务器下发时间,客户端请求时带上下发时间,服务器判断文件是否过期。存在的问题服务器下发的时间难以定义
Etag/If-None-Match:服务器下发hash值,客户端请求时带上hash值,服务器判断文件是否过期。优先级高

HTTP状态码

区分状态码
1××开头 - 信息提示
2××开头 - 请求成功
3××开头 - 请求被重定向
4××开头 - 请求错误
5××开头 - 服务器错误
常见状态码
200 - 请求成功,Ajax 接受到信息了
400 - 服务器不理解请求
403 - 服务器拒绝请求
404 - 请求页面错误
500 - 服务器内部错误,无法完成请求

get和post的区别

1、get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些
2、get相对post安全性低

3、get有缓存,post没有

4、get体积小,post可以无限大

5、get的url参数可见,post不可见

6、get只接受ASCII字符的参数数据类型,post没有限制

7、get请求参数会保留历史记录,post中参数不会保留

8、get会被浏览器主动catch,post不会,需要手动设置

9、get在浏览器回退时无害,post会再次提交请求

git

git常用命令

从远程库克隆到本地:git clone 网站上的仓库地址
新增文件的命令:git add .
提交文件的命令:git commit –m或者git commit –a
查看工作区状况:git status –s
拉取合并远程分支的操作:git fetch/git merge或者git pull
查看提交记录命令:git reflog
标签:

给我留言

Copyright © web前端技术开发个人博客 保留所有权利  京ICP备14060653号 Theme  Ality

用户登录