# Node 核心模块
# util 模块
promisify
将function
转换成promise
inherits
继承公共属性inspect
可以显示隐藏属性isDate
,isNumber
,isPrimitive
(判断是否是原始数据类型的)等各种判断方法
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;