跳坑之js调用另一个js文件中函数

最近在做electron的内容,但是踩了很多坑,其中一个坑:

问题背景:对于进程间的通信,实现带参数的输入输出,就是直接写一些函数,可以实现其他文件对于函数的调用

问题内容:其中一个js是实现功能函数(renderer.js),也就是带参数的输入输出,另一个js是调用这些功能(hello.js),那么如何实现这个调用过程呢?

我的hello.js和renderer.js在同一个文件夹下面。

来尝试一下网上的方法:

方法一:在html文件中body标签后加入js文件,在index.html中的body标签(</body>与</html>之间插入所引用的hello.js),代码如下:

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

然后,对于hello.js文件,为了调用renderer.js中的函数,需要在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中函数为test
    test(struct, buttonId, msg);
  }
testBtn('click', 'asynchronous message', 'ping');

对于代码,网上解释如下:
让我们来分析一下关键的几句代码:首先,我们利用document.createElement("script")生成了一个script的标签,设置其type属性为text/javascript,src为renderer.js(这里的renderer.js同hello.js放在同一个目录,也可放在不同的目录)。最后将这个标签动态地加入body中。如此一来,我们就可以调用到不同js文件中的方法了。

注意:<script language="JAVASCRIPT" src='b.js'></script>一定要放在body下面。
因为hello.js中用到了body(document.body.appendChild(new_element);)
如果将引如hello.js的代码放在body上面,也就是说,
进入页面后,还没有生成body就已经执行hello.js里的document.body.appendChild(new_element);了。
这时body不存在就会抛javascript错误。

而实际效果呢,并不行(至少我没有测试成功,目前还不知道原因出现在哪里,求告知!!)

方法二:在调用者程序的开始直接加入要被调用的js文件,代码如下:

//加入下面的代码
document.write("<script language=javascript src='./renderer.js'></script>");
//调用函数
test('click', 'asynchronous message', 'ping');

结果呵呵了。。。。。还是不行。。。。。又是一头雾水

方法三:在html文件中加入两个脚本程序,注意,加入的位置在</head>和<body>两个标签之间,(也有的在<body></body>两个标签之间加入的),代码如下:

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

之后在hello.js中直接调用函数就行。

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

然后呢?如果说前两种方法不行我还信了,毕竟没有看到执行结果,但是第三种人家明明成功了,而且两种加入的方法都成功了,到我这儿走不通了,几近崩溃。。。

冷静冷静,如果你试了试前面的方法也不行,一定要淡定,我也不知道怎么想的,然后试了一下下面这个方法。。竟然成功了!!

方法四:首先,在方法三的基础上,在html中直接利用require,将两个js文件直接加载进去,然后就可以实现调用了。
html中的代码:

//首先,方法三中的加入内容不变
</head>
  <script src="hello.js"></script>
  <script src="renderer.js"></script>
  <body>
    <!--- body内容--->

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

至于调用函数的代码,与方法三一样,直接在hello.js中调用即可。

解释解释,知其然必须知其所以然(个人理解):
对于方法三,为什么不行呢?我打开electron调试工具的时候,第一次加载页面时,输出了这个信息(极为重要):
test is not defined----我的test函数没有被定义,为什么没有被定义,我明明已经写好了的,看一下方法三中的加载顺序,先加载的hello.js,之后加载的renderer.js,也就是说,先加载了的hello.js中的test方法没有被定义,然后自然函数执行不成功。
看了看程序,发现方法四的加载顺序与方法三完全相反,在查看了文档之后,发现方法三与方法四的加载的最终结果并没有什么不同,只不过:require引入的的文件,内部声明的最外层变量不属于全局变量,而script引入的属于全局变量。

最重要的信息:
如果用script引入需要考虑引入顺序,避免变量冲突和前置依赖。考虑顺序,考虑顺序,考虑顺序,重要的事情说三遍(之后自己也试了试,把方法三的顺序颠倒,发现可以,之所以没删除这些内容,是想记得更清,也避免让更多的人入坑)

哈哈哈哈,脑子真的被门给夹了,这个坑跳的真的值(说的我自己都信了)
不过,以方法三加载脚本程序的方法并不好:
(来自阮一峰先生的日志:http://www.ruanyifeng.com/blog/2012/11/require_js.html) 首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

最后,介绍一种我最喜欢的方式,对于功能的封装这种方式应该再好不过了,exports和require大法好。

在nodejs中,提供了exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。而在exports抛出的接口中,我们可以抛出变量或者函数。
如果你希望你的模块就想为一个特别的对象类型,请使用module.exports;如果希望模块成为一个传统的模块实例,请使用exports.xx方法;module.exports才是真正的接口,exports只不过是它的一个辅助工具。最终返回给调用的是module.exports而不是exports。
总而言之,二者的关系是:

    exports 是指向的 module.exports 的引用,二者指向同一块内存
    module.exports 初始值为一个空对象 {},所以 exports 初始值也是 {}
    require() 返回的是 module.exports 而不是 exports

下面给出代码:
renderer.js中使用exports导出函数:

//在这里面写好函数的封装,然后在hello.js中调用
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("调用成功");
                break;
            default:
                console.log('Error!!!')
        }
    })
}
//这种方式是成功的
exports.test = test;
//这种方式也是可以得
//module.exports.test = test;

而hello.js中对于代码的使用如下:

//利用require加载模块
const renderer = require('./renderer')

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

可以说,这种方式完全符合我们程序封装的概念,思路统一,结构规整,个人最爱。而且,上面的程序中两种方法都可以输出成功,其原因就在于:
exports变量是在模块的文件级别作用域内有效的,它在模块被执行前被赋于 module.exports 的值。它有一个快捷方式,以便 module.exports.f = ... 可以被更简洁地写成exports.f = ...。 注意,就像任何变量,如果一个新的值被赋值给exports,它就不再绑定到module.exports(其实是exports.xx会自动挂载到没有命名冲突的module.exports.xx)
而且,对于require函数,exports只是函数内部一个局部变量,最后返回的仍是module.exports,这应该就是exports称为module.exports的引用所在。代码内容如下(应该很清晰了):

function require(...) {  
  var module = { exports: {} };
  ((module, exports) => {
    // 你的被引入代码 Start
    // var exports = module.exports = {}; (默认都有的)
    function some_func() {};
    exports = some_func;
    // 此时,exports不再挂载到module.exports,
    // export将导出{}默认对象
    module.exports = some_func;
    // 此时,这个模块将导出some_func对象,覆盖exports上的some_func    
     // 你的被引入代码 End
  })(module, module.exports);
 // 不管是exports还是module.exports,最后返回的还是module.exports 
  return module.exports;
}

最后,这个坑跳的真的值!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容