一、DOM0 和 DOM2
语法上的区别
box.onclick=function(){}
box.addEventListener(‘click’,function(){})底层运行机制上的区别
DOM0 就是给元素的某个属性绑定方法(有效绑定的方法只有一个)
DOM2 是基于事件池机制完成,每增加一个绑定的方法,都会往事件池中存放一个…当事件触发会依次执行事件池中的事情 =>发布订阅其实就是模拟的事件池机制 (可以给同一个元素的某个事件绑定多个不同的方法)DOM2 中可以给一些特殊的事件类型绑定方法,这些事件类型 DOM0 不支持绑定,例如:DOMContentLoaded、transitionend…
$(document).ready() => $(function(){}) VS window.onloadDOM2的事件池机制
基于addEventListener / attachEvent(IE68不可以
当事件行为触发,会把事件池中的方法按照增加的顺序依次执行,但是IE6~8中执行的顺序是不固定的
html部分
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"><title></title><meta name="keyword"content="技术体系:HTML5、CSS3、JAVASCRIPT、ES6、AJAX、NODE、VUE、REACT、小程序、FLUTTER等;课程体系:零基础就业课、在线框架课、全栈架构课;学前端就选珠峰,十年专注做前端!"><!-- IMPORT CSS --></head><body><button class="submit">点我啊~~</button><!-- IMPORT JS --><script src="../node_modules/jquery/dist/jquery.min.js"></script><script>// 创建一个事件池 $.Callbacks()let $pond1 = $.Callbacks();$('.submit').click(function () {// 点击的时候通知事件池中的方法执行,而且还可以给每个方法都传递实参$pond1.fire(100, 200);});let fn1 = function () {console.log(1);};let fn2 = function () {console.log(2);};let fn3 = function () {console.log(3);};// 把需要做的事情陆续添加到事件池中 $pond.add(func) / $pond.remove(func)$pond1.add(fn1);// $pond1.add(fn1); // JQ中没有做去重处理$pond1.add(fn2);$pond1.add(fn3);let fn4 = function (n, m) {console.log(4, n + m);};$pond1.add(fn4); */</script><script src="subscribe.js"></script><script>let pond = _subscribe();document.querySelector('.submit').onclick = function (ev) {pond.fire(ev);};let fn1 = function () {console.log(1);};let fn2 = function () {console.log(2);pond.remove(fn1);};let fn3 = function () {console.log(3);};let fn4 = function () {console.log(4);};pond.add(fn1);pond.add(fn2);pond.add(fn3);pond.add(fn4);</script></body></html>
js部分
let _subscribe = (function () {// SUB:发布订阅类class Sub {constructor() {// 创建一个事件池,用来存储后期需要执行的方法this.$pond = [];}// 向事件池中追加方法(重复处理)add(func) {let flag = this.$pond.some(item => {return item === func;});!flag ? this.$pond.push(func) : null;}// 从事件池中移除方法remove(func) {let $pond = this.$pond;for (let i = 0; i < $pond.length; i++) {let item = $pond[i];if (item === func) {// 移除(顺序不变的情况下基本上只能用 SPLICE了),但是不能这样写,这样会导致数组塌陷问题,我们移除不能真移除,只能把当前项赋值为 null// $pond.splice(i, 1);$pond[i] = null;break;}}}// 通知事件池中的方法,按照顺序依次执行fire(...args) {let $pond = this.$pond;for (let i = 0; i < $pond.length; i++) {let item = $pond[i];if (typeof item !== 'function') {// 此时再删除$pond.splice(i, 1);i--;continue;}item.call(this, ...args);}}}// 暴露给外面用return function subscribe() {return new Sub();}})();
数组塌陷的问题

