美文网首页
前端常见面试题目(三)

前端常见面试题目(三)

作者: 菜菜的小阿允 | 来源:发表于2020-10-12 17:19 被阅读0次

1、React的受控组件与非受控组件
React 有两种不同的方式来处理表单输入。
如果一个 input 表单元素的值是由 React 控制,就其称为受控组件。当用户将数据输入到受控组件时,会触发修改状态的事件处理器,这时由你的代码来决定此输入是否有效(如果有效就使用更新后的值重新渲染)。如果不重新渲染,则表单元素将保持不变。
一个非受控组件,就像是运行在 React 体系之外的表单元素。当用户将数据输入到表单字段(例如 input,dropdown 等)时,React 不需要做任何事情就可以映射更新后的信息。然而,这也意味着,你无法强制给这个表单字段设置一个特定值。在大多数情况下,你应该使用受控组件。
例如,非受控组件如下:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

2、react的合成事件机制
react的合成事件机制是一个比较复杂的概念,下面简单叙述一下。

  • 合成事件是相对浏览器原生的事件而言的。合成事件本质上是遵循W3C的相关规范,把浏览器实现过的事件再实现一遍,并抹平各个浏览器的实现差异,使得开发者使用起来体验是一致的。
  • 原理大致为:React并不是将click事件绑在真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行。
    如图:


    image

3、http2

  • HTTP发展史
    1、HTTP/0.9 - 单行协议:HTTP于1990年问世,那时候HTTP非常简单:只支持GET方法;没有首部;只能获取纯文本。
    2、HTTP/1.0 - 搭建协议的框架:1996年,HTTP正式被作为标准公布,版本为HTTP/1.0。1.0版本增加了首部、状态码、权限、缓存、长连接(默认短连接)等规范,可以说搭建了协议的基本框架。
    3、HTTP/1.1 - 进一步完善:1997年,1.1版本接踵而至。1.1版本的重大改进在于默认长连接;强制客户端提供Host首部;管线化;Cache-Control、ETag等缓存的相关扩展。
  • HTTP1.1目前存在的问题
    1、线头阻塞:TCP连接上只能发送一个请求,前面的请求未完成前,后续的请求都在排队等待。
    2、多个TCP连接:虽然HTTP/1.1管线化可以支持请求并发,但是浏览器很难实现,chrome、firefox等都禁用了管线化。所以1.1版本请求并发依赖于多个TCP连接,建立TCP连接成本很高,还会存在慢启动的问题。
    3、头部冗余,采用文本格式:HTTP/1.X版本是采用文本格式,首部未压缩,而且每一个请求都会带上cookie、user-agent等完全相同的首部。
    4、客户端需要主动请求
  • HTTP2.0改进
    1、二进制分帧层:HTTP2性能提升的核心就在于二进制分帧层。HTTP2是二进制协议,他采用二进制格式传输数据而不是1.x的文本格式。
    2、多路复用:HTTP2的多路复用完美解决了HTTP/1.1的线头阻塞和多个TCP连接的问题。HTTP2让所有的通信都在一个TCP连接上完成,真正实现了请求的并发。
    3、头部压缩:头部压缩也是HTTP2的一大亮点。在1.X版本中,首部用文本格式传输,通常会给每个传输增加500-800字节的开销。现在打开一个网页上百个请求已是常态,而每个请求带的一些首部字段都是相同的,例如cookie、user-agent等。HTTP2为此采用HPACK压缩格式来压缩首部。头部压缩需要在浏览器和服务器端之间:维护一份相同的静态字典,包含常见的头部名称,以及常见的头部名称和值的组合;维护一份相同的动态字典,可以动态的添加内容;通过静态Huffman编码对传输的首部字段进行编码。
    4、服务器端推送:服务器端推送使得服务器可以预测客户端需要的资源,主动推送到客户端。
    例如:客户端请求index.html,服务器端能够额外推送script.js和style.css。
    实现原理就是客户端发出页面请求时,服务器端能够分析这个页面所依赖的其他资源,主动推送到客户端的缓存,当客户端收到原始网页的请求时,它需要的资源已经位于缓存。针对每一个希望发送的资源,服务器会发送一个PUSH_PROMISE帧,客户端可以通过发送RST_STREAM帧来拒绝推送(当资源已经位于缓存)。这一步的操作先于父响应(index.html),客户端了解到服务器端打算推送哪些资源,就不会再为这些资源创建重复请求。当客户端收到index.html的响应时,script.js和style.css已经位于缓存。

4、闭包及其作用

  • 闭包的概念
    闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
  • 闭包的用途
    它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
        alert(n);
    }
    return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制回收。这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

5、原型

  • 什么是原型
    在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个" [[Prototype]]"内部属性,这个属性所对应的就是该对象的原型。"[[Prototype]]"作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了"proto"这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器"Object.getPrototype(object)")。
  • 原型链
    因为每个对象和原型都有原型,对象的原型指向对象的父,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 "Object.prototype"), 如果仍然没有找到指定的属性,就会返回 undefined。
    "hasOwnProperty"是"Object.prototype"的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性,因为"hasOwnProperty" 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。
  • 作用域链
    作用域链与一个执行上下文相关,是内部上下文所有变量对象(包括父变量对象)的列表,用于变量查询。
  • 总结
    1、所有的对象都有"[[prototype]]"属性(通过proto访问),该属性对应对象的原型
    2、所有的函数对象都有"prototype"属性,该属性的值会被赋值给该函数创建的对象的"proto"属性
    3、所有的原型对象都有"constructor"属性,该属性对应创建所有指向该原型的实例的构造函数
    4、函数对象和原型对象通过"prototype"和"constructor"属性进行相互关联

6、call、apply、bind之间的关系

  • bind,apply,call的共同和不同点:
    1、三者都可以用来改变this的指向
    2、三者第一个参数都是this要指向的对象,也就是想指定的上下文,上下文就是指调用函数的那个对象。(点前的那个对象,没有就是全局window)
    3、三者都可以传参,但是apply是数组,而call是有顺序的传入
    4、bind 是返回对应函数,便于稍后调用;apply 、call 则是立即执行
  • 例子
var a ={
  name : "Cherry",
  fn : function (a,b) {
    console.log( a + b)
   }
}
var b = a.fn;
b.apply(a, [1,2]); //3
b.call(a, 4, 5, 6); //9
b.bind(a,1,2)(); // 3

相关文章

网友评论

      本文标题:前端常见面试题目(三)

      本文链接:https://www.haomeiwen.com/subject/oovfyktx.html