事件冒泡和事件捕获

事件冒泡和事件捕获的区别

1
2
3
<div id="outer">
<p id="inner">Click me!</p>
</div>

事件冒泡: 事件从最内层的元素开始,一直向上传播,直到document。则在事件冒泡的概念上,应该是p -> div -> body -> html -> document
事件捕获: 与事件冒泡相反,从最外层开始,直到具体元素

1
element.addEventListener(event, function, useCapture)

第一个参数是需要绑定的元素
第二个参数是触发事件后要执行的函数
第三个元素就是为事件冒泡还是捕获准备的
默认是false,表示在事件冒泡阶段处理函数,
true 则表示在事件捕获阶段处理函数

addEventListener方法用来为一个特定的元素绑定一个事件处理函数,

事件冒泡与事件捕获应用:

在实际开发中,利用事件流的特性,事件代理

1
2
3
4
5
6
7
8
9
<ul class="color_list">        
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>purple</li>
</ul>
<div class="box"></div>

这时就需要事件代理出场了,利用事件流的特性,我们只绑定一个事件处理函数也可以完成:

1
2
3
4
5
6
7
function colorChange(e) {
var e = e || window.event;
if (e.target.nodeName.toLowerCase === 'li') {
box.innerHTML="该颜色为 "+e.target.innerHTML;
}
}
color_list.addEventListener("click", colorChange, false)

Cors中的简单请求和复杂请求

CORS

cors: cross origin resource share 跨域资源共享
允许浏览器向跨域服务器发出xhr,从而克服跨域问题,需要浏览器和服务器同时支持。

  • 浏览器会自动往请求header里添加origin字段表明当前请求来源
  • 服务器端需要设置响应头的Access-Control-Allow-origin/Methods/Headers 源 方法 头部信息等
  • 请求分为简单请求和复杂请求,复杂请求发之前会发生Options类型的预检请求,看是否允许当前跨域请求

    简单请求

    简单请求
    请求方法是以下三种方法之一:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    HEAD
    GET
    POST

    HTTP的请求头信息不超出以下几种字段:

    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

    后端的头部响应设置

    1
    2
    3
    Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个<code>*</code>,表示接受任意域名的请求。
    Access-Control-Allow-Credentials:该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。
    Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

    复杂请求

    非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)
    Access-Control-Request-Method: Put/Delete 必须,表示当前请求会用到哪些Http方法
    Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
    如果浏览器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。

和JSONP请求对比

  • Jsonp只能支持get请求,而cors支持所有http请求方法
  • JSONP优势在于支持老是浏览器,以及可以向不支持CORS的网站请求数据

参考链接

Set和Map的区别

Set

Es6新的数据结构。类似于数组,成员唯一,没有重复的值
Set本身是构造函数,用来生成Set数据结构.

WeakSet 与 Set区别

  • WeakSet成员只能是对象,不能是其他类型的值
  • WeakSet的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
    因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。

由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。

WeakSet应用

  • WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。
  • 确保实例方法只能在实例上调用,
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const foos = new WeakSet()
    class Foo {
    constructor() {
    foos.add(this)
    }
    method () {
    if (!foos.has(this)) {
    throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
    }
    }
    }
    上面代码保证了Foo的实例方法,只能在Foo的实例上调用。这里使用 WeakSet 的好处是,foos对实例的引用,不会被计入内存回收机制,所以删除实例的时候,不用考虑foos,也不会出现内存泄漏。

Map

定义

js对象,本质上是键值对的集合(hash结构)

以前对象里的key只能是字符串,Map里阔以用对象当作key,Object结构提供了字符串-值的对应结构,Map结构提供了值-值 的数据结构,是一种更完善的hash结构实现。

  • Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
  • 如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,比如0和-0就是一个键,布尔值true和字符串true则是两个不同的键。

相同点

WeakMap结构与Map结构类似,也是用于生成键值对的集合。

不同点

weakMap只接受对象作为键名(null 除外),不接受其他类型的值作为键名key。
weakMap它的键名所指向的对象都是弱引用,即垃圾回收机制不会将该引用考虑在内。
因此只要所引用对象的其他引用都被清除,GC就会释放该引用对象所占的内存,也就是说,一旦不需要,weakMap里的键名对象和对应的键值对会自动消失,不用手动删除引用。

WeakMap 与 Map 在 API 上的区别主要是两个,一是没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性。

1
2
3
4
5
6
const wm = new WeakMap();

const element = document.getElementById('example');

wm.set(element, 'some information');
wm.get(element) // "some information"

WeakMap对element就是弱引用,不会被计入垃圾回收机制。也就是说,上面dom节点引用计数是1,一旦消除该节点的引用,所占用的内存即会被释放,WeakMap里保存的键值对也会自动消失

用途

  1. DOM节点作为键名 注意是键名
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let myWeakmap = new WeakMap();

    myWeakmap.set(
    document.getElementById('logo'),
    {timesClicked: 0})
    ;

    document.getElementById('logo').addEventListener('click', function() {
    let logoData = myWeakmap.get(document.getElementById('logo'));
    logoData.timesClicked++;
    }, false);
    上面代码中,document.getElementById(‘logo’)是一个 DOM 节点,每当发生click事件,就更新一下状态。我们将这个状态作为键值放在 WeakMap 里,对应的键名就是这个节点对象。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。

2.WeakMap 部署私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const SimCard = (() => {
const _private = new Map()
class SimCard {
constructor(number, type, p1, p2) {
_private.set('p1', p1)
_private.set('p2', p2)
}
get p1() {
return _private.get('p1')
}
get p2() {
return _private.get('p2')
}
}
return SimCard
})()
var test = new SimCard('one', 'two')
console.log(test.p1) // 'one'
console.log(test.p2) // 'two'
console.log(test._private) // undefined

参考链接

vue slot是做什么的

实现bind函数

实现一个并发请求控制函数

参考链接