2018 – 2019 年前端 JavaScript 面试题
JavaScript 基础问题
1.使以下代码正常运行:
JavaScript 代码:const a = [1, 2, 3, 4, 5];// Implement this a.multiply();console.log(a); // [1, 2, 3, 4, 5, 1, 4, 9, 16, 25]
2.以下代码在 JavaScript 中返回 false
。 解释一下为什么会这样:
JavaScript 代码: // false0.2 + 0.1 === 0.3
3.JavaScript 中有哪些不同的数据类型?
提示:只有两种类型 – 主要数据类型和引用类型(对象)。 有 6 种主要类型。
4.解决以下异步代码问题。
检索并计算属于同一教室中每个学生的平均分数,其中一些ID为75。每个学生可以在一年内参加一门或多门课程。 以下 API 可用于检索所需数据。
JavaScript 代码:// GET LIST OF ALL THE STUDENTSGET /api/studentsResponse:[{"id": 1,"name": "John","classroomId": 75}]// GET COURSES FOR GIVEN A STUDENTGET /api/courses?filter=studentId eq 1Response:[{"id": "history","studentId": 1}, {"id": "algebra","studentId": 1},]// GET EVALUATION FOR EACH COURSEGET /api/evaluation/history?filter=studentId eq 1 Response:{"id": 200,"score": 50,"totalScore": 100}
编写一个接受教室 ID 的函数,您将根据该函数计算该教室中每个学生的平均值。该函数的最终输出应该是具有平均分数的学生列表:
JavaScript 代码:[{ "id": 1, "name": "John", "average": 70.5 },{ "id": 3, "name": "Lois", "average": 67 },]
使用普通的 callbacks ,promises ,observables,generator 或 async-wait 编写所需的函数。尝试使用至少 3 种不同的技术解决这个问题。
5.使用 JavaScript Proxy 实现简单的数据绑定
提示:ES Proxy 允许您拦截对任何对象属性或方法的调用。首先,每当更改底层绑定对象时,都应更新 DOM 。
6.解释 JavaScript 并发模型
您是否熟悉 Elixir,Clojure,Java 等其他编程语言中使用的任何其他并发模型?
提示:查找事件循环,任务队列,调用栈,堆等。
7.new
关键字在 JavaScript 中有什么作用?
提示:在 JavaScript 中,new
是用于实例化对象的运算符。 这里的目的是了解知识广度和记忆情况。
另外,请注意 [[Construct]]
和 [[Call]]
。
8.JavaScript 中有哪些不同的函数调用模式? 详细解释。
提示:有四种模式,函数调用,方法调用,.call()
和 .apply()
。
9.解释任一即将发布新的 ECMAScript 提案。
提示:比如 2018 的 BigInt,partial 函数,pipeline 操作符 等。
10.JavaScript 中的迭代器(iterators)和迭代(iterables)是什么? 你知道什么是内置迭代器吗?
11.为什么 JavaScript classes(类)被认为是坏的或反模式?
这是一个神话吗?它是否遭受了误传?是否有一些有用的用例?
12.如何在 JSON 中序列化以下对象?
如果我们将以下对象转换为 JSON 字符串,会发生什么?
JavaScript 代码:const a = {key1: Symbol(),key2: 10}// What will happen?console.log(JSON.stringify(a));
13.你熟悉 Typed Arrays 吗? 如果熟悉,请解释他们与 JavaScript 中的传统数组相比的异同?
Arrays
ES6对数组添加了一些新的方法,另外还添加了TypedArray类型,这种类型支持对内存的操作,ArrayBuffer
和C语言内存分配一样,分配一块内存块。下面从以下几个方面来看看ES6数组的变化:
- 2个静态方法
Array.of()
,Array.from()
; - 数组原型上新添加的方法
find()
,findIndex()
,fill()
,copyWithin()
; - 新类型
ArrayBuffer
; - Typed Arrays, 以及和Array的相同性,差异性
一.Array.of() & Array.from()
1.Array.of()
ES6新添加了这个静态方法,用于数组构造器实例化数组。我们知道数组实例化一般可以通过构造器或者数组字面量的形式来声明。ES5通过构造器声明数组会出现一个比较模糊的地方,比如:
var arr = new Array(1, 2, 3); // 表示声明一个数组元素为[1, 2, 3]的数组 arr.length; // 3 arr[0]; // 1 arr[1]; // 2 arr[2]; // 3var arr = new Array(2); // 2表示长度 // 而这样则表示一个数组长度为2的数组,而数组元素未声明 arr.length; // 2 arr; // [undefined, undefined]
而Array.of()
则消除了这种模糊,凡是向方法中添加数字,都表示数组元素,而不是长度
var arr = Array.of(1, 2); arr; // [1, 2]var arr = Array.of(2); // 2表示元素 arr; // [2]
2.Array.from()
ES6之前要将一个array-like
对象转换成数组,我们一般是利用slice
方法,比如
function doSomething() {// 将arguments类数组对象转换成数组var args = Array.prototype.slice.call(arguments);// 或者 [].slice.call(arguments)// ... }
ES6通过静态方法 Array.from()
可以将 类数组对象 或者 可迭代的对象 转换成一个数组,其语法为:
Array.from(arraylike[, callback] [, thisArg])
上面的例子可以写为:
function doSomething() {var args = Array.from(arguments);// ... }
将可迭代的对象转变为数组:
var set = new Set([1, 2, 2, 4, 5]); // Set {1, 2, 4, 5} var arr = Array.from(set); // [1, 2, 4, 5]
后面添加回调函数, 如果回调函数属于一个对象, 则可以添加第3个可选参数,指出this
上下文:
let helper = {diff: 1,add(value) {return value + this.diff;} }function translate() {// 第2个参数为callback, 第3个参数为上下文return Array.from(arguments, helper.add, helper); }translate(1, 2, 3); // [2, 3, 4]
二.新添加的方法
1.find(),findIndex()
以前我们查看数组中是否存在某个值或者某个值的位置时,一般使用indexOf()
, lastIndexOf()
,ES6添加了find(), findIndex()来添加条件查找。这两个方法和map(),forEach()一样添加一个回调函数,有选择性的添加thisArg
指定上下文。
find找到了就返回第一个满足条件的,未找到返回undefined, findIndex返回索引位置,未找到返回 -1:
var arr = [1, 2, 19, 16]; arr.find(v => v > 10 ); // 返回 19 arr.findIndex(v => v > 10); // 返回 2
find(), findIndex()用于查找一个数组元素满足某个条件而不是值,要根据值查找建议使用indexOf(), lastIndexOf().
2.fill(), copyWithin()
这两个方法其实为了操作Typed Array对象使用的,但是为了保持一致性,也添加给普通数组了。看下语法:
fill(value[,startFillPostion = 0 ] [, endFillPostion = arr.length])copyWithin(StartToBeCopiedPos[,StartCopyPos = 0] [,EndCopyPos = arr.length])
先看fill:
var arr = [1, 2, 3, 4];// 不指定开始和结束填充的位置 arr.fill(5); // arr: [5, 5, 5, 5]// 指定开始 arr.fill(5, 2); // arr: [1, 2, 5, 5]// 都指定,不包含结束位置 arr.fill(5, 0, 2)// arr: [5, 5, 3, 4]// 当然起始和结尾也可以为负数,相当于加上数组长度 arr.fill(5, -3); // arr: [1, 5, 5, 5] // 相当于 arr.fill(5, -3+4)
copyWith: 比较绕, 它是指复制自身内容到指定的位置:
var arr = [1, 10, 15, 29, 18];// 只有一个参数表示被复制的索引,另外2个参数则默认从0开始到结束 arr.copyWithin(2); // arr [1, 10, 1, 10, 15]// 2个参数,指定自身复制的位置 arr.copyWithin(3, 1); // arr [1, 10, 15, 10, 15]// 3个参数都指定 arr.copyWithin(2, 0, 1); // arr [1, 10, 1, 29, 18] // 0-1只有一个数 "1", 所有索引位置为2的 "15" 被替换成 "1"
上面例子我们可以发现,是有这些方法都会改变数组自身
三.ArrayBuffer
AarryBuffer是指分配内存中的一块位置用于操作,相当于C语言中的malloc(),对内存块进行二进制操作,会极大的提升性能,满足一些特别的接口要求。
先了解一下内存分配的基本语法:
var buffer = new ArrayBuffer(bytes);
比如:分配10个字节(byte)
var buffer = new ArrayBuffer(10);
内存的大小确定之后是不能修改的,可以改变内部内容
属性: byteLength
, slice()
slice方法是从已经存在的内存块中复制一段,添加都新的内存块中
var buffer = new ArrayBuffer(10); var buffer2 = buffer.slice(3, 5); // 将buffer中的3, 4字节内容拷贝到新的内存块中console.log(buffer2.byteLength); // 2
四.TypedArray, Views视图
光有内存块,而不进行操作也是没有用的,javascript通过视图的方式对内存块进行读写,存在两种视图:
- TypedArray: 特定类型的数据类型,特定类型的一种视图,对特定类型操作性能更高;
- DataView: 各种数据类型都可以,还可以指定大端序(BIG_ENDIAN),小端序(LITTLE_ENDIAN),功能更强大的一种视图
1.共同属性
这两种视图拥有一些共同的属性:
2.DataView
DataView构造器能够添加三个参数:new DataView(buffer[, byteOffset][, byteLength])
var buffer = new ArrayBuffer(10); // 指向整个内存块 var dataView1 = new DataView(buffer); dataView1.buffer === buffer; // true dataView1.byteOffset; // 0 dataView1.byteLength; // 10// 表示 字节 5, 6上的视图 var dataView2 = new DataView(buffer, 5, 2); dataView2.buffer === buffer; // true dataView2.byteOffset; // 5 dataView2.byteLength; // 2
3.TypedArray
TypedArray本质上是一个抽象类,他表示9中特定类型: Int8Array
, Uint8Array
, Int16Array
, Uint16Array
, Int32Array
, Uint32Array
, Float32Array
,Float64Array
,还有一种只针对Canvas颜色值的 Uint8ClampedArray
14. 默认参数是如何工作?
如果我们在调用 makeAPIRequest
函数时必须使用 timeout
的默认值,那么正确的语法是什么?
function makeAPIRequest(url, timeout = 2000, headers) {// Some code to fetch data}
15.解释 TCO – 尾调用优化(Tail Call Optimization)。 有没有支持尾调用优化的 JavaScript 引擎?
提示:截至 2018 年,没有。
JavaScript 前端应用设计问题
1.解释单向数据流和双向数据绑定。
Angular 1.x 基于双向数据绑定,而 React,Vue,Elm 等基于单向数据流架构。
单向数据绑定
单向数据绑定,带来单向数据流。。
指的是我们先把模板写好,然后把模板和数据(数据可能来自后台)整合到一起形成HTML代码,然后把这段HTML代码插入到文档流里面。适用于整体项目,并于追溯。
优点:
1. 所有状态的改变可记录、可跟踪,源头易追溯;
2. 所有数据只有一份,组件数据只有唯一的入口和出口,使得程序更直观更容易理解,有利于应用的可维护性;
3. 一旦数据变化,就去更新页面(data-页面),但是没有(页面-data);
4. 如果用户在页面上做了变动,那么就手动收集起来(双向是自动),合并到原有的数据中。
方神:双向绑定 = 单向绑定 + UI事件监听,可了解vuex
缺点:
1. HTML代码渲染完成,无法改变,有新数据,就须把旧HTML代码去掉,整合新数据和模板重新渲染;
2. 代码量上升,数据流转过程变长,出现很多类似的样板代码;
3. 同时由于对应用状态独立管理的严格要求(单一的全局store),在处理局部状态较多的场景时(如用户输入交互较多的“富表单型”应用),会显得啰嗦及繁琐。
双向数据绑定
双向数据绑定,带来双向数据流。AngularJS2添加了单向数据绑定
数据模型(Module)和视图(View)之间的双向绑定。无论数据改变,或是用户操作,都能带来互相的变动,自动更新。适用于项目细节,如:UI控件中(通常是类表单操作)。
优点:
1. 用户在视图上的修改会自动同步到数据模型中去,数据模型中值的变化也会立刻同步到视图中去;
2. 无需进行和单向数据绑定的那些CRUD(Create,Retrieve,Update,Delete)操作;
3. 在表单交互较多的场景下,会简化大量业务无关的代码。
缺点:
1. 无法追踪局部状态的变化;
2. “暗箱操作”,增加了出错时 debug 的难度;
3. 由于组件数据变化来源入口变得可能不止一个,数据流转方向易紊乱,若再缺乏“管制”手段,血崩。
双向数据绑定,Angular使用 脏检查“digest” - “dirty checking”
(在angular中,他没有办法判断你的数据是否做了更改, 所以它设置了一些条件,当你触发了这些条件之后,它就执行一个检测来遍历所有的数据,对比你更改了地方,然后执行变化。这个检查很不科学。而且效率不高,有很多多余的地方,所以官方称为脏检查)
2.单向数据流架构在哪些方面适合 MVC?
MVC 拥有大约 50 年的悠久历史,并已演变为 MVP,MVVM 和 MV *。两者之间的相互关系是什么?如果 MVC 是架构模式,那么单向数据流是什么?这些竞争模式是否能解决同样的问题?
3.客户端 MVC 与服务器端或经典 MVC 有何不同?
提示:经典 MVC 是适用于桌面应用程序的 Smalltalk MVC。在 Web 应用中,至少有两个不同的数据 MVC 周期。
4.使函数式编程与面向对象或命令式编程不同的关键因素是什么?
提示:Currying(柯里化),point-free 函数,partial 函数应用,高阶函数,纯函数,独立副作用,record 类型(联合,代数数据类型)等。
5.在 JavaScript 和前端的上下文中,函数式编程与响应式编程有什么关系?
提示:没有正确答案。但粗略地说,函数式编程是关于小型编码,编写纯函数和响应式编程是大型编码,即模块之间的数据流,连接以 FP 风格编写的组件。 FRP – 功能响应式编程( Functional Reactive Programming)是另一个不同但相关的概念。
6.不可变数据结构(immutable data structures)解决了哪些问题?
不可变结构是否有任何性能影响? JS 生态系统中哪些库提供了不可变的数据结构?这些库的优点和缺点是什么?
提示:线程安全(我们真的需要在浏览器 JavaScript 中担心吗?),无副作用的函数,更好的状态管理等。
7.大型应用程序是否应使用静态类型?
- 如何比较 TypeScript/Flow 与 Elm/ReasonML/PureScript 等 JS 转换语言?这些方法的优缺点是什么?
- 选择特定类型系统的主要标准应该是什么?
- 什么是类型推断(type inference)?
- 静态类型语言和强类型语言有什么区别?在这方面 JavaScript 的本质是什么?
- 有你知道的弱类型但静态类型的语言吗?有你知道的动态类型但强类型的语言吗?举例一二。
提示:Structural 与 Nominal 类型系统,类型稳健性,工具/生态系统支持,正确性超过方便。
8.JavaScript 中有哪些杰出的模块系统(module systems )?如何评价 ES 模块系统。
列出在实现不同模块系统之间互操作所涉及的一些复杂性问题(主要对 ES 模块和 CommonJS 互操作感兴趣)
9.HTTP/2 将如何影响 JavaScript 应用程序打包?
列出 HTTP/2 与其上一个版本的基本区别。
10.Fetch API 相对于传统的 Ajax 有哪些改进?
- 使用 Fetch API 有那些缺点/难点吗?
- 哪些是Ajax 可以做的,而 fetch 不能做的?
11.如何评论 pull-based 和 push-based 的反应系统。
讨论概念,含义,用途等。
- 在这个讨论中加入惰性和及早求值。
- 然后在讨论中添加单数和复数值维度。
- 最后,讨论值解析的同步和异步性质。
- 为JavaScript中可用的每个组合提供示例。
提示:Observable 是惰性的,基于推送的复数值构造,同时具有 async/sync 调度程序。
12.讨论与 Promise 相关的问题。
提示:及早求值(eager evaluation),尴尬的取消机制,用 then()
方法伪装 map()
和 flatMap()
等。
前端基础和理论问题
1.HTML 中 Doctype 的用途是什么?
具体谈谈,以下每种情况下会发生什么:
- Doctype 不存在。
- 使用了 HTML4 Doctype,但 HTML 页面使用了 HTML5 的标签,如
或
。它会导致任何错误吗?
- 使用了无效的 Doctype。
2. DOM 和 BOM 的区别是什么?
提示:BOM,DOM,ECMAScript 和 JavaScript 都是不同的东西。
3.JavaScript 中的事件处理如何运行?
如下图所示,我们有三个 div 元素。每个 div 都有一个与之关联的点击处理程序。处理程序执行以下任务:
编写一段代码来分配这些任务,以便在单击 innermost div 时始终打印以下序列?
hello inner
→ hello innermost
→ hello outer
提示:事件捕获和事件冒泡
4.使用单页应用将文件上传到服务器的有哪些方法?
提示:XMLHttpRequest2(streaming),fetch(non-streaming),File API
5.CSS 重排和重绘之间有什么区别?
哪些 CSS 属性会导致重排及重绘?
6. 什么是 CSS 选择器权重以及它如何工作?
说说计算 CSS 选择器权重的算法。
7.CSS 中的 pixel 与硬件/物理中的 pixel 有何不同?
提示:像素不是像素不是像素 – ppk。
8.什么是 sectioning 算法?
提示:它也被称为 HTML5 大纲算法。特别是在构建具有语义结构的网站时非常重要。
9.如果你用过 CSS Flex / CSS Grid(网格)布局,请说明你为什么要使用它?它为你解决了什么问题?
提示:等高的列,垂直居中,复杂网格等。
10.什么时候应该使用 CSS animations 而不是 CSS transitions ?你做出这个决定标准是什么?
11.如果你正在 Review CSS 代码,那么你在代码中经常遇到的问题是什么?
示例:使用魔性数字,如 width: 67px;
或使用 em
代替 rem
单位,在通用代码之前编写 media queries(媒体查询),滥用 ID 和类等。
12.如何在 JavaScript 中检测触摸事件?
- 你是否不看好检测设备对触摸事件的支持?如果是,为什么?
- 比较触摸事件和点击事件。
- 当设备同时支持触摸和鼠标事件时,你认为这些事件的正确事件顺序是什么或应该是什么?
13.为 script 标签定义的 async
和 defer
属性有什么用?
列出的清单只是我们在面试中可能讨论的无限点的一瞥。Web Components,CORS,安全性,Cookies,CSS transform,Web Assembly,Service Workers,PWA,CSS架构等,还有许多我们没有考虑到的东西。我们也没有涉及框架或库的具体问题。
转载于:https://www.cnblogs.com/amujoe/p/11176277.html
标签:
相关文章
-
无相关信息