1. 程式人生 > >關於node中的this,module,exports

關於node中的this,module,exports

接觸到node後對於node中可以自由使用module和exports感到很神奇,再加上自己碰到的一些問題,做了一些總結,先丟擲自己的一些問題:
場景1:

const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
   console.log(error);
});
client.on("connect", ()=>{
    console.log("redis connect successful");
 });
 console
.log(this); //{} console.log(exports);//{} console.log(module.exports);//{} module.exports=client; console.log(this);//{} console.log(exports);//{} console.log(module.exports);// RedisClientObj

場景2

const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
   console
.log(error); })
; client.on("connect", ()=>{ console.log("redis connect successful"); }); console.log(this); //{} console.log(exports);//{} console.log(module.exports);//{} exports=client; console.log(this);//{} console.log(exports);//RedisClientObj console.log(module.exports);// {}

場景3

const
redis=require("redis"); var client=redis.createClient("6379","127.0.0.1"); client.on("error", (error)=>{ console.log(error); }); client.on("connect", ()=>{ console.log("redis connect successful"); }); console.log(this); //{} console.log(exports);//{} console.log(module.exports);//{} exports.result=client; console.log(this);//{'result':RedisClientObj} console.log(exports);//{'result':RedisClientObj} console.log(module.exports);// {'result':RedisClientObj}

這個模組就是簡單引入redis,這裡redis不是重點,可以忽略,關鍵點是之後的那些console

查詢了很多資料後,感覺以上的問題可以歸咎為2點:
1.node模組執行時幫我們做了什麼操作
2.函式引數的傳遞是值傳遞還是引用傳遞

別急,喝口水,讓我一步步往下講。

首先關鍵是要弄清楚,你寫了一個模組以後,node做了什麼封裝操作,以上面的程式碼為例:

let module={"id":"module_id","exports":{},"path_name":"path_name","children":"children"};

let getResult=function(exports,module){
//開始自己模組的程式碼
const redis=require("redis");
var client=redis.createClient("6379","127.0.0.1");
client.on("error", (error)=>{
   console.log(error);
});
client.on("connect", ()=>{
    console.log("redis connect successful");
 });
 module.exports=client;
 //自己程式碼塊結束
return module.exports;
}
 let exported = getResult.call(module.exports,module.exports,module);

從上面看來,node會為我們先準備一個module物件,然後把他當作函式的引數傳進來,由於使用了call,導致函式體內的this就會指向module.exports,而傳進去的引數又是module.exports和module。
接著在函式體內,我們就可以使用module和exports這兩個引數了,這裡要注意的是,這裡傳參是值傳遞,即該物件的記憶體地址,不是引用傳遞!

然後我們先來看場景1:
通過上面程式碼可以很清楚知道,開始實際上module.exports和exports是指向同一個物件,而this開始又是指向module.exports,所以開始的三個console出來都是空物件。之後開始對module.exports賦值,這裡要注意了,我們使用的module,實際上是傳進來的引數,是外面定義那個module物件的地址,現在我們對module.exports賦值,如此一來,module裡面這個exports的地址指向已經變了,指向了另一塊記憶體,而由於是值傳遞,this和exports儲存的仍然是之前的記憶體地址,所以他們仍然為{}

再看場景2:
同樣的道理,這次對exports賦值,也只有exports會變化,而this和module.exports還是指向之前的記憶體地址。

場景3:
這裡的賦值是對exports.res來說的,這裡並沒有開闢新的記憶體去覆蓋exports,只是在exports上新加了一個屬性罷了,所以exports的記憶體地址沒有改變,最後三個打印出來都是被賦了值的物件。

以上只是自己的一些總結,歡迎指正。