# Node 核心模块

# util 模块

  • promisifyfunction转换成promise
  • inherits 继承公共属性
  • inspect 可以显示隐藏属性
  • isDate,isNumberisPrimitive(判断是否是原始数据类型的)等各种判断方法
let ncp = require("ncp"); // 第三方模块 => 拷贝
let path = require("path");
let util = require("util");
// ncp 用法
// ncp(
//   path.resolve(__dirname, "README.md"), // 需要拷贝的文件
//   path.resolve(__dirname, "README1.md"), // 拷贝后的文件
//   err => {
//     // 回调函数
//     console.log(err);
//   }
// );

// 上面的ncp的用法不是很优雅 现在一般都用async await + promise 的方式写 这里就用会用到util的一个模块,promisify => 转换为promise 用法如下
ncp = util.promisify(ncp);
(async () => {
  await ncp(
    path.resolve(__dirname, "README.md"),
    path.resolve(__dirname, "README1.md")
  );
  console.log("拷贝成功");
})();

// promisify的原理非常简单 就是返回一个函数 函数再返回一个promise
const promisify = fn => (...args) => {
  return new Promise((resolve, reject) => {
    fn(...args, function(err) {
      if (err) reject();
      resolve();
    });
  });
};
// 验证一下 功能无误
ncp = promisify(ncp);
(async () => {
  await ncp(
    path.resolve(__dirname, "README.md"),
    path.resolve(__dirname, "README1.md")
  );
  console.log("拷贝成功");
})();

// inherits node内部不是用es6写的 实现类的继承
function Parent() {}
function Child() {}
// 原理就是 Object.setPrototypeOf(Child.prototype,Parent.prototype)
util.inherits(Child, Parent); // 继承公共属性
console.log(util.inspect(Array.prototype, { showHidden: true })); // 可以显示隐藏属性

# events 模块

  • on 订阅 用法:.on('eventsName',callback)
  • emit 发布 用法: .emit('eventsName',...args)
  • off 删除订阅 用法同 on
  • once 订阅后只执行一次 用法同on

用法:

// 发布订阅模块 用法
let EventEmitter = require("./eventsCode");
let util = require("util");
let events = new EventEmitter();
// 订阅事件
events.on("提了个问题", function (whosaid) {
  console.log(whosaid + ": 你喜欢我嘛?喵~");
});
events.on("提了个问题", function (whosaid) {
  console.log(whosaid + ": Do you love me?喵~");
});
// 发布事件
events.emit("提了个问题", "九儿说:");

// 但是一般情况下 我们会用一个自己的子类来继承 events 类 也方便我们自己处理
function MyEvents() { }
util.inherits(MyEvents, EventEmitter);

let myevents = new MyEvents();
// 监听on事件的触发
myevents.on("newListener", type => {
  console.log(type);
  // on一次执行 执行一遍下面的发布 也就是on了两次 会执行两遍emit
  process.nextTick(() => {
    myevents.emit("九儿");
  });
});
let callback =function() { console.log("喵");};
myevents.once("九儿",callback);
myevents.off("九儿", callback);

myevents.once("九儿", () => {
  console.log("喵喵");
});

原理代码:

function EventEmitter() {
  // 用Object.create(null)创建空对象的方式与直接字面量方式{}的区别是:{}这种方式会有__proto__上面有很多属性
  this._events = Object.create(null);
}

EventEmitter.prototype.on = function (eventName, callback) {
  // (this._events[eventName] || []).push(callback)
  // 如果实例上没有_events属性就添加上一个,指例子中的Myevents的情况 => 此时的this是Myevents的实例 而非 EventEmitter的实例 所以this上没有 _events
  if (!this._events) this._events = Object.create(null);
  // 如果当前的订阅不是newListener就执行 newListener的回调 并传递当前的事件名 用这种方式实现 监控on事件的触发
  if (eventName !== "newListener") {
    this.emit("newListener", eventName);
  }
  // 向对应事件的数组中添加callback
  if (this._events[eventName]) {
    this._events[eventName].push(callback);
  } else {
    this._events[eventName] = [callback];
  }
};

EventEmitter.prototype.emit = function (eventName, ...args) {
  if (this._events[eventName]) {
    this._events[eventName].forEach(fn => {
      fn(...args);
    });
  }
};

EventEmitter.prototype.once = function (eventName, callback) {
  // 用one代替callback 在执行了callback之后 删除callback 由此实现了只执行一次
  let one = () => {
    callback();
    this.off(eventName, one) // 下面on的是one所以这里off的应该也是one
  }
  // 如果手动off了 那么传入off的callback跟one肯定是不相等的 所以将callback赋值给one的自定义属性,用于在off中判断
  one.l = callback
  this.on(eventName, one)
}
EventEmitter.prototype.off = function (eventName, callback) {
  if (this._events[eventName]) {
    this._events[eventName] = this._events[eventName].filter(fn => {
      // 返回false的会被过滤掉
      return fn !== callback && fn.l !== callback
    })
  }
};
module.exports = EventEmitter;

# Buffer 模块

# fs 模块