前端经典面试问题(60个前端面试问题包括JS、CSS、React、浏览器等。)
降低开支
误区:我们常说get请求的参数大小有限制,post请求的参数大小没有限制。
事实上,HTTP协议从来没有规定GET/POST的请求长度限制。get请求参数的限制是源和浏览器或web服务器限制url的长度。为了澄清这个概念,我们必须再次强调以下几点:
在缓存中添加get和post之间的差异:
可从IIFE、AMD、CMD、CommonJS、UMD获得,网络包(需要。assure),ES模块,
vue和react都使用diff算法来比较新旧虚拟节点,从而更新节点。在vue的diff函数中(建议先了解diff算法流程)。在交叉比较中,当新节点和旧节点的首尾交叉比较没有结果时,会根据新节点的key比较旧节点数组中的key,从而找到对应的旧节点(这里对应一个key = & gt映射索引的映射)。如果没有找到,则认为是新节点。如果没有键,那么遍历搜索就会找到对应的旧节点。一个是地图映射,另一个是遍历搜索。相比较而言。地图映射更快。vue部分的源代码如下:
创建地图功能
遍历搜索
在React中,如果事件由React处理(比如通过onClick),调用setState不会同步更新this.state,其他setState调用会同步执行this.state。所谓“另外”是指addEventListener绕过React直接添加的事件处理程序,以及setTimeout/setInterval生成的异步调用。
* *原因:* * React的setState函数的实现中,会根据一个变量isBatchingUpdates来判断是直接更新this.state还是放到队列里以后再说,isBatchingUpdates默认为false,也就是说setState会同步更新this.state。但是有一个函数batchedudates,它会将isBatchingUpdates改为true,当React在调用事件处理程序之前调用这个batchedudates时,结果就是React控制的事件处理程序setState不会同步更新this.state。
虚拟dom相当于在js和真实dom之间增加了一个缓存,使用dom diff算法避免了不必要的dom操作,从而提高了性能。
具体实施步骤如下:
DOM树的结构用JavaScript对象结构表示;然后使用这个树构建一个真正的DOM树,并将其插入到文档中。
当状态改变时,重新构建新的对象树。然后比较新树和老树,记录两棵树的区别。
将2中记录的差异应用于步骤1中构建的真实DOM树,视图将被更新。
结构:显示:无:会让元素从渲染树中完全消失,渲染时不会占用任何空间。可见性:隐藏:不会使元素从渲染树中消失,渲染元素会继续占用空间,但内容不可见,所以不能点击不透明:0:不会使元素从渲染树中消失,渲染元素会继续占用空间,但内容不可见,所以可以点击。
继承:显示:无:是非继承属性,后代节点的消失是由于渲染树中的元素消失造成的,无法通过修改后代节点属性来显示。Visibility: hidden:是继承的属性,后代节点消失。因为它继承了hidden,通过设置可见性:visible您可以将后代节点显式化。
性能:displaynone:修改一个元素会导致文档重排,屏幕阅读器不会读取display: none元素的内容,所以性能消耗高。可见性:隐藏:修改一个元素只会引起这个元素的重绘,性能消耗低。屏幕阅读器读取可见性:隐藏元素内容不透明度:0:修改一个元素会导致重绘,性能消耗低。
连接:它们都使元素不可见。
常用的有三种。Clearfix,clear: both,overflow:hidden;
好多了。clearfix,伪元素万金油版,后两者有局限性。
Clear:both:如果在同一个容器中的相邻元素上使用,那么它是好的。有时在容器外部会出现一些问题,例如相邻容器中的包壳元件坍塌。
溢出:隐藏:如果在同一个容器中使用,可以形成BFC,避免浮动导致的元素崩溃。
概念:把几个小图拼接成一张图。根据背景位置和元素大小调整要显示的背景图案。
优势:
缺点:
块状元素特征:
1.在正常流程中,如果没有设置宽度,父容器将自动填充。2.可以应用边距/填充。3.高度将被扩展以包括正常流中的子元素,而不设置高度。4.在正常流程中,布局在前后元素位置之间(不包括水平空间)。5.忽略垂直对齐。
内嵌元素特征
1.根据方向进行水平布局。
2.元素前后都不会有换行符。
3.由空白控制
4.边距/填充在垂直方向无效,在水平方向有效。
5.宽度/高度属性对于非替换行中的元素无效,宽度由元素的内容决定。
6.非替换行元素的行框高度由行高决定,替换行元素的行框高度由高度、边距、填充和边框决定。7.浮动或绝对定位将被转换成块8。垂直对齐属性生效。
GIF:
JPEG:
巴布亚新几内亚:
七种数据类型
(ES6之前),其中五种是基本类型:字符串,数字,布尔,空,未定义,
来自ES6的符号也是原始数据类型,表示唯一的值。
对象是一种引用类型(范围很广),包括数组、函数、
输出结果是:
工厂模式
简单的工厂模型可以理解为解决很多类似的问题;
单一模式
只能实例化一次(构造函数向实例添加属性和方法)
沙盒模式
把一些函数放到自执行函数中,但是要用闭包来公开接口,用变量来接收公开的接口,然后调用里面的值,否则里面的值就不能用了。
1.字面量
2.对象构造函数创建
3.使用工厂模式创建对象
4.使用构造函数创建对象
HTML中与javascript的交互是通过事件驱动实现的,比如鼠标点击事件onclick、页面滚动事件onscroll等。您可以向文档或文档中的元素添加事件侦听器来订阅事件。如果你想知道这些事件何时被调用,你需要理解“事件流”的概念。
什么是事件流?事件流描述了从页面接收事件的顺序。DOM2级事件流包括以下阶段。
addevent listener:addevent listener是指定为DOM2级别事件添加的事件处理程序的操作。该方法接收三个参数:要处理的事件的名称、作为事件处理程序的函数和一个布尔值。如果最后一个布尔参数为true,这意味着在捕获阶段调用了事件处理程序。如果为false,则意味着在冒泡阶段调用事件处理程序。
IE只支持事件冒泡。
获取对象的原型,可以是chrome中的__proto__形式,也可以是ES6中的Object.getPrototypeOf形式。
那么什么是Function.proto呢?也就是说,函数是从什么对象继承来的,我们来做如下判断。
我们发现函数的原型也是函数。
我们可以用图表来阐明这种关系:
这里举个栗子。以Object为例。我们的公共对象是一个构造函数,所以我们可以通过它构建一个实例。
那么此时,实例是实例,构造函数是对象。我们知道,构造函数有一个指向原型的prototype属性,所以原型是:
在这里我们可以看到三者之间的关系:
在JS中,继承通常是指原型链继承,也就是通过指定原型,而你可以通过原型链继承原型上的属性或者方法。
在函数式编程中,函数是一等公民。那么什么是函数的柯里化呢?
函数的cori化是指将一个可以接收多个参数的函数转化为一个接收单个参数的函数,并返回一个接收其余参数并返回结果的新函数的技术。
函数代码化的主要功能和特点是参数重用、提前返回和延迟执行。
在一个函数中,先填充几个参数,然后返回到一个新函数的技术,称为函数的科里化。它通常可用于为重复调用的函数预设公共参数,而不会侵入函数。
调用和应用都是为了解决改变这个方向的问题。功能是一样的,只是传递参数的方式不同。
除了第一个参数,call可以接收一个参数列表,而apply只接受一个参数数组。
Bind的功能与其他两个方法相同,只是这个方法将返回一个函数。我们可以通过绑定来实现cori化。
如何实现绑定函数
要实现以下功能,可以从几个方面来思考。
如何实现一个调用函数
如何实现应用函数
arrow函数其实没有this,这个函数中的this只依赖于它外面第一个不是arrow函数的函数的this。在此示例中,这是window,因为调用符合前面代码中的第一种情况。而这一旦绑定到上下文,就不会被任何代码改变。
为什么我们要用下面的例子来验证let中是否存在变量提升?
如果let变量没有变量提升,console.log(name)会输出ConardLi,但结果是一个ReferenceError,说明let变量也有变量提升,但它有一个“临时死区”,在变量初始化或赋值之前无法访问。
变量的分配可以分为三个阶段:
关于字母、变量和函数:
依次输出:未定义-& gt;10->;20
答案:d
colorChange方法是静态的。静态方法仅存在于创建它们的构造函数中,不能传递给任何子方法。因为freddie是子对象,所以不会传递函数,所以在freddie实例上没有freddie方法:抛出TypeError。
1.使用第一次push,将obj对象的push方法设置为obj[2]= 1;长度+= 1 ^ 2。使用第二次push,对obj对象的push方法设置obj[3]= 2;长度+= 1 ^ 3。当使用console.log输出时,它被打印为数组,因为它具有length属性和splice方法。4.打印时打印为空,因为数组没有设置下标0 1,活动obj[0]获取为未定义。
未定义的{n:2}
首先A和B同时引用{n:2}对象,然后执行语句a.x = a = {n: 2}。虽然赋值是从右到左的,但是。大于=,所以这里先执行a.x,相当于A(或B)指向的{ n:1}。x:未定义} .然后按照正常情况从右到左进行赋值。此时执行a ={n:2}时,A的引用发生变化,指向新对象{n:2},而B仍然指向旧对象。后面执行a.x = {n: 2}时,不会重新解析A,而是原A,即旧对象,所以旧对象的X的值为{n: 2},旧对象为{ n:1;X: {n: 2}},被b引用,后面输出a.x的时候,就要重新解析A了。此时A是指向一个新对象的A,而这个新对象没有X属性,所以未定义;访问时输出;当访问b.x时,会输出旧对象的x的值,即{n:2}。
在比较等式中,基元类型通过它们的值进行比较,而对象通过它们的引用进行比较。JavaScript检查对象是否引用了内存中的相同位置。
我们作为参数传递的对象和我们用来检查相等性的对象位于内存中的不同位置,所以它们的引用是不同的。
这就是{age: 18} == {age: 18}和{age: 18} = = {age: 18}返回false的原因。
所有对象键(符号除外)都存储为字符串,即使您没有给定字符串类型的键。这就是obj.hasOwnProperty('1 ')也返回true的原因。
上述陈述不适用于Set。我们的集合中没有“1”:Set . has(' 1 ')返回false。它的数值类型为1,set.has(1)返回true。
这个问题考察对象的键名转换。
Catch块接收参数x,当我们传递参数时,这与变量的x不同。这个变量x属于catch的范围。
之后,我们将这个块级作用域的变量设置为1,并设置变量y的值,现在,让我们打印块级作用域的变量x,它等于1。
在catch块之外,x仍然是未定义的,y是2。当我们希望console.log(x)在catch块之外时,它返回undefined,y返回2。