4. Events

Event

Tips:原型继承的几种方式

const EventEmitter = require('events');

function Girl() {}

// 原型继承的几种方式
Girl.prototype.__proto__ = EventEmitter.prototype;

Object.setPrototypeOf(Girl.prototype, EventEmitter.prototype);

Girl.prototype = Object.create(EventEmitter.prototype);

// create的实现
function create(proto) {
  function Fn() {}

  Fn.prototype = proto;

  return new Fn();
}
复制代码

node 中的发布订阅

  • on订阅 emit触发 once订阅一次 off取消订阅

  • node 中原型继承的实现: util.inherits(Girl, EventEmitter) (内部是通过 setPrototypeOf 实现的)

  • 使用

const EventEmitter = require('events');

const util = require('util');

function Girl() {}

// 原型继承 需要通过实例来调用继承的方法
util.inherits(Girl, EventEmitter);

let girl = new Girl();

// 订阅
girl.on('brokenheart', (a, b) => {
  console.log('cry');
});
girl.on('brokenheart', (a, b) => {
  console.log('eat');
});
//触发
setTimeout(() => {
  girl.emit('brokenheart', 'a', 'b');
}, 1000);

// 订阅
const fn = () => {
  console.log('shopping');
};
girl.once('brokenheart', fn);

//触发
setTimeout(() => {
  // 如果先移除绑定一次的事件,再执行,因为绑定的是one,移除的是fn,所以要给one上绑定原事件函数
  girl.off('brokenheart', fn);

  girl.emit('brokenheart', 'a', 'b');
}, 1000);
复制代码

EventEmitter 的实现

  • 要能手写
function EventEmitter() {
  this._events = {};
}
EventEmitter.prototype.on = function (eventName, callback) {
  if (this._events) {
    // this是girl的实例,要把_events绑定到girl上
    this._events = {};
  }
  if (this._events[eventName]) {
    this._events[eventName].push(callback);
  } else {
    this._events[eventName] = [callback];
  }
};
EventEmitter.prototype.emit = function (eventName, ...args) {
  this._events[eventName].forEach((fn) => fn(...args));
};
EventEmitter.prototype.off = function (eventName, callback) {
  if (this._events && this._events[eventName]) {
    this._events[eventName] = this._events[eventName].filter(
      (fn) => fn !== callback && fn.l !== callback
    );
  }
};
EventEmitter.prototype.once = function (eventName, callback) {
  // 执行完毕后移除
  const one = () => {
    // AOP
    callback();
    this.off(eventName, one);
  };
  one.l = callback; // 关联上原始事件 用于事件移除时判断

  this.on(eventName, one);
};
module.exports = EventEmitter;
复制代码

Buffer

进制的概念

  • 早期前端是无法直接读取文件操作文件的 (node 是使用在服务端)对文件和前端传递过来的数据进行处理
  • 前端传递过来的是二进制数据
  • 进制数据: 所有内容都是以二进制来存储
  • node 需要将这个数据读取出来,将数据存储到需要的位置(如硬盘),在内存中的表现都是以二进制来表现的

    0.1 + 0.2 !== 0.3
    最终数据都是以二进制来存储的,所以会出现不精准的情况

二进制和十进制的区别

  • 十进制中最大的是 9

  • 二进制中最大的是 1

  • 以字节为单位存储数据 1024 字节 => 1k 1024k => 1m

  • 一个字节由 8 个位组成,里面都是二进制数

  • 其他进制转化为十进制:当前位的值 * 进制^当前所在位, 把每一位进行相加

  • 所以一个字节最大就是 11111111(8 个 1), 最大能表示的十进制数为 255, 0-255 就是一个字节的取值范围

  • 将十进制转换成二进制:取余 倒着组合

  • parseInt 可以将其他进制转换为十进制: parseInt(‘101’, 2); 参数 2 用来表示前面的 101 是一个二进制的数

  • 0b 二进制 0x 十六进制

  • (0x64).toString(2) 十六进制转二进制 将任意进制转换成任意进制 字符串

  • 小数也要转化成 2 进制

    10 进制中的 0.5 是 2 进制中的 0.1(因为 10 => 0.5 20 倍 所以 2 => 0.1 20 倍)
    十进制小数转为二进制的方法:乘 2 取整法可以将一个小数转化成 2 进制数

// 0.1 + 0.2的问题

0.1 * 2 = 0.2 0
0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
0.6 * 2 = 1.2 1
0.1 * 2 = 0.2 0
0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
0.6 * 2 = 1.2 1

// 0.1转为二进制是一个无穷尽的小数
// 0.1转为二进制进行存储的时候会稍微比0.1大一点
// 0.2也是这样
// 所以 0.1 + 0.2 会大于 0.3

console.log(0.1+0.2) // 考察的是进制转化的问题

// js没有将小数转化成2进制方法
// 为什么 0.2+0.2 没有问题?

// 如果出现精度问题怎么解决?
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享