乐趣区

关于javascript:刘建2022年前端面试题汇总

前端面试材料

Author: 刘建(Abbott Liu)

Create::2022/03/20

Update:2022/03/30

如果感觉不错,麻烦关注下我

技术能力考核

原生 JavaScript

JavaScript 数据类型

JavaScript 中有几种简略数据类型(也称为根本数据类型):Number、Undefined、Null、String 和 Boolean。还要一种简单类型——Object,Object 实质是一组无序的名值对组成。JavaScript 中不反对任何创立自定义的类型的机制,而所有值都是这 6 种数据类型之一。

值类型(根本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。

援用数据类型(对象类型):对象 (Object)、数组(Array)、函数(Function),还有两个非凡的对象:正则(RegExp) 和日期(Date)。

注:ES5 中有 5 种根本数据类型,Symbol 是 ES6 引入了一种新的原始数据类型,示意举世无双的值。

判断 Object 和 Array

应用instanceof

let o = new Object();
let a = new Array();
console.log(o instanceof Array);
console.log(a instanceof Array);

应用Array.isArray

console.log(Array.isArray(a))

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

行内元素:a、b、span、img、input、strong、select、label、em、button、textarea

块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote

空元素:即系没有内容的 HTML 元素,例如:br、meta、hr、link、input、img

什么是 MVVM

MVVM(Model-View-ViewModel)是一种软件架构设计模式,它是一种简化用户界面的事件驱动编程形式。

去掉字符串的前后空格

function trimString(str) {var regSpace = /^(\s*)|(\s*)$/ig;
    if(str !== null && str !== undefined) {return str.replace(regSpace, '')
    } else {return str}
}

let valueTest = "AbbottLiu"

console.log(valueTest)
console.log(valueTest.length)
console.log(trimString(valueTest, ""))
console.log(trimString(valueTest, "").length)

生成肯定范畴内随机数

function createRandomNum(minVal, maxVal) {
    var result = null
    switch(arguments.length) {
      case 1:
        result = parseInt(Math.random()*minVal+1,10);
        break;
      case 2:
        result = Math.floor(Math.random() * (maxVal - minVal + 1)) + minVal
        break;
      default:
        break;
    }
    return result;
}

for(var i = 0; i<10; i++) {console.log(createRandomNum(2));
}

防抖和节流

函数防抖(debounce):触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则从新计算工夫。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div>
  <div class="test01"> 点击 </div>
</div>
</body>

<script>
  // 防抖 debounce 代码(定时器):var debounce = function(func, delay) {
    var timer = null
    let result;

    return function() {console.log("防抖点击函数")
      var context = this;
      var args = arguments;
      if (timer) {clearTimeout(timer);
      }
      timer = setTimeout(function() {result = func.apply(context, args);
      }, delay)
      return result
    }
  }
  function handle() {console.log('random ==', Math.random());
  }

  document.querySelector('.test01').onclick = debounce(handle, 5 * 1000)

</script>

</html>

函数节流(throttle):高频事件触发,但在 n 秒内只会执行一次,所以节流会浓缩函数的执行频率。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div>
  <div class="test01"> 点击 </div>
</div>
</body>

<script>
  // 节流 throttle 代码(定时器):var throttle = function(func, delay) {var prev = Date.now();
    console.log('prev ==', prev)
    return function() {
      var context = this;
      var args = arguments;
      var now = Date.now();
      console.log('now ==', now)
      if (now - prev >= delay) {func.apply(context, args);
        prev = Date.now();}
    }
  }
  function handle() {console.log('random ==', Math.random());
  }

  document.querySelector('.test01').onclick = throttle(handle, 5 * 1000)

</script>

</html>

总结:
函数防抖:将屡次操作合并为一次操作进行。原理是保护一个计时器,规定在 delay 工夫后触发函数,然而在 delay 工夫内再次触发的话,就会勾销之前的计时器而从新设置。这样一来,只有最初一次操作能被触发。

函数节流:使得肯定工夫内只触发一次函数。原理是通过判断是否有提早调用函数未执行。

区别:函数节流不论事件触发有多频繁,都会保障在规定工夫内肯定会执行一次真正的事件处理函数,而函数防抖只是在最初一次事件后才触发一次函数。比方在页面的有限加载场景下,咱们须要用户在滚动页面时,每隔一段时间发一次 Ajax 申请,而不是在用户停下滚动页面操作时才去申请数据。这样的场景,就适宜用节流技术来实现。

cookies,sessionStorage 和 localStorage 的区别

三者之间的区别比照

分类 Cookie localStorage sessionStorage
个性 个别由服务器生成,可设置生效工夫。如果在浏览器端生成 Cookie,默认是敞开浏览器后生效 除非被革除,否则永恒保留 仅在以后会话下无效,敞开页面或浏览器后被革除
4K 左右 个别为 5MB
与服务器端通信 每次会携带在 HTTP 头中,如果应用 cookie 保留过多数据会带来性能问题 仅在客户端(即浏览器)中保留,不参加和服务器的通信
易用性 须要程序员本人封装,源生的 Cookie 接口不敌对 源生接口能够承受,亦可再次封装来对 Object 和 Array 有更好的反对

Get 和 Post

分类 GET POST
后退按钮 / 刷新 有害 数据会被从新提交(浏览器应该告知用户数据会被从新提交)
书签 可珍藏为书签 不可珍藏为书签
缓存 能被缓存 不能缓存
编码类型 application/x-www-form-urlencoded application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据应用多重编码。
历史 参数保留在浏览器历史中 参数不会保留在浏览器历史中
对数据长度的限度 是的。当发送数据时,GET 办法向 URL 增加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符) 无限度。
对数据类型的限度 只容许 ASCII 字符 没有限度。也容许二进制数据
安全性 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送明码或其余敏感信息时绝不要应用 GET! POST 比 GET 更平安,因为参数不会被保留在浏览器历史或 web 服务器日志中。
可见性 数据在 URL 中对所有人都是可见的。 数据不会显示在 URL 中。

它们的实质都是 TCP 链接,并无区别。然而因为 HTTP 的规定以及浏览器 / 服务器的限度,导致它们在利用过程中可能会有所不同。

TCP 和 UDP 的比拟

分类 GET POST
后退按钮 / 刷新 有害 数据会被从新提交(浏览器应该告知用户数据会被从新提交)
书签 可珍藏为书签 不可珍藏为书签

TCP 三次握手

留神,连贯的建设与完结都是 客户端 发动的。

第一次握手:建设连贯时,客户端发送 syn 包(syn=j)到服务器,并进入 SYN_SENT 状态,期待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=j+1),同时本人也发送一个 SYN 包(syn=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;

第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=k+1),此包发送结束,客户端和服务器进入 ESTABLISHED(TCP 连贯胜利)状态,实现三次握手。

TCP 为什么是三次握手,为什么不是两次或者四次

这是一个很有意思的问题~

首先,咱们要晓得 TCP 是全双工的,即客户端在给服务器端发送信息的同时,服务器端也能够给客户端发送信息。而半双工的意思是 A 能够给 B 发,B 也能够给 A 发,然而 A 在给 B 发的时候,B 不能给 A 发,即不同时,为半双工。单工为只能 A 给 B 发,B 不能给 A 发;或者是只能 B 给 A 发,不能 A 给 B 发。

咱们假如 A 和 B 是通信的单方。我了解的握手实际上就是通信,发一次信息就是进行一次握手。

第一次握手:A 给 B 打电话说,你能够听到我谈话吗?
第二次握手:B 收到了 A 的信息,而后对 A 说:我能够听失去你谈话啊,你能听失去我谈话吗?
第三次握手:A 收到了 B 的信息,而后说能够的,我要给你发信息啦!

在三次握手之后,A 和 B 都能确定这么一件事:我说的话,你能听到;你说的话,我也能听到。这样,就能够开始失常通信了。

留神:HTTP 是基于 TCP 协定的,所以每次都是客户端发送申请,服务器应答,然而 TCP 还能够给其余应用层提供服务,即可能 A、B 在建设链接之后,谁都可能先开始通信。

如果两次,那么 B 无奈确定 B 的信息 A 是否能收到,所以如果 B 先谈话,可能前面的 A 都收不到,会呈现问题。

如果四次,那么就造成了节约,因为在三次完结之后,就曾经能够保障 A 能够给 B 发信息,A 能够收到 B 的信息;B 能够给 A 发信息,B 能够收到 A 的信息。

AMD 和 CMD 的区别

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。

CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

区别

  1. 对于依赖的模块,AMD 是提前执行,CMD 是提早执行。不过 RequireJS 从 2.0 开始,也改成能够提早执行(依据写法不同,解决形式不同)。CMD 推崇 as lazy as possible。
  2. AMD 推崇依赖前置,CMD 推崇依赖就近。
  3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格辨别,推崇职责繁多。比方 AMD 里,require 分全局 require 和部分 require,都叫 require。CMD 里,没有全局 require,而是依据模块零碎的齐备性,提供 seajs.use 来实现模块零碎的加载启动。CMD 里,每个 API 都简略纯正。

WebSocket 的定义

// 申请一个 WebSocket 对象,参数是服务端地址,var ws = new WebSocket("ws://localhost:8080"); 
ws.onopen = function() {
    // 当 WebSocket 创立胜利时,触发 onopen 事件
   console.log("open");
   ws.send("hello"); // 将音讯发送到服务端
}

// 当客户端收到服务端发来的音讯时,触发 onmessage 事件,参数 e.data 蕴含 server 传递过去的数据
ws.onmessage = function(e) {console.log(e.data);
}
// 当客户端收到服务端发送的敞开连贯申请时,触发 onclose 事件
ws.onclose = function(e) {console.log("close");
}
// 如果呈现连贯、解决、接管、发送数据失败的时候触发 onerror 事件
ws.onerror = function(e) {console.log(error);
}

弹性盒子 flexbox 罕用的容器属性与我的项目属性

介绍

CSS 弹性盒子布局是 CSS 的模块之一,定义了一种针对用户界面设计而优化的 CSS 盒子模型。在弹性布局模型中,弹性容器的子元素能够在任何方向上排布,也能够“弹性伸缩”其尺寸,既能够减少尺寸以填满未应用的空间,也能够膨胀尺寸以防止父元素溢出。子元素的程度对齐和垂直对齐都能很不便的进行操控。通过嵌套这些框(程度框在垂直框内,或垂直框在程度框内)能够在两个维度上构建布局。

术语

  • 容器:具备 display: flex 属性元素,任何元素都能够通过增加 display:flex; 属性,转换为弹性盒元素,转换为 flex 元素后,它的外部的“子元素”就反对 flex 布局了。
  • 我的项目:flex 容器的”子元素”,容器中的我的项目主动转为行内块元素,不论之前是什么类型。
  • 主轴:我的项目排列的轴线,个别默认状况下主轴为程度方向。
  • 穿插轴:与主轴垂直的轴线,个别默认状况下,穿插轴为竖直方向。

容器属性

属性 形容
flex-flow 主轴方向与换行形式
justify-content 我的项目在主轴上的对齐形式
align-items 我的项目在穿插轴上的对齐形式
align-content 我的项目在多行容器中的对齐形式

我的项目属性

属性 形容
flex 我的项目的缩放比例与基准宽度
align-self 单个我的项目在穿插轴上的对齐形式
order 我的项目在主轴上排列程序

应用 flex 布局绘制款式

html 文件

<div class='daily-sign-in-root'>
    <div class='t1'>
        <div class='t11'>1</div>
        <div class='t12'>2</div>
    </div>
</div>

css 文件

.t1 {
    display: flex;
    width: 500px;
    height: 300px;
    background: #00ee00;
    align-items: center;
    box-sizing: border-box;
    justify-content: space-between;
    padding: 20px;
}

.t11 {
    width: 150px;
    height: 100px;
    background: #2c009f;
    align-self: flex-end;
}

.t12 {
    width: 150px;
    height: 100px;
    background: #00A0E9;
    align-self: flex-start;
}

斐波那契数列

什么是斐波那契数列:斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子滋生为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、55、……在数学上,斐波纳契数列以如下被以递归的办法定义:F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)(n>2,n∈N*)

function Fibonacci(n) {if(n<=1) {return 1};
    return Fibonacci(n-1)+ Fibonacci(n-2)
}
console.log(Fibonacci(9));

革除浏览器缓存的几种办法

<meta http-equiv="pragma" CONTENT="no-cache">
<meta http-equiv="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta http-equiv="expires" CONTENT="0">

说了这么多 mate 兼容性不靠谱!所以说根本没用

<head>
    <link type="text/css" rel="styleSheet" href="./assets/styles/job.202102231230.css?time=20220530.css" />
</head>

ES6

Promise 了解

Promise 构造函数承受一个函数作为参数,该函数的两个参数别离是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不必本人部署。

resolve 函数的作用是,将 Promise 对象的状态从“未实现”变为“胜利”(即从 pending 变为 resolved),在异步操作胜利时调用,并将异步操作的后果,作为参数传递进来;reject 函数的作用是,将 Promise 对象的状态从“未实现”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的谬误,作为参数传递进来。

const p = new Promise((resolve, reject)=>{
    var a = 20 
    if(a > 10) {reject(10)
    } else {resolve(5)
    }
})

p.then((data)=>{console.log('success ==', data);
}).catch((err)=>{console.log('err ==', err);
})

Vue

Vue 生命周期

双向数据绑定原理

Vue 是一个 MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变动。这也算是 vue 的精华之处了。值得注意的是,咱们所说的数据双向绑定,肯定是对于 UI 控件来说的,非 UI 控件不会波及到数据双向绑定。单向数据绑定是应用状态管理工具(如 Redux)的前提。

例子

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>defineProperty</title>
</head>
<body>
<input type="text" id="textInput">
输出:<span id="textSpan"></span>
<script>
  var obj = {foo: ''},
      textInput = document.querySelector('#textInput'),
      textSpan = document.querySelector('#textSpan');

  Object.defineProperty(obj, 'foo', {get: function () {console.log('obj.foo 属性');
      return 'variety'
    },
    set: function (newValue) {console.log('newValue ==', newValue);
      textInput.value = newValue;
      textSpan.innerHTML = newValue;
    }
  });
  console.log(obj.foo)
  textInput.addEventListener('keyup', function (e) {obj.foo = e.target.value;});

</script>
</body>
</html>

watched 和 computed 区别

计算属性 computed

  • 反对缓存,只有依赖数据产生扭转,才会从新进行计算
  • 不反对异步,当 computed 内有异步操作时有效,无奈监听数据的变动
  • computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于 data 中申明过或者父组件传递的 props 中的数据通过计算失去的值
  • 如果一个属性是由其余属性计算而来的,这个属性依赖其余属性,是一个多对一或者一对一,个别用 computed
  • 如果 computed 属性属性值是函数,那么默认会走 get 办法;函数的返回值就是属性的属性值;在 computed 中的,属性都有一个 get 和一个 set 办法,当数据变动时,调用 set 办法。
<p id="app"> {fullName}} </p>

<script>
    var vm = new Vue({  
        el: '#app',  
        data: {  
            firstName: 'Foo',  
            lastName: 'Bar',  
        },  
        computed: {fullName: function () {return this.firstName + ' ' + this.lastName}  
        }  
    })
</script>

侦听属性 watch

  • 不反对缓存,数据变,间接会触发相应的操作。
  • watch 反对异步;监听的函数接管两个参数,第一个参数是最新的值;第二个参数是输出之前的值;
  • 当一个属性发生变化时,须要执行对应的操作;一对多;
  • 监听数据必须是 data 中申明过或者父组件传递过去的 props 中的数据,当数据变动时,触发其余操作,函数有两个参数
var vm = new Vue({
        el: '#app',
        data: {
            firstName: 'Foo',
            lastName: 'Bar',
            fullName: 'Foo Bar'
        },
        watch: {firstName: function (val) {this.fullName = val + ' ' + this.lastName},
            lastName: function (val) {this.fullName = this.firstName + ' ' + val}
        }
    })

我的项目所遇到的问题

登录验证码图片显示

后盾返回的登录验证码图片是以流的模式返回的。所以这里须要应用到 Uint8Array 和 String.fromCharCode 这 2 个 api。Uint8Array 示意一个 8 位无符号整型数组,用来存储返回来的流。String.fromCharCode()依据指定的 Unicode 编码中的序号值来返回一个字符串。这里我是应用 axios 进行申请的,同是须要指定返回的类型是 arraybuffer,代码如下:

SSO 单点登录

SSO(Single Sign On)是在一个多零碎共存的环境下,用户在一处登录之后,就不必在其余的零碎中登录,也就是用户的一次登录能失去其余所有零碎的信赖。单点登录在大型网站外面应用的比拟多,例如像阿里巴巴这样的网站,在万丈的背地是成千盈百的子系统,用户一次操作或交易可能波及到几个十几个子系统的合作,如果每个子系统都须要用户认证, 会在无形中减少工夫的消耗。实现单点登录说到底就是要解决如何产生和存储那个信赖, 再就是其余子系统如何验证这个信赖的有效性, 因而要一下两个点:

秒杀零碎前端优化

1、为什么须要前端优化?

在一个网站中,大部分的服务器申请带宽资源都被动态资源占用了,动态资源蕴含(CSS/IMG/JS/MP4)等,而 HTTP 协定接口占用带宽资源十分小,比方:

1M 宽带等于等于 128KB/S,如果加载一个网页含动态资源须要 640/KB,那么就须要 5 秒工夫加载整个网页。

想让用户的申请及时的发送到服务器端上,服务器带宽肯定足够,所以这时候网站肯定要实现动静拆散架构模式,将动态资源与动静资源离开,动态资源放入到 CDN 服务器端上。

2、前端优化计划

前端的优化计划具体指的是动态资源优化计划,形式有如下几种:

  1. js/css/img 实现压缩缩小带宽的传输、将动态资源放入第三方资源服务器中(例如七牛云、阿里 OSS 等)。
  2. 商品详情页面应用 Nginx+Lua+OpenResty 实现商品详情页面的优化。
  3. 提交后按钮 disabled,禁止用户反复提交。

3、Nginx 实现页面缓存

1、nginx 配置文件内容如下(nginx 端口为 7788,零碎门户端口为 8080)

events {
  #的最大连接数(蕴含所有连接数)1024
  worker_connections  1024;  ## Default: 1024
}

http{

   # 代理缓存配置
   proxy_cache_path "./taodong_cachedata"  levels=1:2 keys_zone=taodongcache:256m inactive=1d max_size=1000g; 
   server {
     listen 7788;
     location /{
        #应用缓存名称
        proxy_cache taodongcache;
        #对以下状态码实现缓存
        proxy_cache_valid 200 206 304 301 302 1d;
        #缓存的 key
        proxy_cache_key $request_uri;
        add_header X-Cache-Status $upstream_cache_status;
        #反向代理地址
        proxy_pass http://127.0.0.1:8080;
      }
   }
}

2. 配置文件下新建文件夹:

mkdir taodong_cachedata

3. 浏览器应用 Nginx 拜访:http://127.0.0.1:7788/login,能够看到拜访失常,Nginx 反向代理到了门户零碎)

Vue

页面卡顿问题

setInterval 路由跳转持续运行并没有及时进行销毁

比方一些弹幕,走马灯文字,这类须要定时调用的,路由跳转之后,因为组件曾经销毁了,然而 setInterval 还没有销毁,还在持续后盾调用,控制台会一直报错,如果运算量大的话,无奈及时革除,会导致重大的页面卡顿。

解决方案:在组件生命周期 beforeDestroy 进行 setInterval

beforeDestory() {clearInterval(this.timer);
    MessageBox.close()}

上传图片有效

某些时候,商家上传图片当前,某些图片上传没有胜利。

因为在上传后,应用了定时器来跳转,没有判断全副图片是否都上传胜利了。

禁止浏览器弹框的解决办法

点击这里查看

更多其余前端工程师面试题

退出移动版