关于javascript:2022秋招前端面试题二附答案

UDP协定为什么不牢靠?

UDP在传输数据之前不须要先建设连贯,远地主机的运输层在接管到UDP报文后,不须要确认,提供不牢靠交付。总结就以下四点:

  • 不保障音讯交付:不确认,不重传,无超时
  • 不保障交付程序:不设置包序号,不重排,不会产生队首阻塞
  • 不跟踪连贯状态:不用建设连贯或重启状态机
  • 不进行拥塞管制:不内置客户端或网络反馈机制

浏览器是如何对 HTML5 的离线贮存资源进行治理和加载?

  • 在线的状况下,浏览器发现 html 头部有 manifest 属性,它会申请 manifest 文件,如果是第一次拜访页面 ,那么浏览器就会依据 manifest 文件的内容下载相应的资源并且进行离线存储。如果曾经拜访过页面并且资源曾经进行离线存储了,那么浏览器就会应用离线的资源加载页面,而后浏览器会比照新的 manifest 文件与旧的 manifest 文件,如果文件没有产生扭转,就不做任何操作,如果文件扭转了,就会从新下载文件中的资源并进行离线存储。
  • 离线的状况下,浏览器会间接应用离线存储的资源。

说一下类组件和函数组件的区别?

1. 语法上的区别:

函数式组件是一个纯函数,它是须要承受props参数并且返回一个React元素就能够了。类组件是须要继承React.Component的,而且class组件须要创立render并且返回React元素,语法上来讲更简单。

2. 调用形式

函数式组件能够间接调用,返回一个新的React元素;类组件在调用时是须要创立一个实例的,而后通过调用实例里的render办法来返回一个React元素。

3. 状态治理

函数式组件没有状态治理,类组件有状态治理。

4. 应用场景

类组件没有具体的要求。函数式组件个别是用在大型项目中来宰割大组件(函数式组件不必创立实例,所有更高效),个别状况下能用函数式组件就不必类组件,晋升效率。
复制代码

Set 和 Map有什么区别?

1、Map是键值对,Set是值得汇合,当然键和值能够是任何得值
2、Map能够通过get办法获取值,而set不能因为它只有值
3、都能通过迭代器进行for...of 遍历
4、Set的值是惟一的能够做数组去重,而Map因为没有格局限度,能够做数据存储
复制代码

说一说js是什么语言

JavaScript是一种直译式脚本语言,是一种动静类型、弱类型、基于原型的语言,内置反对类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,宽泛用于客户端的脚本语言,最早是在HTML(规范通用标记语言下的一个利用)网页上应用,用来给HTML网页减少动静性能。

js语言是弱语言类型, 因而咱们在我的项目开发中当咱们随便更该某个变量的数据类型后
有可能会导致其余援用这个变量的办法中报错等等。
复制代码

说说浏览器缓存

缓存能够缩小网络 IO 耗费,进步访问速度。浏览器缓存是一种操作简略、效果显著的前端性能优化伎俩
很多时候,大家偏向于将浏览器缓存简略地了解为“HTTP 缓存”。
但事实上,浏览器缓存机制有四个方面,它们依照获取资源时申请的优先级顺次排列如下:

Memory Cache
Service Worker Cache
HTTP Cache
Push Cache

缓存它又分为强缓存和协商缓存。优先级较高的是强缓存,在命中强缓存失败的状况下,才会走协商缓存
    实现强缓存,过来咱们始终用 expires。    当服务器返回响应时,在 Response Headers 中将过期工夫写入 expires 字段,当初个别应用Cache-Control 两者同时呈现应用Cache-Control         协商缓存,Last-Modified 是一个工夫戳,如果咱们启用了协商缓存,它会在首次申请时随着 Response Headers 返回:每次申请去判断这个工夫戳是否发生变化。    从而去决定你是304读取缓存还是给你返回最新的数据
复制代码

原型

构造函数是一种非凡的办法,次要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)(箭头函数以及Function.prototype.bind()没有)属性,
这个prototype(原型)属性是一个指针,指向一个对象,这个对象的用处是蕴含特定类型的所有实例共享的
属性和办法,即这个原型对象是用来给实例对象共享属性和办法的。每个实例对象的__proto__都指向这个
构造函数/类的prototype属性。

面向对象的三大个性:继承/多态/封装

对于new操作符:

1. new执行的函数, 函数外部默认生成了一个对象

2. 函数外部的this默认指向了这个new生成的对象

3. new执行函数生成的这个对象, 是函数的默认返回值

ES5例子:
function Person(obj) {
    this.name = obj.name
    this.age= obj.age
}
// 原型办法
Person.prototype.say = function() {
  console.log('你好,', this.name )
}
// p为实例化对象,new Person()这个操作称为构造函数的实例化
let p = new Person({name: '番茄', age: '27'})
console.log(p.name, p.age)
p.say()

ES6例子:
class Person{
    constructor(obj) {
      this.name = obj.name
        this.age= obj.age
  }
  say() {
      console.log(this.name)
  }
}

let p = new Person({name: 'ES6-番茄', age: '27'})
console.log(p.name, p.age)
p.say()
复制代码

webpack配置入口进口

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

说一下vue3.0你理解多少?

 <!-- 响应式原理的扭转 Vue3.x 应用Proxy取代 Vue2.x 版本的Object.defineProperty -->
 <!-- 组件选项申明形式Vue3.x 应用Composition API setup 是Vue3.x新增的一个选项,他
    是组件内应用Composition API 的入口 -->
 <!-- 模板语法变动slot具名插槽语法 自定义指令 v-model 降级 -->
 <!-- 其它方面的更改Suspense反对Fragment(多个根节点) 和Protal (在dom其余局部渲染组建内容)组件
     针对一些非凡的场景做了解决。基于treeshaking优化,提供了更多的内置性能。 -->
复制代码

你在工作终于到那些问题,解决办法是什么

常常遇到的问题就是Cannot read property ‘prototype’ of undefined
解决办法通过浏览器报错提醒代码定位问题,解决问题

Vue我的项目中遇到视图不更新,办法不执行,埋点不触发等问题
个别解决方案查看浏览器报错,查看代码运行到那个阶段未之行完结,浏览源码以及相干文档等
而后举进去最近开发的我的项目中遇到的算是两个比拟大的问题。
复制代码

说一下data为什么是一个函数而不是一个对象?

JavaScript中的对象是援用类型的数据,当多个实例援用同一个对象时,只有一个实例对这个对象进行操作,其余实例中的数据也会发生变化。而在Vue中,咱们更多的是想要复用组件,那就须要每个组件都有本人的数据,这样组件之间才不会互相烦扰。所以组件的数据不能写成对象的模式,而是要写成函数的模式。数据以函数返回值的模式定义,这样当咱们每次复用组件的时候,就会返回一个新的data,也就是说每个组件都有本人的公有数据空间,它们各自保护本人的数据,不会烦扰其余组件的失常运行。

说一下常见的git操作

git branch 查看本地所有分支
git status 查看以后状态 
git commit 提交 
git branch -a 查看所有的分支
git branch -r 查看近程所有分支
git commit -am "nit" 提交并且加正文 
git remote add origin git@192.168.1.119:ndshow
git push origin master 将文件给推到服务器上 
git remote show origin 显示近程库origin里的资源 
git push origin master:develop
git push origin master:hb-dev 将本地库与服务器上的库进行关联 
git checkout --track origin/dev 切换到近程dev分支
git branch -D master develop 删除本地库develop
git checkout -b dev 建设一个新的本地分支dev
git merge origin/dev 将分支dev与以后分支进行合并
git checkout dev 切换到本地dev分支
git remote show 查看近程库
git add .
git rm 文件名(包含门路) 从git中删除指定文件
git clone git://github.com/schacon/grit.git 从服务器上将代码给拉下来
git config --list 看所有用户
git ls-files 看曾经被提交的
git rm [file name] 删除一个文件
git commit -a 提交以后repos的所有的扭转
git add [file name] 增加一个文件到git index
git commit -v 当你用-v参数的时候能够看commit的差别
git commit -m "This is the message describing the commit" 增加commit信息
git commit -a -a是代表add,把所有的change加到git index里而后再commit
git commit -a -v 个别提交命令
git log 看你commit的日志
git diff 查看尚未暂存的更新
git rm a.a 移除文件(从暂存区和工作区中删除)
git rm --cached a.a 移除文件(只从暂存区中删除)
git commit -m "remove" 移除文件(从Git中删除)
git rm -f a.a 强行移除批改后文件(从暂存区和工作区中删除)
git diff --cached 或 $ git diff --staged 查看尚未提交的更新
git stash push 将文件给push到一个长期空间中
git stash pop 将文件从长期空间pop下来

webpack3和webpack4区别

1.mode

webpack减少了一个mode配置,只有两种值development | production。对不同的环境他会启用不同的配置。

2.CommonsChunkPlugin

CommonChunksPlugin曾经从webpack4中移除。
可应用optimization.splitChunks进行模块划分(提取专用代码)。
然而须要留神一个问题,默认配置只会对异步申请的模块进行提取拆分,如果要对entry进行拆分
须要设置optimization.splitChunks.chunks = 'all'。

3.webpack4应用MiniCssExtractPlugin取代ExtractTextWebpackPlugin。

4.代码宰割。

应用动静import,而不是用system.import或者require.ensure

5.vue-loader。

应用vue-loader插件为.vue文件中的各局部应用绝对应的loader,比方css-loader等

6.UglifyJsPlugin

当初也不须要应用这个plugin了,只须要应用optimization.minimize为true就行,production mode上面主动为true

optimization.minimizer能够配置你本人的压缩程序
复制代码

New操作符做了什么事件?

1、首先创立了一个新对象
2、设置原型,将对象的原型设置为函数的prototype对象
3、让函数的this指向这个对象,执行构造函数的代码(为这个新对象增加属性)
4、判断函数的返回值类型,如果是值类型,返回创立的对象。如果是援用类型,就返回这个援用类型的对象
复制代码

JS闭包,你理解多少?

应该有面试官问过你:

  1. 什么是闭包?
  2. 闭包有哪些理论使用场景?
  3. 闭包是如何产生的?
  4. 闭包产生的变量如何被回收?

这些问题其实都能够被看作是同一个问题,那就是面试官在问你:你对JS闭包理解多少?

来总结一下我听到过的答案,尽量齐全还原候选人面试的时候说的原话。

答案1: 就是一个function外面return了一个子函数,子函数拜访了里面那个函数的变量。

答案2: for循环外面能够用闭包来解决问题。

for(var i = 0; i < 10; i++){
    setTimeout(()=>console.log(i),0)
}
// 控制台输入10遍10.
for(var i = 0; i < 10; i++){
    (function(a){
    setTimeout(()=>console.log(a),0)
    })(i)
}
 // 控制台输入0-9
复制代码

答案3: 以后作用域产产生了对父作用域的援用。

答案4: 不晓得。是跟浏览器的垃圾回收机制无关吗?

开杠了。请问,小伙伴的答案和以上的内容有多少类似水平?

其实,拿着这些问题好好想想,你就会发现这些问题都只是为了最终那一个问题。

闭包的底层实现原理

1. JS执行上下文

咱们都晓得,咱们手写的js代码是要通过浏览器V8进行预编译后能力真正的被执行。例如变量晋升、函数晋升。举个栗子。

// 栗子:
var d = 'abc';
function a(){
    console.log("函数a");
};
console.log(a);   // ƒ a(){ console.log("函数a"); }
a();              // '函数a'
var a = "变量a";  
console.log(a);   // '变量a'
a();              // a is not a function
var c = 123;

// 输入后果及程序:
// ƒ a(){ console.log("函数a"); }
// '函数a'
// '变量a'
// a is not a function

// 栗子预编后相当于:
function a(){
    console.log("函数a");
};
var d;
console.log(a);  // ƒ a(){ console.log("函数a"); }
a();              // '函数a'

a = "变量a";     // 此时变量a赋值,函数申明被笼罩

console.log(a); // "变量a"
a();         // a is not a function

复制代码

那么问题来了。 请问是谁来执行预编译操作的?那这个谁又是在哪里进行预编译的?

是的,你的纳闷没有错。js代码运行须要一个运行环境,那这个环境就是执行上下文。 是的,js运行前的预编译也是在这个环境中进行。

js执行上下文分三种:

  • 全局执行上下文: 代码开始执行时首先进入的环境。
  • 函数执行上下文:函数调用时,会开始执行函数中的代码。
  • eval执行上下文:不倡议应用,可疏忽。

那么,执行上下文的周期,分为两个阶段:

  • 创立阶段

    • 创立词法环境
    • 生成变量对象(VO),建设作用域链作用域链作用域链(重要的事说三遍)
    • 确认this指向,并绑定this
  • 执行阶段。这个阶段进行变量赋值,函数援用及执行代码。

你当初猜猜看,预编译是产生在什么时候?

噢,我遗记说了,其实与编译还有另一个称说:执行期上下文

预编译产生在函数执行之前。预编译四部曲为:

  1. 创立AO对象
  2. 找形参和变量申明,将变量和形参作为AO属性名,值为undefined
  3. 将实参和形参相对立
  4. 在函数体里找到函数申明,值赋予函数体。最初程序输入变量值的时候,就是从AO对象中拿。

所以,预编译真正的后果是:

var AO = {
    a = function a(){console.log("函数a");};
    d = 'abc'
}
复制代码

咱们从新来。

1. 什么叫变量对象?

变量对象是 js 代码在进入执行上下文时,js 引擎在内存中建设的一个对象,用来寄存以后执行环境中的变量。

2. 变量对象(VO)的创立过程

变量对象的创立,是在执行上下文创立阶段,顺次通过以下三个过程:

  • 创立 arguments 对象。

    对于函数执行环境,首先查问是否有传入的实参,如果有,则会将参数名是实参值组成的键值对放入arguments 对象中。否则,将参数名和 undefined组成的键值对放入 arguments 对象中。

//举个栗子 
function bar(a, b, c) {
    console.log(arguments);  // [1, 2]
    console.log(arguments[2]); // undefined
}
bar(1,2)
复制代码
  • 当遇到同名的函数时,前面的会笼罩后面的。
console.log(a); // function a() {console.log('Is a ?') }
function a() {
    console.log('Is a');
}
function a() {
  console.log('Is a ?')
}

/**ps: 在执行第一行代码之前,函数申明曾经创立实现.前面的对之前的申明进行了笼罩。**/
复制代码
  • 查看以后环境中的变量申明并赋值为undefined。当遇到同名的函数申明,为了防止函数被赋值为 undefined ,会疏忽此申明
console.log(a); // function a() {console.log('Is a ?') }
console.log(b); // undefined
function a() {
  console.log('Is a ');
}
function a() {
console.log('Is a ?');
}
var b = 'Is b';
var a = 10086;

/**这段代码执行一下,你会发现 a 打印后果仍旧是一个函数,而 b 则是 undefined。**/
复制代码

依据以上三个步骤,对于变量晋升也就晓得是怎么回事了。

3. 变量对象变为流动对象

执行上下文的第二个阶段,称为执行阶段,在此时,会进行变量赋值,函数援用并执行其余代码,此时,变量对象变为流动对象。

咱们还是举下面的例子:

console.log(a); // function a() {console.log('fjdsfs') }
console.log(b); // undefined
function a() {
   console.log('Is a');
}
function a() {
 console.log('Is a?');
}
var b = 'Is b';
console.log(b); // 'Is b'
var a = 10086; 
console.log(a);  // 10086
var b = 'Is b?';
console.log(b); // 'Is b?'
复制代码

在下面的代码中,代码真正开始执行是从第一行 console.log() 开始的,自这之前,执行上下文是这样的:

// 创立过程
EC= {
  VO: {}; // 创立变量对象
  scopeChain: {}; // 作用域链
}
VO = {
  argument: {...}; // 以后为全局上下文,所以这个属性值是空的
  a: <a reference> // 函数 a  的援用地址  b: undefiend  // 见上文创立变量对象的第三步}

复制代码
词法作用域(Lexical scope

这里想阐明,咱们在函数执行上下文中有变量,在全局执行上下文中有变量。JavaScript的一个简单之处在于它如何查找变量,如果在函数执行上下文中找不到变量,它将在调用上下文中寻找它,如果在它的调用上下文中没有找到,就始终往上一级,直到它在全局执行上下文中查找为止。(如果最初找不到,它就是 undefined)。

再来举个栗子:

 1: let top = 0; // 
 2: function createWarp() {
 3:   function add(a, b) {
 4:     let ret = a + b
 5:     return ret
 6:   }
 7:   return add
 8: }
 9: let sum = createWarp()
10: let result = sum(top, 8)
11: console.log('result:',result)


复制代码

剖析过程如下:

  • 在全局上下文中申明变量top 并赋值为0.
  • 2 – 8行。在全局执行上下文中申明了一个名为 createWarp 的变量,并为其调配了一个函数定义。其中第3-7行形容了其函数定义,并将函数定义存储到那个变量(createWarp)中。
  • 第9行。咱们在全局执行上下文中申明了一个名为 sum 的新变量,临时,值为 undefined
  • 第9行。遇到(),表明须要执行或调用一个函数。那么查找全局执行上下文的内存并查找名为 createWarp 的变量。 显著,曾经在步骤2中创立结束。接着,调用它。
  • 调用函数时,回到第2行。创立一个新的createWarp执行上下文。咱们能够在 createWarp 的执行上下文中创立自有变量。js 引擎createWarp 的上下文增加到调用堆栈(call stack)。因为这个函数没有参数,间接跳到它的主体局部.
  • 3 – 6 行。咱们有一个新的函数申明,createWarp执行上下文中创立一个变量 addadd 只存在于 createWarp 执行上下文中, 其函数定义存储在名为 add 的自有变量中。
  • 第7行,咱们返回变量 add 的内容。js引擎查找一个名为 add 的变量并找到它. 第4行和第5行括号之间的内容形成该函数定义。
  • createWarp 调用结束,createWarp 执行上下文将被销毁。add 变量也跟着被销毁。add 函数定义依然存在,因为它返回并赋值给了 sum 变量。 (ps: 这才是闭包产生的变量存于内存当中的假相
  • 接下来就是简略的执行过程,不再赘述。。
  • ……
  • 代码执行结束,全局执行上下文被销毁。sum 和 result 也跟着被销毁。

小结一下

当初,如果再让你答复什么是闭包,你能答出多少?

其实,大家说的都对。不论是函数返回一个函数,还是产生了内部作用域的援用,都是有情理的。

所以,什么是闭包?

  • 解释一下作用域链是如何产生的。
  • 解释一下js执行上下文的创立、执行过程。
  • 解释一下闭包所产生的变量放在哪了。
  • 最初请把以上3点联合起来说给面试官听。

深拷贝浅拷贝

浅拷贝:浅拷贝通过ES6新个性Object.assign()或者通过扩大运算法...来达到浅拷贝的目标,浅拷贝批改
正本,不会影响原数据,但毛病是浅拷贝只能拷贝第一层的数据,且都是值类型数据,如果有援用型数据,批改
正本会影响原数据。

深拷贝:通过利用JSON.parse(JSON.stringify())来实现深拷贝的目标,但利用JSON拷贝也是有毛病的,
当要拷贝的数据中含有undefined/function/symbol类型是无奈进行拷贝的,当然咱们想我的项目开发中须要
深拷贝的数据个别不会含有以上三种类型,如有须要能够本人在封装一个函数来实现。
复制代码

说一下你对盒模型的了解?

CSS3中的盒模型有以下两种:规范盒模型、IE盒模型
盒模型都是由四个局部组成的,别离是margin、border、padding和content
规范盒模型和IE盒模型的区别在于设置width和height时, 所对应的范畴不同
1、规范盒模型的width和height属性的范畴只蕴含了content
2、IE盒模型的width和height属性的范畴蕴含了border、padding和content
能够通过批改元素的box-sizing属性来扭转元素的盒模型;
1、box-sizing:content-box示意规范盒模型(默认值)
2、box-sizing:border-box示意IE盒模型(怪异盒模型)
复制代码

CDN的作用

CDN个别会用来托管Web资源(包含文本、图片和脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。应用CDN来减速这些资源的拜访。

(1)在性能方面,引入CDN的作用在于:

  • 用户收到的内容来自最近的数据中心,提早更低,内容加载更快
  • 局部资源申请调配给了CDN,缩小了服务器的负载

(2)在平安方面,CDN有助于进攻DDoS、MITM等网络攻击:

  • 针对DDoS:通过监控剖析异样流量,限度其申请频率
  • 针对MITM:从源服务器到 CDN 节点到 ISP(Internet Service Provider),全链路 HTTPS 通信

除此之外,CDN作为一种根底的云服务,同样具备资源托管、按需扩大(可能应答流量顶峰)等方面的劣势。

代码输入后果

Promise.resolve().then(() => {
  return new Error('error!!!')
}).then(res => {
  console.log("then: ", res)
}).catch(err => {
  console.log("catch: ", err)
})
复制代码

输入后果如下:

"then: " "Error: error!!!"
复制代码

返回任意一个非 promise 的值都会被包裹成 promise 对象,因而这里的return new Error('error!!!')也被包裹成了return Promise.resolve(new Error('error!!!')),因而它会被then捕捉而不是catch。

Vuex有哪些根本属性?为什么 Vuex 的 mutation 中不能做异步操作?

有五种,别离是 State、 Getter、Mutation 、Action、 Module
1、state => 根本数据(数据源寄存地)
2、getters => 从根本数据派生进去的数据
3、mutations => 提交更改数据的办法,同步
4、actions => 像一个装璜器,包裹mutations,使之能够异步。
5、modules => 模块化Vuex

1、Vuex中所有的状态更新的惟一路径都是mutation,异步操作通过 Action 来提交 mutation实现,这样能够不便地跟踪每一个状态的变动,从而可能实现一些工具帮忙更好地理解咱们的利用。
2、每个mutation执行实现后都会对应到一个新的状态变更,这样devtools就能够打个快照存下来,而后就能够实现 time-travel 了。如果mutation反对异步操作,就没有方法晓得状态是何时更新的,无奈很好的进行状态的追踪,给调试带来艰难。
复制代码

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理