有哪些前端面试题是面试官必考的

36 阅读16分钟

分片思想解决大数据量渲染问题

题目描述:渲染百万条结构简单的大数据时 怎么使用分片思想优化渲染

实现代码如下:

let ul = document.getElementById("container");
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total / once;
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal, curIndex) {
  if (curTotal <= 0) {
    return false;
  }
  //每页多少条
  let pageCount = Math.min(curTotal, once);
  window.requestAnimationFrame(function () {
    for (let i = 0; i < pageCount; i++) {
      let li = document.createElement("li");
      li.innerText = curIndex + i + " : " + ~~(Math.random() * total);
      ul.appendChild(li);
    }
    loop(curTotal - pageCount, curIndex + pageCount);
  });
}
loop(total, index);

扩展思考:对于大数据量的简单 dom 结构渲染可以用分片思想解决 如果是复杂的 dom 结构渲染如何处理?

这时候就需要使用虚拟列表了 大家自行百度哈 虚拟列表和虚拟表格在日常项目使用还是很频繁的

行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

  • 行内元素有:a b span img input select strong
  • 块级元素有:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p

空元素,即没有内容的HTML元素。空元素是在开始标签中关闭的,也就是空元素没有闭合标签:

  • 常见的有:<br><hr><img><input><link><meta>
  • 鲜见的有:<area><base><col><colgroup><command><embed><keygen><param><source><track><wbr>

ES6新特性

1.ES6引入来严格模式
    变量必须声明后在使用
    函数的参数不能有同名属性, 否则报错
    不能使用with语句 (说实话我基本没用过)
    不能对只读属性赋值, 否则报错
    不能使用前缀0表示八进制数,否则报错 (说实话我基本没用过)
    不能删除不可删除的数据, 否则报错
    不能删除变量delete prop, 会报错, 只能删除属性delete global[prop]
    eval不会在它的外层作用域引入变量
    evalarguments不能被重新赋值
    arguments不会自动反映函数参数的变化
    不能使用arguments.caller (说实话我基本没用过)
    不能使用arguments.callee (说实话我基本没用过)
    禁止this指向全局对象
    不能使用fn.caller和fn.arguments获取函数调用的堆栈 (说实话我基本没用过)
    增加了保留字(比如protected、static和interface)

2.关于letconst新增的变量声明

3.变量的解构赋值

4.字符串的扩展
    includes():返回布尔值,表示是否找到了参数字符串。
    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
5.数值的扩展
    Number.isFinite()用来检查一个数值是否为有限的(finite)。
    Number.isNaN()用来检查一个值是否为NaN6.函数的扩展
    函数参数指定默认值
7.数组的扩展
    扩展运算符
8.对象的扩展
    对象的解构
9.新增symbol数据类型

10.SetMap 数据结构 
    ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。 Set 本身是一个构造函数,用来生成 Set 数据结构。

    Map它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
11.Proxy
    Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问
    都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
    Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
    Vue3.0使用了proxy
12.Promise
    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
    特点是:
        对象的状态不受外界影响。
        一旦状态改变,就不会再变,任何时候都可以得到这个结果。
13.async 函数 
    async函数对 Generator 函数的区别:
    (1)内置执行器。
    Generator 函数的执行必须靠执行器,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
    (2)更好的语义。
    asyncawait,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
    (3)正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。
    (4)返回值是 Promiseasync函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
14.Class 
    classletconst一样:不存在变量提升、不能重复声明...
    ES6class可以看作只是一个语法糖,它的绝大部分功能
    ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
15.Module
    ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
    importexport命令以及exportexport default的区别

左右两边定宽,中间自适应

float,float + calc, 圣杯布局(设置BFC,margin负值法),flex

.wrap {
  width: 100%;
  height: 200px;
}
.wrap > div {
  height: 100%;
}
/* 方案1 */
.left {
  width: 120px;
  float: left;
}
.right {
  float: right;
  width: 120px;
}
.center {
  margin: 0 120px; 
}
/* 方案2 */
.left {
  width: 120px;
  float: left;
}
.right {
  float: right;
  width: 120px;
}
.center {
  width: calc(100% - 240px);
  margin-left: 120px;
}
/* 方案3 */
.wrap {
  display: flex;
}
.left {
  width: 120px;
}
.right {
  width: 120px;
}
.center {
  flex: 1;
}

for...in和for...of的区别

for…of 是ES6新增的遍历方式,允许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值,和ES3中的for…in的区别如下

  • for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
  • for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;
  • 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;

总结: for...in 循环主要是为了遍历对象而生,不适用于遍历数组;for...of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。

link和@import的区别

两者都是外部引用CSS的方式,它们的区别如下:

  • link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
  • link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。
  • link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。
  • link支持使用Javascript控制DOM去改变样式;而@import不支持。

参考 前端进阶面试题详细解答

常见的HTTP请求头和响应头

HTTP Request Header 常见的请求头:

  • Accept:浏览器能够处理的内容类型
  • Accept-Charset:浏览器能够显示的字符集
  • Accept-Encoding:浏览器能够处理的压缩编码
  • Accept-Language:浏览器当前设置的语言
  • Connection:浏览器与服务器之间连接的类型
  • Cookie:当前页面设置的任何Cookie
  • Host:发出请求的页面所在的域
  • Referer:发出请求的页面的URL
  • User-Agent:浏览器的用户代理字符串

HTTP Responses Header 常见的响应头:

  • Date:表示消息发送的时间,时间的描述格式由rfc822定义
  • server:服务器名称
  • Connection:浏览器与服务器之间连接的类型
  • Cache-Control:控制HTTP缓存
  • content-type:表示后面的文档属于什么MIME类型

常见的 Content-Type 属性值有以下四种:

(1)application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码。

(2)multipart/form-data:该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。

(3)application/json:服务器消息主体是序列化后的 JSON 字符串。

(4)text/xml:该种方式主要用来提交 XML 格式的数据。

对this对象的理解

this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this 的指向可以通过四种调用模式来判断。

  • 第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
  • 第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。
  • 第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
  • 第四种是 apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。

这四种方式,使用构造器调用模式的优先级最高,然后是 apply、call 和 bind 调用模式,然后是方法调用模式,然后是函数调用模式。

隐藏元素的方法有哪些

  • display: none:渲染树不会包含该渲染对象,因此该元素不会在页面中占据位置,也不会响应绑定的监听事件。
  • visibility: hidden:元素在页面中仍占据空间,但是不会响应绑定的监听事件。
  • opacity: 0:将元素的透明度设置为 0,以此来实现元素的隐藏。元素在页面中仍然占据空间,并且能够响应元素绑定的监听事件。
  • position: absolute:通过使用绝对定位将元素移除可视区域内,以此来实现元素的隐藏。
  • z-index: 负值:来使其他元素遮盖住该元素,以此来实现隐藏。
  • clip/clip-path :使用元素裁剪的方法来实现元素的隐藏,这种方法下,元素仍在页面中占据位置,但是不会响应绑定的监听事件。
  • transform: scale(0,0):将元素缩放为 0,来实现元素的隐藏。这种方法下,元素仍在页面中占据位置,但是不会响应绑定的监听事件。

常用的正则表达式有哪些?

// (1)匹配 16 进制颜色值
var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;

// (2)匹配日期,如 yyyy-mm-dd 格式
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;

// (3)匹配 qq 号
var regex = /^[1-9][0-9]{4,10}$/g;

// (4)手机号码正则
var regex = /^1[34578]\d{9}$/g;

// (5)用户名正则
var regex = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;

script标签中defer和async的区别

如果没有defer或async属性,浏览器会立即加载并执行相应的脚本。它不会等待后续加载的文档元素,读取到就会开始加载和执行,这样就阻塞了后续文档的加载。

defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析,其区别如下:

  • 执行顺序: 多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行;
  • 脚本是否并行执行:async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的,即异步执行;defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。

数据类型判断

核心思想typeof 可以判断 Undefined、String、Number、Boolean、Symbol、Function类型的数据,但对其他的都会认为是Object,比如Null、Array等。所以通过typeof来判断数据类型会不准确。

解决方法:可以通过Object.prototype.toString解决。

实现

function mytypeof(obj) {
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

  1. 使用call 是为了绑定 thisobj
  2. 使用slice 是因为这前面返回的结果是类似[Object xxx]这样的, xxx 是根据 obj 的类型变化的
  3. 使用toLowerCase 是因为原生typeof的返回结果的第一个字母是小写字母。

DNS 协议是什么

概念: DNS 是域名系统 (Domain Name System) 的缩写,提供的是一种主机名到 IP 地址的转换服务,就是我们常说的域名系统。它是一个由分层的 DNS 服务器组成的分布式数据库,是定义了主机如何查询这个分布式数据库的方式的应用层协议。能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。

作用: 将域名解析为IP地址,客户端向DNS服务器(DNS服务器有自己的IP地址)发送域名查询请求,DNS服务器告知客户机Web服务器的 IP 地址。

webpack配置入口出口

module.exports={
    //入口文件的配置项
    entry:{},
    //出口文件的配置项
    output:{},
    //模块:例如解读CSS,图片如何转换,压缩
    module:{},
    //插件,用于生产模版和各项功能
    plugins:[],
    //配置webpack开发服务功能
    devServer:{}
}
简单描述了一下这几个属性是干什么的。
描述一下npm run dev / npm run build执行的是哪些文件
通过配置proxyTable来达到开发环境跨域的问题,然后又可以扩展和他聊聊跨域的产生,如何跨域
最后可以在聊聊webpack的优化,例如babel-loader的优化,gzip压缩等等

浏览器存储

我们经常需要对业务中的一些数据进行存储,通常可以分为 短暂性存储 和 持久性储存。

  • 短暂性的时候,我们只需要将数据存在内存中,只在运行时可用
  • 持久性存储,可以分为 浏览器端 与 服务器端
    • 浏览器:
      • cookie: 通常用于存储用户身份,登录状态等
        • http 中自动携带, 体积上限为 4K, 可自行设置过期时间
      • localStorage / sessionStorage: 长久储存/窗口关闭删除, 体积限制为 4~5M
      • indexDB
    • 服务器:
      • 分布式缓存 redis
      • 数据库

cookie和localSrorage、session、indexDB 的区别

特性cookielocalStoragesessionStorageindexDB
数据生命周期一般由服务器生成,可以设置过期时间除非被清理,否则一直存在页面关闭就清理除非被清理,否则一直存在
数据存储大小4K5M5M无限
与服务端通信每次都会携带在 header 中,对于请求性能影响不参与不参与不参与

从上表可以看到,cookie 已经不建议用于存储。如果没有大量数据存储需求的话,可以使用 localStoragesessionStorage 。对于不怎么改变的数据尽量使用 localStorage 存储,否则可以用 sessionStorage 存储。

对于 cookie,我们还需要注意安全性

属性作用
value如果用于保存用户登录态,应该将该值加密,不能使用明文的用户标识
http-only不能通过 JS访问 Cookie,减少 XSS攻击
secure只能在协议为 HTTPS 的请求中携带
same-site规定浏览器不能在跨域请求中携带 Cookie,减少 CSRF 攻击

  • Name,即该 Cookie 的名称。Cookie 一旦创建,名称便不可更改。
  • Value,即该 Cookie 的值。如果值为 Unicode 字符,需要为字符编码。如果值为二进制数据,则需要使用 BASE64 编码。
  • Max Age,即该 Cookie 失效的时间,单位秒,也常和 Expires 一起使用,通过它可以计算出其有效时间。Max Age如果为正数,则该 CookieMax Age 秒之后失效。如果为负数,则关闭浏览器时 Cookie 即失效,浏览器也不会以任何形式保存该 Cookie
  • Path,即该 Cookie 的使用路径。如果设置为 /path/,则只有路径为 /path/ 的页面可以访问该 Cookie。如果设置为 /,则本域名下的所有页面都可以访问该 Cookie
  • Domain,即可以访问该 Cookie 的域名。例如如果设置为 .zhihu.com,则所有以 zhihu.com,结尾的域名都可以访问该 CookieSize 字段,即此 Cookie 的大小。
  • Http 字段,即 Cookiehttponly 属性。若此属性为 true,则只有在 HTTP Headers 中会带有此 Cookie 的信息,而不能通过 document.cookie 来访问此 Cookie。
  • Secure,即该 Cookie 是否仅被使用安全协议传输。安全协议。安全协议有 HTTPS、SSL 等,在网络上传输数据之前先将数据加密。默认为 false

实现 JSONP 跨域

JSONP 核心原理script 标签不受同源策略约束,所以可以用来进行跨域请求,优点是兼容性好,但是只能用于 GET 请求;

实现

const jsonp = (url, params, callbackName) => {
    const generateUrl = () => {
        let dataSrc = "";
        for(let key in params) {
            if(params.hasOwnProperty(key)) {
                dataSrc += `${key}=${params[key]}&`
            }
        }
        dataSrc += `callback=${callbackName}`;
        return `${url}?${dataSrc}`;
    }
    return new Promise((resolve, reject) => {
        const scriptEle = document.createElement('script');
        scriptEle.src = generateUrl();
        document.body.appendChild(scriptEle);
        window[callbackName] = data => {
            resolve(data);
            document.removeChild(scriptEle);
        }
    });
}

同样是重定向,307303302的区别?

302是http1.0的协议状态码,在http1.1版本的时候为了细化302状态码⼜出来了两个303和307。 303明确表示客户端应当采⽤get⽅法获取资源,他会把POST请求变为GET请求进⾏重定向。 307会遵照浏览器标准,不会从post变为get。

实现一个 add 方法

题目描述:实现一个 add 方法 使计算结果能够满足如下预期: add(1)(2)(3)()=6 add(1,2,3)(4)()=10

其实就是考函数柯里化

实现代码如下:

function add(...args) {
  let allArgs = [...args];
  function fn(...newArgs) {
    allArgs = [...allArgs, ...newArgs];
    return fn;
  }
  fn.toString = function () {
    if (!allArgs.length) {
      return;
    }
    return allArgs.reduce((sum, cur) => sum + cur);
  };
  return fn;
}

说一说js是什么语言

JavaScript是一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。

js语言是弱语言类型, 因此我们在项目开发中当我们随意更该某个变量的数据类型后
有可能会导致其他引用这个变量的方法中报错等等。

JS 数据类型

基本类型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 引用类型:Object,对象子类型(Array,Function)