跳坑之js調(diào)用另一個(gè)js文件中函數(shù)

最近在做electron的內(nèi)容优训,但是踩了很多坑续语,其中一個(gè)坑:

問題背景:對(duì)于進(jìn)程間的通信襟己,實(shí)現(xiàn)帶參數(shù)的輸入輸出引谜,就是直接寫一些函數(shù),可以實(shí)現(xiàn)其他文件對(duì)于函數(shù)的調(diào)用

問題內(nèi)容:其中一個(gè)js是實(shí)現(xiàn)功能函數(shù)(renderer.js)擎浴,也就是帶參數(shù)的輸入輸出员咽,另一個(gè)js是調(diào)用這些功能(hello.js),那么如何實(shí)現(xiàn)這個(gè)調(diào)用過程呢贮预?

我的hello.js和renderer.js在同一個(gè)文件夾下面贝室。

來(lái)嘗試一下網(wǎng)上的方法:

方法一:在html文件中body標(biāo)簽后加入js文件,在index.html中的body標(biāo)簽(</body>與</html>之間插入所引用的hello.js)仿吞,代碼如下:

<html>
  <head>
    <!---head內(nèi)容--->
  </head>
    <body>
      <!---body內(nèi)容--->
    </body>
    <!---在body后面添加所引用的js文件-->
    <script language="JAVASCRIPT" src='hello.js'></script>
</html>

然后滑频,對(duì)于hello.js文件,為了調(diào)用renderer.js中的函數(shù)唤冈,需要在hello.js中添加以下代碼:

new_element = document.createElement("script");
new_element.setAttribute("type","text/javascript");
new_element.setAttribute("src", "renderer.js");
document.body.appendChild(new_element);

function testBtn(struct, buttonId, msg){
    //renderer.js中函數(shù)為test
    test(struct, buttonId, msg);
  }
testBtn('click', 'asynchronous message', 'ping');

對(duì)于代碼峡迷,網(wǎng)上解釋如下:
讓我們來(lái)分析一下關(guān)鍵的幾句代碼:首先,我們利用document.createElement("script")生成了一個(gè)script的標(biāo)簽,設(shè)置其type屬性為text/javascript绘搞,src為renderer.js(這里的renderer.js同hello.js放在同一個(gè)目錄彤避,也可放在不同的目錄)。最后將這個(gè)標(biāo)簽動(dòng)態(tài)地加入body中夯辖。如此一來(lái)琉预,我們就可以調(diào)用到不同js文件中的方法了。

注意:<script language="JAVASCRIPT" src='b.js'></script>一定要放在body下面蒿褂。
因?yàn)閔ello.js中用到了body(document.body.appendChild(new_element);)
如果將引如hello.js的代碼放在body上面圆米,也就是說,
進(jìn)入頁(yè)面后啄栓,還沒有生成body就已經(jīng)執(zhí)行hello.js里的document.body.appendChild(new_element);了娄帖。
這時(shí)body不存在就會(huì)拋javascript錯(cuò)誤。

而實(shí)際效果呢谴供,并不行(至少我沒有測(cè)試成功块茁,目前還不知道原因出現(xiàn)在哪里,求告知9鸺 J浮)

方法二:在調(diào)用者程序的開始直接加入要被調(diào)用的js文件,代碼如下:

//加入下面的代碼
document.write("<script language=javascript src='./renderer.js'></script>");
//調(diào)用函數(shù)
test('click', 'asynchronous message', 'ping');

結(jié)果呵呵了崎场。佩耳。。谭跨。干厚。還是不行。螃宙。蛮瞄。。谆扎。又是一頭霧水

方法三:在html文件中加入兩個(gè)腳本程序挂捅,注意,加入的位置在</head>和<body>兩個(gè)標(biāo)簽之間堂湖,(也有的在<body></body>兩個(gè)標(biāo)簽之間加入的)闲先,代碼如下:

</head>
  <script src="hello.js"></script>
  <script src="renderer.js"></script>
  <body>

之后在hello.js中直接調(diào)用函數(shù)就行。

test('click', 'asynchronous message', 'ping');

然后呢无蜂?如果說前兩種方法不行我還信了伺糠,畢竟沒有看到執(zhí)行結(jié)果,但是第三種人家明明成功了斥季,而且兩種加入的方法都成功了训桶,到我這兒走不通了,幾近崩潰。渊迁。慰照。

冷靜冷靜,如果你試了試前面的方法也不行琉朽,一定要淡定,我也不知道怎么想的稚铣,然后試了一下下面這個(gè)方法箱叁。。竟然成功了L枰健耕漱!

方法四:首先,在方法三的基礎(chǔ)上抬伺,在html中直接利用require螟够,將兩個(gè)js文件直接加載進(jìn)去,然后就可以實(shí)現(xiàn)調(diào)用了峡钓。
html中的代碼:

//首先妓笙,方法三中的加入內(nèi)容不變
</head>
  <script src="hello.js"></script>
  <script src="renderer.js"></script>
  <body>
    <!--- body內(nèi)容--->

    //方法四加入的內(nèi)容
    <script>
    // You can also require other files to run in this process
    require('./renderer.js')
    require('./hello.js')
    </script>
  </body>
 </head>

至于調(diào)用函數(shù)的代碼,與方法三一樣能岩,直接在hello.js中調(diào)用即可寞宫。

解釋解釋,知其然必須知其所以然(個(gè)人理解):
對(duì)于方法三拉鹃,為什么不行呢辈赋?我打開electron調(diào)試工具的時(shí)候,第一次加載頁(yè)面時(shí)膏燕,輸出了這個(gè)信息(極為重要):
test is not defined----我的test函數(shù)沒有被定義钥屈,為什么沒有被定義,我明明已經(jīng)寫好了的坝辫,看一下方法三中的加載順序篷就,先加載的hello.js,之后加載的renderer.js阀溶,也就是說腻脏,先加載了的hello.js中的test方法沒有被定義,然后自然函數(shù)執(zhí)行不成功银锻。
看了看程序永品,發(fā)現(xiàn)方法四的加載順序與方法三完全相反,在查看了文檔之后击纬,發(fā)現(xiàn)方法三與方法四的加載的最終結(jié)果并沒有什么不同鼎姐,只不過:require引入的的文件,內(nèi)部聲明的最外層變量不屬于全局變量,而script引入的屬于全局變量炕桨。

最重要的信息:
如果用script引入需要考慮引入順序饭尝,避免變量沖突和前置依賴∠坠考慮順序钥平,考慮順序,考慮順序姊途,重要的事情說三遍(之后自己也試了試涉瘾,把方法三的順序顛倒,發(fā)現(xiàn)可以捷兰,之所以沒刪除這些內(nèi)容立叛,是想記得更清,也避免讓更多的人入坑)

哈哈哈哈贡茅,腦子真的被門給夾了秘蛇,這個(gè)坑跳的真的值(說的我自己都信了)
不過,以方法三加載腳本程序的方法并不好:
(來(lái)自阮一峰先生的日志:http://www.ruanyifeng.com/blog/2012/11/require_js.html) 首先顶考,加載的時(shí)候赁还,瀏覽器會(huì)停止網(wǎng)頁(yè)渲染,加載文件越多村怪,網(wǎng)頁(yè)失去響應(yīng)的時(shí)間就會(huì)越長(zhǎng)秽浇;其次,由于js文件之間存在依賴關(guān)系甚负,因此必須嚴(yán)格保證加載順序(比如上例的1.js要在2.js的前面)柬焕,依賴性最大的模塊一定要放到最后加載,當(dāng)依賴關(guān)系很復(fù)雜的時(shí)候梭域,代碼的編寫和維護(hù)都會(huì)變得困難斑举。

最后,介紹一種我最喜歡的方式病涨,對(duì)于功能的封裝這種方式應(yīng)該再好不過了富玷,exports和require大法好。

在nodejs中既穆,提供了exports 和 require 兩個(gè)對(duì)象赎懦,其中 exports 是模塊公開的接口,require 用于從外部獲取一個(gè)模塊的接口幻工,即所獲取模塊的 exports 對(duì)象励两。而在exports拋出的接口中,我們可以拋出變量或者函數(shù)囊颅。
如果你希望你的模塊就想為一個(gè)特別的對(duì)象類型当悔,請(qǐng)使用module.exports傅瞻;如果希望模塊成為一個(gè)傳統(tǒng)的模塊實(shí)例,請(qǐng)使用exports.xx方法盲憎;module.exports才是真正的接口嗅骄,exports只不過是它的一個(gè)輔助工具。最終返回給調(diào)用的是module.exports而不是exports饼疙。
總而言之溺森,二者的關(guān)系是:

    exports 是指向的 module.exports 的引用,二者指向同一塊內(nèi)存
    module.exports 初始值為一個(gè)空對(duì)象 {}窑眯,所以 exports 初始值也是 {}
    require() 返回的是 module.exports 而不是 exports

下面給出代碼:
renderer.js中使用exports導(dǎo)出函數(shù):

//在這里面寫好函數(shù)的封裝儿惫,然后在hello.js中調(diào)用
var test = function(struct, buttonId, msg){
    const asyncMsgBtn = document.getElementById(buttonId);
    asyncMsgBtn.addEventListener(struct, function(){
        switch(struct){
            case 'click':
                ipc.send('asynchronous-message', msg);
                console.log("調(diào)用成功");
                break;
            default:
                console.log('Error!!!')
        }
    })
}
//這種方式是成功的
exports.test = test;
//這種方式也是可以得
//module.exports.test = test;

而hello.js中對(duì)于代碼的使用如下:

//利用require加載模塊
const renderer = require('./renderer')

renderer.test('click', 'asynchronous message', 'ping');
renderer.test('click', 'changeView', 'change');

可以說,這種方式完全符合我們程序封裝的概念伸但,思路統(tǒng)一,結(jié)構(gòu)規(guī)整留搔,個(gè)人最愛更胖。而且,上面的程序中兩種方法都可以輸出成功隔显,其原因就在于:
exports變量是在模塊的文件級(jí)別作用域內(nèi)有效的却妨,它在模塊被執(zhí)行前被賦于 module.exports 的值。它有一個(gè)快捷方式括眠,以便 module.exports.f = ... 可以被更簡(jiǎn)潔地寫成exports.f = ...彪标。 注意,就像任何變量掷豺,如果一個(gè)新的值被賦值給exports捞烟,它就不再綁定到module.exports(其實(shí)是exports.xx會(huì)自動(dòng)掛載到?jīng)]有命名沖突的module.exports.xx)
而且,對(duì)于require函數(shù)当船,exports只是函數(shù)內(nèi)部一個(gè)局部變量题画,最后返回的仍是module.exports,這應(yīng)該就是exports稱為module.exports的引用所在德频。代碼內(nèi)容如下(應(yīng)該很清晰了):

function require(...) {  
  var module = { exports: {} };
  ((module, exports) => {
    // 你的被引入代碼 Start
    // var exports = module.exports = {}; (默認(rèn)都有的)
    function some_func() {};
    exports = some_func;
    // 此時(shí)苍息,exports不再掛載到module.exports,
    // export將導(dǎo)出{}默認(rèn)對(duì)象
    module.exports = some_func;
    // 此時(shí)壹置,這個(gè)模塊將導(dǎo)出some_func對(duì)象竞思,覆蓋exports上的some_func    
     // 你的被引入代碼 End
  })(module, module.exports);
 // 不管是exports還是module.exports,最后返回的還是module.exports 
  return module.exports;
}

最后钞护,這個(gè)坑跳的真的值8桥纭!患亿!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末传蹈,一起剝皮案震驚了整個(gè)濱河市押逼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惦界,老刑警劉巖挑格,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異沾歪,居然都是意外死亡漂彤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門灾搏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挫望,“玉大人,你說我怎么就攤上這事狂窑∠卑澹” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵泉哈,是天一觀的道長(zhǎng)蛉幸。 經(jīng)常有香客問我,道長(zhǎng)丛晦,這世上最難降的妖魔是什么奕纫? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮烫沙,結(jié)果婚禮上匹层,老公的妹妹穿的比我還像新娘。我一直安慰自己锌蓄,他們只是感情好升筏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著煤率,像睡著了一般仰冠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝶糯,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天洋只,我揣著相機(jī)與錄音,去河邊找鬼昼捍。 笑死识虚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妒茬。 我是一名探鬼主播担锤,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼乍钻!你這毒婦竟也來(lái)了肛循?” 一聲冷哼從身側(cè)響起铭腕,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎多糠,沒想到半個(gè)月后累舷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夹孔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年被盈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搭伤。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡只怎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怜俐,到底是詐尸還是另有隱情身堡,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布拍鲤,位于F島的核電站盾沫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏殿漠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一佩捞、第九天 我趴在偏房一處隱蔽的房頂上張望绞幌。 院中可真熱鬧,春花似錦一忱、人聲如沸莲蜘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)票渠。三九已至,卻和暖如春芬迄,著一層夾襖步出監(jiān)牢的瞬間问顷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工禀梳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杜窄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓算途,卻偏偏與公主長(zhǎng)得像塞耕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘴瓤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 1 Webpack 1.1 概念簡(jiǎn)介 1.1.1 WebPack是什么 1扫外、一個(gè)打包工具 2莉钙、一個(gè)模塊加載工具 3...
    Kevin_Junbaozi閱讀 6,647評(píng)論 0 16
  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,064評(píng)論 0 1
  • Node.js是目前非常火熱的技術(shù)筛谚,但是它的誕生經(jīng)歷卻很奇特磁玉。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,612評(píng)論 2 41
  • JavaScript 標(biāo)準(zhǔn)參考教程(alpha) 草稿二:Node.js CommonJS規(guī)范 GitHub TO...
    鑨的傳人閱讀 444評(píng)論 0 1
  • Node.js是目前非晨袒瘢火熱的技術(shù)蜀涨,但是它的誕生經(jīng)歷卻很奇特。 眾所周知蝎毡,在Netscape設(shè)計(jì)出JavaScri...
    Myselfyan閱讀 4,066評(píng)論 2 58