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

37次阅读

共计 10735 个字符,预计需要花费 27 分钟才能阅读完成。

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 反对异步操作,就没有方法晓得状态是何时更新的,无奈很好的进行状态的追踪,给调试带来艰难。复制代码

正文完
 0