[前端面筋]旺旺的飞书一面

841 阅读13分钟

以下内容部分属实,多数虚构,切勿代入

旺旺的弔技术栈太多了,部分涉及后端我就不记录了

1.你这么弔,为什么要做前端

旺旺:工程化。框架不成熟,希望能在这里有突破...............(大概意思就说自己对哪个方向感兴趣)

2.怎么接触那么多弔项目

创业弔项目

社团的弔项目

学校的弔项目

校外的弔外包

3.怎么接触弔前端的,为什么会懂后端

弔电协里面一堆弔人卷我

做弔项目时候 前端tmd太憋屈了我tm直接自己写后端好吧

4.关于函数柯里化

边有思路可以边和面试官交流。然后不要纠结太久

以下对话纯属虚构,萝莉王本人做题时候一下子就出来了,根本不需要讨论

(1)Currying有哪些好处呢?

​ 函数复用,提前确认,延迟执行

(2)实现一个add(1)(2)(3)(4)

涉及到知识点:函数的隐式转化,柯里化,闭包

​ 这道题,我们一步一步来思考🤔把add函数的x,y两个参数变成了先用一个函数接收x然后返回一个函数去处理y参数。现在思路应该就比较清晰了,就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。。。。所以初步的思路是这亚子滴!

function add(x) {
    return function (y) {
        return x + y
    }
    ........
}

面试官:那如果我要addadd(1)(2)(3)(4)......那你这边不够对吧.... 旺旺:那简单,我tm直接

function add(num){
	var sum=num
	return temp=function(numB){
		sum+=numB
		return temp
	}
}

面试官:你确定你这个东西是可以输出正确结果的吗?你看看控制台,输出的是字符串而不是数字

image-20210603232941060

旺旺:哦哦,那我➕一个条件判断。然后调用时候是这样子的,add(2)(3)(4)(5)()

function add(num){
	var sum=num
	return temp=function(numB){
		if(numB){
		sum+=numB
		return temp
		}
		else
			return sum
	}
}

面试官:这样确实可行,但有没有优雅的写法呢?

旺旺:那.....这样子你看看,利用JS中对象到原始值的转换规则来实现 面试官:简单介绍一下?

旺旺:当一个对象转换成原始值时,先查看对象是否有valueOf方法,如果有并且返回值是一个原始值, 那么直接返回这个值,否则没有valueOf或返回的不是原始值,那么调用toString方法,返回字符串表示

function add(num){
	//闭包
	var tmp = function (y) {
        sum = sum + y;
        return tmp;
    };
    tmp.toString = function () {
        return sum;
    };
    return tmp;
}
}

image-20210603234719771

补充:👇解法是网上其他面试者【 追求极致 】写的

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(...arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

5.JavaScript垃圾回收

6.前端基础知识「bfc」

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

形成 BFC 的条件

五种: 浮动元素,float 除 none 以外的值 定位元素,position(absolute,fixed) display 为以下其中之一的值 inline-block,table-cell,table-caption overflow 除了 visible 以外的值(hidden,auto,scroll) HTML 就是一个 BFC

BFC 的特性

内部的 Box 会在垂直方向上一个接一个的放置。 垂直方向上的距离由 margin 决定 bfc 的区域不会与 float 的元素区域重叠。 计算 bfc 的高度时,浮动元素也参与计算 bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。

利用BFC让浮动内容和周围的内容等高

来自于BFC

为了更好的理解BFC,我们先看看下面这些。

在下面的例子中,我们让 <div> 元素浮动,并给它一个边框效果。<div> 里的内容现在已经在浮动元素周围浮动起来了。由于浮动的元素比它旁边的元素高,所以 <div> 的边框穿出了浮动。正如我们在这篇文章中 guide to in-flow and out of flow elements 解释的,浮动脱离了文档流,所以 <div>backgroundborder 仅仅包含了内容,不包含浮动。

使用overflow: auto

创建一个会包含这个浮动的 BFC,通常的做法是设置父元素 overflow: auto 或者设置其他的非默认的 overflow: visible 的值。

设置 overflow: auto 创建一个新的BFC来包含这个浮动。我们的 <div> 元素现在变成布局中的迷你布局。任何子元素都会被包含进去。

使用 overflow 来创建一个新的 BFC,是因为 overflow 属性告诉浏览器你想要怎样处理溢出的内容。当你使用这个属性只是为了创建 BFC 的时候,你可能会发现一些不想要的问题,比如滚动条或者一些剪切的阴影,需要注意。另外,对于后续的开发,可能不是很清楚当时为什么使用 overflow。所以你最好添加一些注释来解释为什么这样做。

使用display: flow-root

display:flow-root属性是css新增的属性,专门用来触发BFC,不干别的

一个新的 display 属性的值,它可以创建无副作用的 BFC。在父级块中使用 display: flow-root 可以创建新的 BFC。

<div> display: flow-root 属性后,<div> 中的所有内容都会参与 BFC,浮动的内容不会从底部溢出。

关于值 flow-root的这个名字,当你明白你实际上是在创建一个行为类似于根元素 (浏览器中的<html>元素) 的东西时,就能发现这个名字的意义了——即创建一个上下文,里面将进行 flow layout。

7.webpack 的 tree-shaking

文章部分内容摘自:百度外卖大前端

概念

面试官:简单说一下什么是 tree-shaking

旺旺:

App往往有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝。实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过Tree shaking,将没有使用的模块摇掉,这样来达到删除无用代码的目的。

Tree-shaking的本质是消除无用的js代码。无用代码消除在广泛存在于传统的编程语言编译器中,编译器可以判断出某些代码根本不影响输出,然后消除这些代码,这个称之为DCE(dead code elimination)。 因为ES6模块的出现,ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析, 这就是Tree shaking的基础。

Tree-shaking 是 DCE 的一种新的实现,Javascript同传统的编程语言不同的是,javascript绝大多数情况需要通过网络进行加载,然后执行,加载的文件大小越小,整体执行时间更短,所以去除无用代码以减少文件体积,对javascript来说更有意义。

Tree-shaking 和传统的 DCE的方法又不太一样,传统的DCE 消灭不可能执行的代码,而Tree-shaking 更关注于消除没有用到的代码

大概原理

面试官:说下具体原理,为什么刚才你说es6 module是其实现的基础

传统编译型的语言中,都是由编译器将Dead Code从AST(抽象语法树)中删除,在送到浏览器之前的步骤用代码压缩工具uglify工具进行优化。

ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,这就是tree-shaking的基础。

所谓静态分析就是不执行代码,从字面量上对代码进行分析,ES6之前的模块化,比如我们可以动态require一个模块,只有执行后才知道引用的什么模块,这个就不能通过静态分析去做优化。

这是 ES6 modules 在设计时的一个重要考量,也是为什么没有直接采用 CommonJS,正是基于这个基础上,才使得 tree-shaking 成为可能,这也是为什么 rollup 和 webpack 2 都要用 ES6 module syntax 才能 tree-shaking。

8.浏览器渲染页面过程

面试官:简单说下

​ 旺旺:

浏览器将HTML,CSS,JavaScript代码转换成屏幕上所能呈现的实际像素,这期间所经历的一系列步骤,叫做关键渲染路径(Critical Rendering Path)。其中包含:

  • 构建对象模型(DOM,CSSOM)
  • 构建渲染树(RenderTree)
  • 布局
  • 渲染

image-20210604010909748

面试官:那图片会不会阻塞浏览器渲染

解析遇到link、script、img标签时,浏览器会向服务器发送请求资源。 script的加载或者执行都会阻塞html解析、其他下载线程以及渲染线程。 link加载完css后会解析为CSSOM(层叠样式表对象模型,一棵仅含有样式信息的树)。css的加载和解析不会阻塞html的解析,但会阻塞渲染。 img的加载不会阻塞html的解析,但img加载后并不渲染,它需要等待Render Tree生成完后才和Render Tree一起渲染出来。未下载完的图片需等下载完后才渲染。

9.Java script的闭包

问烂了,不想写

10.display none会不会进入渲染流程

面试官:既然你不知道我就大发慈悲告诉你,会进入dom🌲,但不会进入渲染树🌲

11.will-change

CSS 属性 will-change 为web开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。 这种优化可以将一部分复杂的计算工作提前准备好,使页面的反应更为快速灵敏。

面试官:这东西是怎么运作的?

样式表中直接添加了 will-change 属性,会导致浏览器将对应的优化工作一直保存在内存中

面试官:应用场景举两个例子

某个应用在按下键盘的时候会翻页,比如相册或者幻灯片一类的,它的页面很大很复杂,此时在样式表中写上 will-change 是合适的。这会使浏览器提前准备好过渡动画,当键盘按下的时候就能立即看到灵活轻快的动画。

例子一

.slide {
  will-change: transform;
}

例子二

var el = document.getElementById('element');

// 当鼠标移动到该元素上时给该元素设置 will-change 属性
el.addEventListener('mouseenter', hintBrowser);
// 当 CSS 动画结束后清除 will-change 属性
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
  // 绑定你想看到的样式内容
  this.style.willChange = 'transform, opacity';
}

function removeHint() {
  this.style.willChange = 'auto';
}

12.http和https的区别

13.https是怎么加密的

14.对称加密 为什么不行 ,什么时候对称加密,什么时候非对称加密

15.http2.0说说呗

16.(微任务 宏任务

给段弔代码 然后让你猜测结果

async  function  async1 ()  {    console.log('async1 start');    await  async2();    console.log('async1 end')}async  function  async2 ()  {    console.log('async2')}console.log('script start');setTimeout(function ()  {    console.log('setTimeout')},  0);async1();new  Promise(function (resolve)  {    console.log('promise1');    resolve()}).then(function ()  {    console.log('promise2')});console.log('script end')

image-20210604014440681

17.对路由的了解

  1. 后端路由
  2. 前端路由

后端路由又可称之为服务器端路由,因为对于服务器来说,当接收到客户端发来的HTTP请求,就会根据所请求的相应URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。对于最简单的静态资源服务器,可以认为,所有URL的映射函数就是一个文件读取操作。对于动态资源,映射函数可能是一个数据库读取操作,也可能是进行一些数据的处理,等等。然后根据这些读取的数据,在服务器端就使用相应的模板来对页面进行渲染后,再返回渲染完毕的页面。这种方式在早期的前端开发中非常普遍,它的好处与坏处都很明显:

  • 好处:安全性好,h好。
  • 缺点:加大服务器的压力,不利于用户体验,代码冗合。

对于前端路由来说,路由的映射函数通常是进行一些DOM的显示和隐藏操作。这样,当访问不同的路径的时候,会显示不同的页面组件。前端路由主要有以下两种实现方案:

  • hash

    ​ 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。 hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说hash 出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。

  • history API

    这种模式充分利用了html5 history interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 outsite.com/user/id 就会返回 404,这就不好看了。所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

18.小程序性能优化

面试官:说下你做性能优化的时候的一些项目亮点

​ 旺旺:长列表渲染方案……

(这个是旺旺的项目亮点,我后面遇到这个问题再写文章,不然今晚我没法睡觉

19.你实习时间多长?

面试官:你能实习多长时间呢

旺旺:这辈子我一定要给字节卖命(逃