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






网友评论