一、DOM0 和 DOM2

  1. 语法上的区别
    box.onclick=function(){}
    box.addEventListener(‘click’,function(){})

  2. 底层运行机制上的区别
    DOM0 就是给元素的某个属性绑定方法(有效绑定的方法只有一个)
    DOM2 是基于事件池机制完成,每增加一个绑定的方法,都会往事件池中存放一个…当事件触发会依次执行事件池中的事情 =>发布订阅其实就是模拟的事件池机制 (可以给同一个元素的某个事件绑定多个不同的方法)

  3. DOM2 中可以给一些特殊的事件类型绑定方法,这些事件类型 DOM0 不支持绑定,例如:DOMContentLoaded、transitionend…
    $(document).ready() => $(function(){}) VS window.onload

  4. DOM2的事件池机制

基于addEventListener / attachEvent(IE68不可以
当事件行为触发,会把事件池中的方法按照增加的顺序依次执行,但是IE6~8中执行的顺序是不固定的

html部分

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  6. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
  7. <title></title>
  8. <meta name="keyword"
  9. content="技术体系:HTML5、CSS3、JAVASCRIPT、ES6、AJAX、NODE、VUE、REACT、小程序、FLUTTER等;课程体系:零基础就业课、在线框架课、全栈架构课;学前端就选珠峰,十年专注做前端!">
  10. <!-- IMPORT CSS -->
  11. </head>
  12. <body>
  13. <button class="submit">点我啊~~</button>
  14. <!-- IMPORT JS -->
  15. <script src="../node_modules/jquery/dist/jquery.min.js"></script>
  16. <script>
  17. // 创建一个事件池 $.Callbacks()
  18. let $pond1 = $.Callbacks();
  19. $('.submit').click(function () {
  20. // 点击的时候通知事件池中的方法执行,而且还可以给每个方法都传递实参
  21. $pond1.fire(100, 200);
  22. });
  23. let fn1 = function () {
  24. console.log(1);
  25. };
  26. let fn2 = function () {
  27. console.log(2);
  28. };
  29. let fn3 = function () {
  30. console.log(3);
  31. };
  32. // 把需要做的事情陆续添加到事件池中 $pond.add(func) / $pond.remove(func)
  33. $pond1.add(fn1);
  34. // $pond1.add(fn1); // JQ中没有做去重处理
  35. $pond1.add(fn2);
  36. $pond1.add(fn3);
  37. let fn4 = function (n, m) {
  38. console.log(4, n + m);
  39. };
  40. $pond1.add(fn4); */
  41. </script>
  42. <script src="subscribe.js"></script>
  43. <script>
  44. let pond = _subscribe();
  45. document.querySelector('.submit').onclick = function (ev) {
  46. pond.fire(ev);
  47. };
  48. let fn1 = function () {
  49. console.log(1);
  50. };
  51. let fn2 = function () {
  52. console.log(2);
  53. pond.remove(fn1);
  54. };
  55. let fn3 = function () {
  56. console.log(3);
  57. };
  58. let fn4 = function () {
  59. console.log(4);
  60. };
  61. pond.add(fn1);
  62. pond.add(fn2);
  63. pond.add(fn3);
  64. pond.add(fn4);
  65. </script>
  66. </body>
  67. </html>

js部分

  1. let _subscribe = (function () {
  2. // SUB:发布订阅类
  3. class Sub {
  4. constructor() {
  5. // 创建一个事件池,用来存储后期需要执行的方法
  6. this.$pond = [];
  7. }
  8. // 向事件池中追加方法(重复处理)
  9. add(func) {
  10. let flag = this.$pond.some(item => {
  11. return item === func;
  12. });
  13. !flag ? this.$pond.push(func) : null;
  14. }
  15. // 从事件池中移除方法
  16. remove(func) {
  17. let $pond = this.$pond;
  18. for (let i = 0; i < $pond.length; i++) {
  19. let item = $pond[i];
  20. if (item === func) {
  21. // 移除(顺序不变的情况下基本上只能用 SPLICE了),但是不能这样写,这样会导致数组塌陷问题,我们移除不能真移除,只能把当前项赋值为 null
  22. // $pond.splice(i, 1);
  23. $pond[i] = null;
  24. break;
  25. }
  26. }
  27. }
  28. // 通知事件池中的方法,按照顺序依次执行
  29. fire(...args) {
  30. let $pond = this.$pond;
  31. for (let i = 0; i < $pond.length; i++) {
  32. let item = $pond[i];
  33. if (typeof item !== 'function') {
  34. // 此时再删除
  35. $pond.splice(i, 1);
  36. i--;
  37. continue;
  38. }
  39. item.call(this, ...args);
  40. }
  41. }
  42. }
  43. // 暴露给外面用
  44. return function subscribe() {
  45. return new Sub();
  46. }
  47. })();

数组塌陷的问题

数组塌陷问题.png