如果对 apply 的使用不太自信,可以看这篇文章 apply 、 call 、bind 三者的区别 什么是发布订阅模式(观察者模式) 订阅者可监听发布者发布的消息,一旦发布者有消息发布,那么订阅者就可以接收到消息,当然订阅者也可选择性订阅 发布订阅模式(观察者模式)实现条件 确定发布者 确定缓存列表(用于存储订阅者) 发布消息(接收消息) 最常见的发布订阅模式(观察者模式) dom 监听事件 发…

如果对 apply 的使用不太自信,可以看这篇文章apply 、 call 、bind 三者的区别

什么是发布订阅模式(观察者模式)

订阅者可监听发布者发布的消息,一旦发布者有消息发布,那么订阅者就可以接收到消息,当然订阅者也可选择性订阅

发布订阅模式(观察者模式)实现条件

  1. 确定发布者
  2. 确定缓存列表(用于存储订阅者)
  3. 发布消息(接收消息)

最常见的发布订阅模式(观察者模式)

dom 监听事件

document.body.addEventListener(
  'click',
  function() {
    console.log('dom点击的订阅');
  },
  false
);
//模拟点击事件
document.body.click();

发布订阅模式(观察者模式)举例

订阅消息

// 确定发布者
var shoeObj = {};
// 确定缓存列表(用于存储订阅者
shoeObj.list = [];
shoeObj.listen = function(fn) {
  this.list.push(fn);
};
shoeObj.trigger = function() {
  for (var i = 0; i < this.list.length; i++) {
    this.list[i].apply(this, arguments);
  }
};
// 发布消息(接收消息)
shoeObj.listen(function(color, size) {
  console.log(color, size);
});
shoeObj.trigger('red', 40);
shoeObj.trigger('green', 43);
// 输出
// red,40
// green,43

订阅指定消息

var shoeObj = {
  list: [],
  listen: function(key, fn) {
    if (!this.list[key]) {
      this.list[key] = [];
    }
    this.list[key].push(fn);
  },
  trigger: function() {
    // 将类数组转成数组
    var key = [].slice.apply(arguments)[0];
    var fns = this.list[key];
    if (!fns || fns.length == 0) {
      return;
    }
    for (var i = 0; i < fns.length; i++) {
      fns[i].apply(this, arguments);
    }
  }
};
shoeObj.listen('green', function(size) {
  console.log(size);
});
shoeObj.trigger('red', 40);
shoeObj.trigger('green', 43);
shoeObj.trigger('yellow', 44);
// 输出
// 43

取消订阅

var shoeObj = {
  list: [],
  listen: function(key, fn) {
    if (!this.list[key]) {
      this.list[key] = [];
    }
    this.list[key].push(fn);
  },
  trigger: function() {
    var key = [].slice.apply(arguments)[0];
    var fns = this.list[key];
    if (!fns || fns.length == 0) {
      return;
    }
    for (var i = 0; i < fns.length; i++) {
      fns[i].apply(this, arguments);
    }
  },
  remove: function(key) {
    this.list[key] = [];
  }
};
shoeObj.listen('green', function(size) {
  console.log(size);
});
shoeObj.remove('green');
shoeObj.listen('yellow', function(size) {
  console.log(size);
});
shoeObj.trigger('red', 40);
shoeObj.trigger('green', 43);
shoeObj.trigger('yellow', 44);
// 输出
// 44

vue 中的响应式系统

vue 的响应式系统也可以看做是一个发布订阅模式(观察者模式)

function notify() {
  console.log('有内容更新了');
}

function defineData(obj, key, value) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function() {
      return value;
    },
    set: function(newVal) {
      if (newVal === value) return;
      notify();
    }
  });
}

function observer(data) {
  if (typeof data !== 'object') {
    return;
  }

  Object.keys(data).forEach((key) => {
    defineData(data, key, data[key]);
  });
}

class Vue {
  constructor(options) {
    this._data = options.data;
    observer(this._data);
  }
}

let myVue = new Vue({
  data: {
    value: 'hello world'
  }
});
myVue._data.value = 'nice world';
// 输出
// 有内容更新了

暂无评论