module.exports,exports,require
為什麼給這兩個單獨拿出來放前面說,因為太重要了! 先用人話解釋一下:module就是require的時候建立的一個物件,並且返回了 module.exports,exports = module.exports;(牢牢記住) 我們來看自己實現一個:
let path = require('path');
let fs = require('fs');
let vm = require('vm');
function Module(filename) { //建構函式
this.loaded = false;
this.filename = filename;
this.exports = {} //模組對應的匯出結果
}
Module._extensions = ['.js', '.json'] //靜態屬性
Module._resolveFilename = function(p) { //靜態方法
p = path.join(__dirname, p);
if (!/\.\w+$/.test(p)) {
for (let i = 0; i<Module._extensions.length; i++) {
let filepath = p + Module._extensions[i];
try{
fs.accessSync(filepath);
return filepath;
} catch(e) {
if(i >= Module._extensions.length) {
throw new Error('module not Found')
}
}
}
} else {
return p
}
}
Module._cache = {}; //靜態屬性 外部無法更改 無法呼叫
Module._extensions['.json'] = function (module) {
let content = fs.readFileSync(module.filename,'utf8');
module.exports = JSON.parse(content)
}
Module.wrapper = ['(function (exports,require,module){','\r\n})'];
//通過這個包裹 使得exports = module.exports;
Module.wrap = function (content) {
return Module.wrapper[0] + content + Module.wrapper[1];
}
Module._extensions['.js'] = function (module) {
let content = fs.readFileSync(module.filename, 'utf8');
let script = Module.wrap(content);
let fn = vm.runInThisContext(script);
// module.exports = exports = {}
// exports.a = 'hello world'
fn.call(module.exports, module.exports, req, module);
}
Module.prototype.load = function () {
// 載入模組本身 js按照js載入 json按照json載入
let extname = path.extname(this.filename);
Module._extensions[extname](this);
}
Module.prototype.load = function () {
let extname = path.extname(this.filename);
Module._extensions[extname](this) //模組的執行
}
//重點require就是給module.exports匯出的程式碼包了一層,然後module.load()執行並取得返回值
function req(path) {
let filename = Module._resolveFilename(path);
if (Module._cache[filename]) {
return Module._cache[filename].exports;
}
let module = new Module(filename)
module.load(); //讓這個模組進行載入 根據不同的字尾載入不同的內容
Module._cache[fileName] = module;
return module.exports;
}
複製程式碼
巨集任務&微任務
進位制
數字按照進位制可分為二進位制,八進位制,十進位制和十六進位制,在計算機內部呢都是使用的二進位制,node中各種進位制的表示:
- ob表示二進位制 ,
- 0o或者0表示八進位制,
- 0x表示16進位制(buffer都是用16進製表示,buffer是啥?後面會說道到)
這些進位制之間怎麼轉換呢? 各種進位制轉化為十進位制用Math.parseInt();十進位制轉為其他進位制可以利用toString()方法。
util模組
- util.promisify(fn); //十分常用
- util.inherits(Child, Parent);
- util.isArray([]) util.isString();
釋出訂閱
let EventEmitter = require('./events');
let util = require('util');
function My() {}
util.inherits(My,EventEmitter);
let e = new My();
// 訂閱
e.on('水開了',function (who) { // {水開了:[fn,fn]}
console.log('吃泡麵' + who)
});
e.on('水開了',function (who) {
console.log('洗臉' + who);
});
// 釋出
e.emit('水開了','我')
複製程式碼
這個地方有一個主意的地方就是 e.on('newListener', cb) 2.
let EventEmitter = require('events');
let util = require('util');
function My() {}
util.inherits(My,EventEmitter);
let e = new My();
e.on('newListener',function (type) {
if(type === 'ok'){
process.nextTick(()=>{ //這個要注意 必須事件已經被新增進去後才可以觸發
e.emit('ok');
});
}
})
e.on('水開了',function (who) {
console.log('吃泡麵' + who)
});
e.on('水開了',function (who) {
console.log('洗臉' + who);
});
e.on('ok',function () {
console.log('ok')
})
複製程式碼
- e.once(event, cb)
- e.removeListener(event, cb)
Buffer
怎麼宣告buffer
- 通過長度 let buffer = Buffer.alloc(length);
- 通過字串宣告 let buffer = Buffer.from('字串');
- 通過陣列宣告 let buffer = Buffer.from([0xe7, 0x8f,0xa0])
另外說明一點的是:buffer是記憶體地址的引用,可以修改的
buffer的幾個常見方法:
- buffer.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
- Buffer.concat(list[, totalLength]) //和陣列類似
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.alloc(14);
const buf3 = Buffer.alloc(18);
const totalLength = buf1.length + buf2.length + buf3.length;
// 輸出: 42
console.log(totalLength);
const bufA = Buffer.concat([buf1, buf2, buf3], totalLength);
// 輸出: <Buffer 00 00 00 00 ...>
console.log(bufA);
// 輸出: 42
console.log(bufA.length);
複製程式碼
有時我們需要給一段字串進行切割,就像字串的split方法一樣,但是buffer並沒有提供一個這樣的方法,我們自己實現一個吧,程式碼如下:
// indexOf 取索引
let buffer = Buffer.from('xlei愛折騰愛js');
// console.log(buffer.indexOf('*',7));
Buffer.prototype.split = function (sep) {
let offset = 0;
let len = Buffer.from(sep).length;
let arr = [];
let start = 0;
while (-1 != (offset = (this.indexOf(sep, start)))) {
arr.push(this.slice(start, offset));
start = offset + len;
};
arr.push(this.slice(start));
return arr;
}
// spilt()方法 分割buffer
// [buffer1,buffer2,buffer3]
console.log(buffer.split('愛'));
複製程式碼
以上是一部分的核心模組常見用法以及部分深刻解析,不足之處歡迎各位提出寶貴的意見或建議,也希望能幫助到你從中獲得一些知識!這是一個系列的文章 還有核心模組(二)核心模組(三)等等部分,謝謝大家的關注!