如何在一个JavaScript文件中包含另外的 JavaScript 文件?

如何在 JavaScript 文件中包含另一个JavaScript 文件,类似于 CSS 中的@import

4095980 次浏览

可以动态生成JavaScript标记并将其附加到其他JavaScript代码中的超文本标记语言文档中。这将加载目标JavaScript文件。

function includeJs(jsFilePath) {var js = document.createElement("script");
js.type = "text/javascript";js.src = jsFilePath;
document.body.appendChild(js);}
includeJs("/path/to/some/file.js");

也许你可以使用我在这个页面如何在JavaScript文件中包含JavaScript文件?上找到的这个函数:

function include(filename){var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');script.src = filename;script.type = 'text/javascript';
head.appendChild(script)}

旧版本的JavaScript没有导入、包含或要求,因此开发了许多不同的方法来解决这个问题。

但自2015年(ES6)以来,JavaScript已经有了es6模块标准来导入Node.js中的模块,大多数现代浏览器也支持这一标准。

为了与旧浏览器兼容,可以使用webpack汇总等构建工具和/或巴别塔等转译工具。

ES6模块

ECMAScript(ES6)模块自v8.5以来一直是支持Node.js,带有--experimental-modules标志,并且至少从Node.jsv13.8.0开始没有该标志。要启用“ESM”(与Node.js以前的Common JS风格模块系统[“CJS”]相比),您可以在package.json中使用"type": "module",或者为文件提供扩展名.mjs。(类似地,如果您的默认值是ESM,则使用Node.js以前的CJS模块编写的模块可以命名为.cjs。)

使用package.json

{"type": "module"}

然后module.js

export function hello() {return "Hello";}

然后main.js

import { hello } from './module.js';let val = hello();  // val is "Hello";

使用.mjs,您将获得module.mjs

export function hello() {return "Hello";}

然后main.mjs

import { hello } from './module.mjs';let val = hello();  // val is "Hello";

浏览器中的ECMAScript模块

浏览器已经支持直接加载ECMAScript模块(不需要像Webpack这样的工具)以来Safari10.1、Chrome61、Firefox 60和Edge 16。在caniuse处检查当前支持。不需要使用Node.js.mjs扩展名;浏览器完全忽略模块/脚本上的文件扩展名。

<script type="module">import { hello } from './hello.mjs'; // Or the extension could be just `.js`hello('world');</script>
// hello.mjs -- or the extension could be just `.js`export function hello(text) {const div = document.createElement('div');div.textContent = `Hello ${text}`;document.body.appendChild(div);}

阅读更多https://jakearchibald.com/2017/es-modules-in-browsers/

浏览器中的动态导入

动态导入允许脚本根据需要加载其他脚本:

<script type="module">import('hello.mjs').then(module => {module.hello('world');});</script>

阅读更多https://developers.google.com/web/updates/2017/11/dynamic-import

Node.js需要

旧的CJS模块风格,仍然广泛用于Node.js,是#0/#1系统。

// mymodule.jsmodule.exports = {hello: function() {return "Hello";}}
// server.jsconst myModule = require('./mymodule');let val = myModule.hello(); // val is "Hello"

JavaScript还有其他方法可以在不需要预处理的浏览器中包含外部JavaScript内容。

AJAX加载

您可以使用AJAX调用加载附加脚本,然后使用eval运行它。这是最直接的方法,但由于JavaScript砂箱安全模型,它仅限于您的域。使用eval也为错误、黑客攻击和安全问题打开了大门。

抓取加载

与动态导入一样,您可以使用fetch调用加载一个或多个脚本,使用取注射液库控制脚本依赖项的执行顺序:

fetchInject(['https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js']).then(() => {console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)})

jQuery加载

jQuery库提供加载功能在一条线

$.getScript("my_lovely_script.js", function() {alert("Script loaded but not necessarily executed.");});

动态脚本加载

您可以将带有脚本URL的脚本标记添加到超文本标记语言中。为了避免jQuery的开销,这是一个理想的解决方案。

脚本甚至可以驻留在不同的服务器上。此外,浏览器评估代码。<script>标签可以注入网页<head>,也可以插入关闭</body>标签之前。

下面是一个如何工作的例子:

function dynamicallyLoadScript(url) {var script = document.createElement("script");  // create a script DOM nodescript.src = url;  // set its src to the provided URL   
document.head.appendChild(script);  // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)}

此函数将在页面的head部分末尾添加一个新的<script>标记,其中src属性设置为作为第一个参数提供给函数的URL。

这两种解决方案都在JavaScript疯狂:动态脚本加载中进行了讨论和说明。

检测脚本何时被执行

现在,有一个你必须知道的大问题。这样做意味着你远程加载代码。现代Web浏览器将加载文件并继续执行您当前的脚本,因为它们异步加载所有内容以提高性能。(这适用于jQuery方法和手动动态脚本加载方法。)

这意味着如果你直接使用这些技巧,在您要求加载新加载的代码后,您将无法在下一行使用它,因为它仍然会加载。

例如:my_lovely_script.js包含MySuperObject

var js = document.createElement("script");
js.type = "text/javascript";js.src = jsFilePath;
document.body.appendChild(js);
var s = new MySuperObject();
Error : MySuperObject is undefined

然后你重新加载点击F5的页面。它起作用了!困惑…

那么该怎么办呢?

嗯,你可以使用作者在我给你的链接中建议的hack。总之,对于匆忙的人来说,他使用一个事件在脚本加载时运行回调函数。所以你可以把所有使用远程库的代码放在回调函数中。例如:

function loadScript(url, callback){// Adding the script tag to the head as suggested beforevar head = document.head;var script = document.createElement('script');script.type = 'text/javascript';script.src = url;
// Then bind the event to the callback function.// There are several events for cross browser compatibility.script.onreadystatechange = callback;script.onload = callback;
// Fire the loadinghead.appendChild(script);}

然后在脚本加载到lambda函数中后编写要使用的代码:

var myPrettyCode = function() {// Here, do whatever you want};

然后你运行所有这些:

loadScript("my_lovely_script.js", myPrettyCode);

请注意,脚本可能会在DOM加载之后或之前执行,具体取决于浏览器以及您是否包含script.async = false;行。有一个关于JavaScript加载的优秀文章讨论了这一点。

源代码合并/预处理

正如在这个答案的顶部提到的,许多开发人员在他们的项目中使用像Parcel,Webpack或Babel这样的构建/转换工具,允许他们使用即将推出的JavaScript语法,为旧浏览器提供向后兼容性,合并文件,缩小,执行代码拆分等。

我刚刚写了这段JavaScript代码(使用原型进行DOM操作):

var require = (function() {var _required = {};return (function(url, callback) {if (typeof url == 'object') {// We've (hopefully) got an array: time to chain!if (url.length > 1) {// Load the nth file as soon as everything up to the// n-1th one is done.require(url.slice(0, url.length - 1), function() {require(url[url.length - 1], callback);});} else if (url.length == 1) {require(url[0], callback);}return;}if (typeof _required[url] == 'undefined') {// Haven't loaded this URL yet; gogogo!_required[url] = [];
var script = new Element('script', {src: url,type: 'text/javascript'});script.observe('load', function() {console.log("script " + url + " loaded.");_required[url].each(function(cb) {cb.call(); // TODO: does this execute in the right context?});_required[url] = true;});
$$('head')[0].insert(script);} else if (typeof _required[url] == 'boolean') {// We already loaded the thing, so go ahead.if (callback) {callback.call();}return;}
if (callback) {_required[url].push(callback);}});})();

用法:

<script src="prototype.js"></script><script src="require.js"></script><script>require(['foo.js','bar.js'], function () {/* Use foo.js and bar.js here */});</script>

Gist:http://gist.github.com/284442.

您还可以使用php组装脚本:

文件main.js.php

<?phpheader('Content-type:text/javascript; charset=utf-8');include_once("foo.js.php");include_once("bar.js.php");?>
// Main JavaScript code goes here

实际上是一种异步加载JavaScript文件没有的方法,因此您可以在加载后立即使用新加载文件中包含的函数,我认为它适用于所有浏览器。

您需要在页面的<head>元素上使用jQuery.append(),即:

$("head").append($("<script></script>").attr("src", url));
/* Note that following line of code is incorrect because it doesn't escape the* HTML attribute src correctly and will fail if `url` contains special characters:* $("head").append('<script src="' + url + '"></script>');*/

但是,这种方法也有一个问题:如果在导入的JavaScript文件中发生错误,Firebug(以及Firefox Error Console和Chrome开发工具)将错误地报告其位置,如果您使用Firebug跟踪JavaScript错误很多(我这样做),这将是一个大问题。Firebug出于某种原因根本不知道新加载的文件,因此如果该文件中发生错误,它会报告它发生在您的主超文本标记语言文件中,您将难以找到错误的真正原因。

但如果这对你来说不是问题,那么这个方法应该有效。

我实际上编写了一个名为$.import_js()的jQuery插件,它使用这种方法:

(function($){/** $.import_js() helper (for JavaScript importing within JavaScript code).*/var import_js_imported = [];    
$.extend(true,{import_js : function(script){var found = false;for (var i = 0; i < import_js_imported.length; i++)if (import_js_imported[i] == script) {found = true;break;}            
if (found == false) {$("head").append($('<script></script').attr('src', script));import_js_imported.push(script);}}});    
})(jQuery);

因此,导入JavaScript需要做的就是:

$.import_js('/path_to_project/scripts/somefunctions.js');

我在示例也做了一个简单的测试。

它在主超文本标记语言中包含一个main.js文件,然后main.js中的脚本使用$.import_js()导入一个名为included.js的附加文件,该文件定义了此函数:

function hello(){alert("Hello world!");}

在包含included.js之后,调用hello()函数,您会收到警报。

(这个答案是对e-satis评论的回应)。

另一种方式,在我看来要干净得多,是发出同步Ajax请求而不是使用<script>标记。这也是Node.js处理包括的方式。

下面是一个使用jQuery的示例:

function require(script) {$.ajax({url: script,dataType: "script",async: false,           // <-- This is the keysuccess: function () {// all good...},error: function () {throw new Error("Could not load script " + script);}});}

然后,您可以像通常使用包含一样在代码中使用它:

require("/scripts/subscript.js");

并且能够在下一行中从所需脚本调用函数:

subscript.doSomethingCool();

我提出这个问题是因为我正在寻找一种简单的方法来维护一组有用的JavaScript插件。在看到这里的一些解决方案后,我想到了这个:

  1. 设置一个名为“plugins.js”(或extensions.js或任何你想要的)的文件。将插件文件与那个主目录保存在一起。

  2. plugins.js将有一个名为pluginNames[]的数组,我们将迭代each(),然后将<script>标记附加到每个插件的头部

//set array to be updated when we add or remove plugin filesvar pluginNames = ["lettering", "fittext", "butterjam", etc.];
//one script tag for each plugin$.each(pluginNames, function(){$('head').append('<script src="js/plugins/' + this + '.js"></script>');});
  1. 手动调用头脑中的一个文件:
    <script src="js/plugins/plugins.js"></script>

但是:

尽管所有的插件都以应有的方式被放入head标签中,但当您单击页面或刷新时,它们并不总是由浏览器运行。

我发现在PHP包含中编写脚本标签更可靠。您只需编写一次,这与使用JavaScript调用插件一样多。

我创建了一个函数,允许您使用类似于C#/Java的措辞来包含一个JavaScript文件。我甚至从另一个 JavaScript文件内部对其进行了一点测试,它似乎可以工作。它确实需要jQuery,尽管最后有点“魔力”。

我把这段代码放在我的脚本目录根目录下的一个文件中(我把它命名为global.js,但是你可以使用任何你想要的东西。除非我弄错了,jQuery应该是给定页面上唯一需要的脚本。请记住,除了一些基本的用法之外,这在很大程度上是未经测试的,所以我这样做的方式可能有也可能没有任何问题;使用yadda yadda需要您自己承担风险,如果你搞砸了任何事情,我不负责:

/*** @fileoverview This file stores global functions that are required by other libraries.*/
if (typeof(jQuery) === 'undefined') {throw 'jQuery is required.';}
/** Defines the base script directory that all .js files are assumed to be organized under. */var BASE_DIR = 'js/';
/*** Loads the specified file, outputting it to the <head> HTMLElement.** This method mimics the use of using in C# or import in Java, allowing* JavaScript files to "load" other JavaScript files that they depend on* using a familiar syntax.** This method assumes all scripts are under a directory at the root and will* append the .js file extension automatically.** @param {string} file A file path to load using C#/Java "dot" syntax.** Example Usage:* imports('core.utils.extensions');* This will output: <script type="text/javascript" src="/js/core/utils/extensions.js"></script>*/function imports(file) {var fileName = file.substr(file.lastIndexOf('.') + 1, file.length);
// Convert PascalCase name to underscore_separated_namevar regex = new RegExp(/([A-Z])/g);if (regex.test(fileName)) {var separated = fileName.replace(regex, ",$1").replace(',', '');fileName = separated.replace(/[,]/g, '_');}
// Remove the original JavaScript file name to replace with underscore versionfile = file.substr(0, file.lastIndexOf('.'));
// Convert the dot syntax to directory syntax to actually load the fileif (file.indexOf('.') > 0) {file = file.replace(/[.]/g, '/');}
var src = BASE_DIR + file + '/' + fileName.toLowerCase() + '.js';var script = document.createElement('script');script.type = 'text/javascript';script.src = src;
$('head').find('script:last').append(script);}

在过去的一个项目中,我使用ajile导入可重用的JavaScript文件取得了相当大的成功。我一直希望JavaScript本身中内置有一个功能。

或者,与其在运行时包含,不如在上载之前使用脚本进行连接。

我使用链轮(我不知道是否还有其他)。你在单独的文件中构建你的JavaScript代码,并包含由链轮引擎作为包含处理的注释。对于开发,你可以顺序包含文件,然后对于生产来合并它们…

另见:

如果有人正在寻找更高级的东西,请尝试是否必填。您将获得额外的好处,例如依赖关系管理、更好的并发性和避免重复(即多次检索脚本)。

您可以在“模块”中编写JavaScript文件,然后在其他脚本中将它们作为依赖项引用。或者您可以使用DeepreJS作为一个简单的“获取此脚本”解决方案。

示例:

将依赖定义为模块:

some-dependency.js

define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {
//Your actual script goes here.//The dependent scripts will be fetched if necessary.
return libraryObject;  //For example, jQuery object});

implementation.js是依赖于some-dependency.js的“主”JavaScript文件

require(['some-dependency'], function(dependency) {
//Your script goes here//some-dependency.js is fetched.//Then your script is executed});

摘自github README:

需要JS加载纯JavaScript文件以及更多定义模块。它针对浏览器内使用进行了优化,包括在Web中Worker,但它可以在其他JavaScript环境中使用,例如Rhino和Node。它实现了异步模块API。

需要JS使用纯脚本标签来加载模块/文件,所以它应该允许轻松调试。它可以简单地用于加载现有的JavaScript文件,因此您可以将其添加到现有项目中,而无需必须重写您的JavaScript文件。

对您来说有一个好消息。很快您将能够轻松加载JavaScript代码。它将成为导入JavaScript代码模块的标准方式,并将成为JavaScript核心本身的一部分。

您只需编写import cond from 'cond.js';即可从文件cond.js加载名为cond的宏。

因此,您不必依赖任何JavaScript框架,也不必显式地进行Ajax调用。

参考:

var js = document.createElement("script");
js.type = "text/javascript";js.src = jsFilePath;
document.body.appendChild(js);

最好使用jQuery方式。要延迟就绪事件,请先调用$.holdReady(true)。示例(来源):

$.holdReady(true);$.getScript("myplugin.js", function() {$.holdReady(false);});

别忘了看看LAB.js

<script type="text/javascript">$LAB.script("jquery-1.8.3.js").wait().script("scripts/clientscript.js");</script>

现在,我可能完全被误导了,但这是我最近开始做的事情……使用回车开始和结束您的JavaScript文件,放在PHP脚本中,然后再进行一次回车。JavaScript注释“//”被PHP忽略,因此无论如何都会发生包含。回车的目的是使包含的JavaScript的第一行不会被注释掉。

从技术上讲,您不需要注释,但它在Dreamweaver中发布了令我恼火的错误。如果您在不发布错误的IDE中编写脚本,您不应该需要注释或回车。

\n//<?php require_once("path/to/javascript/dependency.js"); ?>
function myFunction(){// stuff}\n
var s=["Hscript.js","checkRobert.js","Hscript.js"];for(i=0;i<s.length;i++){var script=document.createElement("script");script.type="text/javascript";script.src=s[i];document.getElementsByTagName("head")[0].appendChild(script)};

这应该做:

xhr = new XMLHttpRequest();xhr.open("GET", "/soap/ajax/11.0/connection.js", false);xhr.send();eval(xhr.responseText);

我编写了一个简单的模块,可以自动在JavaScript中导入/包含模块脚本。有关代码的详细解释,请参阅博客文章JavaScript需要/导入/包括模块

// ----- USAGE -----
require('ivar.util.string');require('ivar.net.*');require('ivar/util/array.js');require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js');
ready(function(){//Do something when required scripts are loaded});
//--------------------
var _rmod = _rmod || {}; //Require module namespace_rmod.LOADED = false;_rmod.on_ready_fn_stack = [];_rmod.libpath = '';_rmod.imported = {};_rmod.loading = {scripts: {},length: 0};
_rmod.findScriptPath = function(script_name) {var script_elems = document.getElementsByTagName('script');for (var i = 0; i < script_elems.length; i++) {if (script_elems[i].src.endsWith(script_name)) {var href = window.location.href;href = href.substring(0, href.lastIndexOf('/'));var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);return url.substring(href.length+1, url.length);}}return '';};
_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark//the root directory of your library, any library.

_rmod.injectScript = function(script_name, uri, callback, prepare) {
if(!prepare)prepare(script_name, uri);
var script_elem = document.createElement('script');script_elem.type = 'text/javascript';script_elem.title = script_name;script_elem.src = uri;script_elem.async = true;script_elem.defer = false;
if(!callback)script_elem.onload = function() {callback(script_name, uri);};document.getElementsByTagName('head')[0].appendChild(script_elem);};
_rmod.requirePrepare = function(script_name, uri) {_rmod.loading.scripts[script_name] = uri;_rmod.loading.length++;};
_rmod.requireCallback = function(script_name, uri) {_rmod.loading.length--;delete _rmod.loading.scripts[script_name];_rmod.imported[script_name] = uri;
if(_rmod.loading.length == 0)_rmod.onReady();};
_rmod.onReady = function() {if (!_rmod.LOADED) {for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){_rmod.on_ready_fn_stack[i]();});_rmod.LOADED = true;}};
_.rmod = namespaceToUri = function(script_name, url) {var np = script_name.split('.');if (np.getLast() === '*') {np.pop();np.push('_all');}
if(!url)url = '';
script_name = np.join('.');return  url + np.join('/')+'.js';};
//You can rename based on your liking. I chose require, but it//can be called include or anything else that is easy for you//to remember or write, except "import", because it is reserved//for future use.var require = function(script_name) {var uri = '';if (script_name.indexOf('/') > -1) {uri = script_name;var lastSlash = uri.lastIndexOf('/');script_name = uri.substring(lastSlash+1, uri.length);}else {uri = _rmod.namespaceToUri(script_name, ivar._private.libpath);}
if (!_rmod.loading.scripts.hasOwnProperty(script_name)&& !_rmod.imported.hasOwnProperty(script_name)) {_rmod.injectScript(script_name, uri,_rmod.requireCallback,_rmod.requirePrepare);}};
var ready = function(fn) {_rmod.on_ready_fn_stack.push(fn);};

我常用的方法是:

var require = function (src, cb) {cb = cb || function () {};
var newScriptTag = document.createElement('script'),firstScriptTag = document.getElementsByTagName('script')[0];newScriptTag.src = src;newScriptTag.async = true;newScriptTag.onload = newScriptTag.onreadystatechange = function () {(!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());};firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);}

它工作得很好,对我来说没有页面重载。我尝试过AJAX方法(其他答案之一),但它似乎对我来说效果不佳。

下面是对那些好奇的人的代码工作原理的解释:本质上,它创建了URL的新脚本标记(在第一个标记之后)。它将其设置为异步模式,因此不会阻止其余代码,但当readyState(要加载的内容的状态)更改为“已加载”时调用回调。

这里显示的大多数解决方案都意味着动态加载。我正在寻找一个编译器,它将所有依赖的文件组装成一个输出文件。与更少/萨斯预处理器处理CSS@import at规则相同。由于我没有找到任何类似的东西,我写了一个简单的工具来解决这个问题。

所以这是编译器https://github.com/dsheiko/jsic,它安全地将$import("file-path")替换为请求的文件内容。这是相应的Grunt插件:https://github.com/dsheiko/grunt-jsic

在jQuery主分支上,他们只是将原子源文件连接成一个从intro.js开始到outtro.js结束的源文件。这不适合我,因为它在源代码设计上没有提供灵活性。看看它是如何与jsic一起工作的:

src/main.js

var foo = $import("./Form/Input/Tel");

src/表单/输入/Tel.js

function() {return {prop: "",method: function(){}}}

现在我们可以运行编译器:

node jsic.js src/main.js build/mail.js

拿到合并文件

构建/main.js

var foo = function() {return {prop: "",method: function(){}}};

此脚本将在任何其他<script>标记的顶部添加一个JavaScript文件:

(function () {var li = document.createElement('script');li.type = 'text/javascript';li.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js";li.async = true;var s = document.getElementsByTagName('script')[0];s.parentNode.insertBefore(li, s);})();

这是一个Grunt插件,允许您在包括JavaScript文件在内的任何文件中使用@import "path/to/file.js";语法。它可以与uglify或watch或任何其他插件配对。

它可以使用npm install安装:https://npmjs.org/package/grunt-import

如果你想要纯JavaScript,你可以使用document.write

document.write('<script src="myscript.js" type="text/javascript"></script>');

如果你使用jQuery库,你可以使用$.getScript方法。

$.getScript("another_script.js");

还有Head.js。很容易处理:

head.load("js/jquery.min.js","js/jquery.someplugin.js","js/jquery.someplugin.css", function() {alert("Everything is ok!");});

如您所见,它比Require.js更容易,并且与jQuery的$.getScript方法一样方便。它还具有一些高级功能,例如条件加载、特征检测和更多

这是同步版本没有jQuery

function myRequire( url ) {var ajax = new XMLHttpRequest();ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronousajax.onreadystatechange = function () {var script = ajax.response || ajax.responseText;if (ajax.readyState === 4) {switch( ajax.status) {case 200:eval.apply( window, [script] );console.log("script loaded: ", url);break;default:console.log("ERROR: script not loaded: ", url);}}};ajax.send(null);}

请注意,要获得这个工作的跨域,服务器需要在其响应中设置allow-origin标头。

实现类似CSS的JavaScript导入的@import语法可以使用Mixture等工具通过其特殊的.mix文件类型(参见这里)实现。我假设应用程序通过上述方法之一做到这一点。

从Mixture留档.mix文件:

Mix文件是简单的. js或. css文件,文件名中包含。A混合文件只是扩展了正常样式或脚本文件,并允许您导入和组合。

这是一个示例.mix文件,它将多个.js文件组合成一个:

// scripts-global.mix.js// Plugins - Global
@import "global-plugins/headroom.js";@import "global-plugins/retina-1.1.0.js";@import "global-plugins/isotope.js";@import "global-plugins/jquery.fitvids.js";

Mixture将其输出为scripts-global.js,也将其输出为缩小版本(scripts-global.min.js)。

注意:除了将它用作前端开发工具之外,我与Mixture没有任何关系。我在看到.mix JavaScript文件时遇到了这个问题(在Mixture的一个样板中)并且对它有点困惑(“你能做到这一点?”我心想)。然后我意识到这是一种特定于应用程序的文件类型(有点令人失望,同意)。尽管如此,我想这些知识可能对其他人有所帮助。

备注: Mixture于2016/07/26停止(在2015/04/12开源后)。

如果您使用Web工作者并希望在工作进程的范围内包含其他脚本,则提供的关于将脚本添加到head标记等的其他答案将不适用于您。

幸运的是,Web Worker有自己的#0函数是Web Worker范围内的全局函数,原生于浏览器本身,因为它是规范的一部分

或者,投票数第二高的答案将突出显示是否必填也可以处理在Web Worker中包含脚本(可能调用importScripts本身,但具有一些其他有用的功能)。

这个问题有很多潜在的答案。我的答案显然是基于其中的一些。这是我通读所有答案后得出的结论。

$.getScript以及任何其他在加载完成时需要回调的解决方案的问题是,如果您有多个使用它并相互依赖的文件,则不再有办法知道何时加载了所有脚本(一旦它们嵌套在多个文件中)。

示例:

file3.js

var f3obj = "file3";
// Define other stuff

file2.js:

var f2obj = "file2";$.getScript("file3.js", function(){
alert(f3obj);
// Use anything defined in file3.});

file1.js:

$.getScript("file2.js", function(){alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.alert(f2obj);
// Use anything defined in the loaded script...});

您说您可以指定Ajax同步运行或使用XMLHttpRequest相关文档是对的,但目前的趋势似乎是弃用同步请求,因此您现在或将来可能无法获得完整的浏览器支持。

您可以尝试使用$.when来检查延迟对象的数组,但现在您在每个文件中都这样做,并且一旦$.when执行而不是回调执行时,file2将被视为已加载,因此file1仍然在file3加载之前继续执行。这仍然存在相同的问题。

我决定向后而不是向前。谢谢你document.writeln。我知道这是禁忌,但只要正确使用它,这就很好。你最终得到的代码可以轻松调试,正确显示在DOM中,并可以确保正确加载依赖项的顺序。

当然,您可以使用$("body"). append(),但这样您就不能再正确调试了。

注意:你只能在页面加载时使用它,否则你会得到一个空白屏幕。换句话说,总是把这个放在document.ready之前/之外。我还没有在页面加载到点击事件或类似事件中后测试使用它,但我很确定它会失败。

我喜欢扩展jQuery的想法,但显然你不需要。

在调用document.writeln之前,它通过评估所有脚本元素来检查以确保脚本尚未加载。

我假设脚本在其document.ready事件执行之前不会完全执行。(我知道不需要使用document.ready,但很多人使用它,处理这是一种保障。)

加载附加文件时,document.ready回调将以错误的顺序执行。为了在脚本实际加载时解决此问题,导入它的脚本本身会重新导入并停止执行。这会导致原始文件现在在其导入的任何脚本之后执行其document.ready回调。

而不是这种方法,你可以尝试修改jQueryreadyList,但这似乎是一个更糟糕的解决方案。

解决方案:

$.extend(true,{import_js : function(scriptpath, reAddLast){if (typeof reAddLast === "undefined" || reAddLast === null){reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.}
var found = false;if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.{found = $('script').filter(function () {return ($(this).attr('src') == scriptpath);}).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.}
if (found == false) {
var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.
document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln
if (reAddLast){$.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.}return true;}return false;}});

用法:

文件3:

var f3obj = "file3";
// Define other stuff$(function(){f3obj = "file3docready";});

文件2:

$.import_js('js/file3.js');var f2obj = "file2";$(function(){f2obj = "file2docready";});

文件1:

$.import_js('js/file2.js');
// Use objects from file2 or file3alert(f3obj); // "file3"alert(f2obj); // "file2"
$(function(){// Use objects from file2 or file3 some more.alert(f3obj); //"file3docready"alert(f2obj); //"file2docready"});

保持它漂亮,简短,简单,可维护!:]

// Third-party plugins / script (don't forget the full path is necessary)var FULL_PATH = '', s =[FULL_PATH + 'plugins/script.js'      // Script exampleFULL_PATH + 'plugins/jquery.1.2.js', // jQuery LibraryFULL_PATH + 'plugins/crypto-js/hmac-sha1.js',      // CryptoJSFULL_PATH + 'plugins/crypto-js/enc-base64-min.js'  // CryptoJS];
function load(url){var ajax = new XMLHttpRequest();ajax.open('GET', url, false);ajax.onreadystatechange = function (){var script = ajax.response || ajax.responseText;if (ajax.readyState === 4){switch(ajax.status){case 200:eval.apply( window, [script] );console.log("library loaded: ", url);break;default:console.log("ERROR: library not loaded: ", url);}}};ajax.send(null);}
// Initialize a single loadload('plugins/script.js');
// Initialize a full load of scriptsif (s.length > 0){for (i = 0; i < s.length; i++){load(s[i]);}}

此代码只是一个简短的功能示例,可以需要额外的功能功能才能在任何(或给定)平台上获得完全支持。

语句#0在ECMAScript 6中。

语法

import name from "module-name";import { member } from "module-name";import { member as alias } from "module-name";import { member1 , member2 } from "module-name";import { member1 , member2 as alias2 , [...] } from "module-name";import name , { member [ , [...] ] } from "module-name";import "module-name" as name;

以下是Facebook为其无处不在的喜欢按钮所做的通用版本:

<script>var firstScript = document.getElementsByTagName('script')[0],js = document.createElement('script');js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';js.onload = function () {// do stuff with your dynamically loaded scriptsnowStorm.snowColor = '#99ccff';};firstScript.parentNode.insertBefore(js, firstScript);</script>

如果它适用于Facebook,它将适用于您。

我们寻找第一个script元素而不是headbody的原因是,如果缺少,某些浏览器不会创建一个,但我们保证有一个script元素-这个。在http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/阅读更多。

我有一个简单的问题,但我对这个问题的回答感到困惑。

我必须在另一个JavaScript文件(main.js)中使用一个JavaScript文件(myvariables.js)中定义的变量(myVar1)。

为此,我做了如下:

以正确的顺序将JavaScript代码加载到超文本标记语言文件中,myvariables.js,然后main.js:

<html><body onload="bodyReady();" >
<script src="myvariables.js" > </script><script src="main.js" > </script>
<!-- Some other code --></body></html>

文件:myvariables.js

var myVar1 = "I am variable from myvariables.js";

文件:main.js

// ...function bodyReady() {// ...alert (myVar1);    // This shows "I am variable from myvariables.js", which I needed// ...}// ...

如您所见,我在另一个JavaScript文件中的一个JavaScript文件中使用了一个变量,但我不需要在另一个JavaScript文件中包含一个变量。我只需要确保第一个JavaScript文件在第二个JavaScript文件之前加载,并且,第一个JavaScript文件的变量可以在第二个JavaScript文件中自动访问。

这拯救了我的一天。我希望这能有所帮助。

如果您加载JavaScript文件的意图是使用导入/包含文件中的函数,您还可以定义一个全局对象并将函数设置为对象项。例如:

global.js

A = {};

file1.js

A.func1 = function() {console.log("func1");}

file2.js

A.func2 = function() {console.log("func2");}

main.js

A.func1();A.func2();

当您在超文本标记语言文件中包含脚本时,您只需要小心。顺序应该如下所示:

<head><script type="text/javascript" src="global.js"></script><script type="text/javascript" src="file1.js"></script><script type="text/javascript" src="file2.js"></script><script type="text/javascript" src="main.js"></script></head>

我基本上像下面这样做,创建一个新元素并将其附加到head:

var x = document.createElement('script');x.src = 'http://example.com/test.js';document.getElementsByTagName("head")[0].appendChild(x);

jQuery

// jQuery$.getScript('/path/to/imported/script.js', function(){// Script is now loaded and executed.// Put your dependent JavaScript code here.});

我需要异步加载一个JavaScript文件数组,并在最后进行回调。基本上,我最好的方法如下:

// Load a JavaScript file from other JavaScript filefunction loadScript(urlPack, callback) {var url = urlPack.shift();var subCallback;
if (urlPack.length == 0) subCallback = callback;else subCallback = function () {console.log("Log script: " + new Date().getTime());loadScript(urlPack, callback);}
// Adding the script tag to the head as suggested beforevar head = document.getElementsByTagName('head')[0];var script = document.createElement('script');script.type = 'text/javascript';script.src = url;
// Then bind the event to the callback function.// There are several events for cross browser compatibility.script.onreadystatechange = subCallback;script.onload = subCallback;
// Fire the loadinghead.appendChild(script);}

示例:

loadScript(["js/DataTable/jquery.dataTables.js","js/DataTable/dataTables.bootstrap.js","js/DataTable/dataTables.buttons.min.js","js/DataTable/dataTables.colReorder.min.js","js/DataTable/dataTables.fixedHeader.min.js","js/DataTable/buttons.bootstrap.min.js","js/DataTable/buttons.colVis.min.js","js/DataTable/buttons.html5.min.js"], function() { gpLoad(params); });

第二个脚本在第一个脚本完全加载之前不会加载,因此…

结果:

结果

你不能导入,但你可以引用。

PhpShtorm IDE。要引用,在一个.js文件中到另一个.js,只需将其添加到文件顶部:

<reference path="../js/file.js" />

当然,您应该对JavaScript文件使用自己的PATH。

我不知道它是否适用于其他IDE。可能是的,试试看。它应该也适用于Visual Studio。

也许还有另一种方式!

在Node.js你可以这样做,就像下面的代码显示!

sub.js

    module.exports = {log: function(string) {if(console) console.log(string);}mylog: function(){console.log('just for log test!');}}

main.js

    const mylog = require('./sub');
mylog.log('Hurray, it works! :)');mylog.mylog();

裁判

http://requirejs.org/docs/node.html

var xxx = require("../lib/your-library.js")

import xxx from "../lib/your-library.js" //get default exportimport {specificPart} from '../lib/your-library.js' //get named exportimport * as _name from '../lib/your-library.js'  //get full export to alias _name

另一种方法是使用超文本标记语言导入。这些可以包含脚本引用以及样式表引用。

你可以链接一个超文本标记语言文件

<link rel="import" href="vendorScripts.html"/>

vendorScripts.html文件中,您可以包含您的脚本引用,例如:

<script src="scripts/vendors/jquery.js"></script><script src="scripts/vendors/bootstrap.js"></script><script src="scripts/vendors/angular.js"></script><script src="scripts/vendors/angular-route.js"></script>

查看超文本标记语言导入了解更多详细信息。

不幸的是,这只适用于Chrome。

如果您使用Angular,那么插件模块$ocLazyLoad可以帮助您做到这一点。

以下是其留档中的一些引文:

加载一个或多个包含多个文件的模块和组件:

$ocLazyLoad.load(['testModule.js', 'testModuleCtrl.js', 'testModuleService.js']);

加载一个或多个包含多个文件的模块,并在必要时指定类型:注意:当使用请求JS样式格式时(例如以js!开头),不要指定文件扩展名。使用一个或另一个。

$ocLazyLoad.load(['testModule.js',{type: 'css', path: 'testModuleCtrl'},{type: 'html', path: 'testModuleCtrl.html'},{type: 'js', path: 'testModuleCtrl'},'js!testModuleService','less!testModuleLessFile']);

您可以加载外部库(不是角度):

$ocLazyLoad.load(['testModule.js','bower_components/bootstrap/dist/js/bootstrap.js', 'anotherModule.js']);

您还可以加载css和模板文件:

 $ocLazyLoad.load(['bower_components/bootstrap/dist/js/bootstrap.js','bower_components/bootstrap/dist/css/bootstrap.css','partials/template1.html']);

这是一个使用超文本标记语言导入的解决方法为浏览器(不是Node.js)。

首先,所有JavaScript类和脚本都不在.js文件中,而是在.js.html文件中(. js.html只是为了识别超文本标记语言页面和完整的JavaScript脚本/类),在<script>标签中,如下所示:

MyClass.js.html

<script>class MyClass {
// Your code here..
}
</script>

然后,如果你想导入你的类,你只需要使用超文本标记语言导入:

<link rel="import" href="relative/path/to/MyClass.js.html"/>
<script>var myClass = new MyClass();// Your code here..</script>

编辑:超文本标记语言导入将被删除

超文本标记语言导入被删除,支持ES6模块。你应该使用ES6模块。

很简单,假设你想导入文件A.jsB.js.

现在确定您已经在超文本标记语言文件中链接了B.js,然后只需在超文本标记语言文件中B.js之前链接A.js。然后A.js的公共变量将在B.js中可用

这并不需要一个复杂的答案。

在现代语言中,检查脚本是否已经加载,它将是:

function loadJs( url ){return new Promise(( resolve, reject ) => {if (document.querySelector( `head > script[ src = "${url}" ]`) !== null ){console.warn( `script already loaded: ${url}` );resolve();}const script = document.createElement( "script" );script.src = url;script.onload = resolve;script.onerror = function( reason ){// This can be useful for your error-handling codereason.message = `error trying to load script ${url}`;reject( reason );};document.head.appendChild( script );});}

用法(异步/等待):

try { await loadJs("https://.../script.js"); }catch(error) { console.log(error); }

await loadJs( "https://.../script.js" ).catch( err => {} );

用法(Promise):

loadJs( "https://.../script.js" ).then( res => {} ).catch( err => {} );

虽然这些答案都很棒,但是自从脚本加载存在以来,就有一个简单的“解决方案”,它将覆盖99.999%的大多数人的用例。只需在需要它的脚本之前包含您需要的脚本。对于大多数项目,不需要很长时间即可确定需要哪些脚本以及以什么顺序。

<!DOCTYPE HTML><html><head><script src="script1.js"></script><script src="script2.js"></script></head><body></body></html>

如果script2需要script1,这确实是做这样的事情的绝对最简单的方法。我很惊讶没有人提出这个问题,因为这是几乎适用于每种情况的最明显和最简单的答案。

请注意,我们通常使用静态脚本。所以我们希望尽可能地从缓存中取出。

这节省了流量并加快了着陆速度。

用法

$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {console.log( textStatus );});

缓存:true选项已添加到Ajax方法中。

如果您发现有两个或多个脚本在调用时占用相同的函数,并且我们不能同时包含它们,我们需要通过用户选择来执行动态

使用$.getScript在jQuery中包含另一个文件,因为脚本默认情况下,不会被缓存起作用。所以我们可以安全地调用其他脚本。调用可以这样安排:

超文本标记语言

<select class="choice"><option value="script1" selected>Script-1</option><option value="script2">Script-2</option></select>

JavaScript

$(".choice").change(on_change);
var url = "https://example.com";$.url1 = url + "/script1.js";$.url2 = url + "/script2.js";
function on_change() {if ($(".choice").val()=="script1") {script1();} else {script2();}}
// script1function script1() {$.getScript($.url1, function( data, textStatus, jqxhr ) {// Execute here});}
// script2function script2() {$.getScript($.url2, function( data, textStatus, jqxhr ) {// Execute here});}

是的,有…

继续阅读。在ES6中,我们可以将exportimport部分或整个JavaScript文件转换为另一个…

但是等等,并非所有浏览器都支持ES6,因此您需要使用babel.js对其进行转译。

所以你创建一个如下所示的类:

class Person {constructor(name) {this.name = name;}
build() {return new Person(this);}}
module.exports = Person;

另一个 JavaScript文件中,导入如下:

import { Person } from 'Person';

您还可以要求文件,如:

const Person = require('./Person');

如果您使用的是较旧的JavaScript版本,您可以使用必填项

requirejs(["helper/util"], function(util) {// This function is called when scripts/helper/util.js is loaded.// If util.js calls define(), then this function is not fired until// util's dependencies have loaded, and the util argument will hold// the module value for "helper/util".});

如果你想坚持使用旧版本的东西,比如jQuery,你也可以使用getScript

jQuery.getScript('./another-script.js', function() {// Call back after another-script loaded});

最后但并非最不重要的是,不要忘记您可以使用<script>标记执行传统的将脚本放在一起的方式…

<script src="./first-script.js"></script><script src="./second-script.js"></script><script src="./third-script.js"></script>

还有async推迟属性,我应该在这里提到…

备注:有几种方法可以执行外部脚本:

  • 如果存在async:脚本异步执行与页面的其余部分(脚本将在页面执行时执行继续解析)
  • 如果不存在async并且延迟是现在:当页面完成时执行脚本解析
  • 如果不存在异步或延迟:脚本是在浏览器继续之前立即获取并执行解析页面

Node.js,这对我来说是最好的!

我在这里尝试了大多数解决方案,但没有一个能帮助我在不改变作用域的情况下加载另一个文件。最后我使用了这个。它保留了作用域和所有内容。它在这一点上和你的代码一样好。

const fs = require('fs');eval(fs.readFileSync('file.js') + '');

使用ES6导入和导出与Node.js

.mjs扩展名而不是.js命名文件

创建文件

touch main.mjs lib.mjs

main.js

import { add } from './lib.mjs';console.log(add(40, 2));

lib.mjs

export let add = (x,y) => {return x + y}

运行

node --experimental-modules main.js

在JavaScript中实现模块有几种方法。以下是最流行的两种:

ES6模块

浏览器还不支持这种调制系统,所以为了让你使用这种语法,你必须使用像webpack这样的捆绑器。无论如何,使用捆绑器更好,因为这可以将你所有不同的文件组合成一个(或几个相关的)文件。这将更快地将文件从服务器提供给客户端,因为每个HTTP请求都有一些相关的开销。因此,通过减少整体HTTP请求,我们提高了性能。这是ES6模块的一个例子:

// main.js file
export function add (a, b) {return a + b;}
export default function multiply (a, b) {return a * b;}

// test.js file
import {add}, multiply from './main';   // For named exports between curly braces {export1, export2}// For default exports without {}
console.log(multiply(2, 2));  // logs 4
console.log(add(1, 2));  // logs 3

通用文档(用于Node.js)

此调制系统用于Node.js.您基本上将导出添加到名为module.exports的对象。然后您可以通过require('modulePath')访问此对象。这里重要的是要意识到这些模块正在缓存,因此如果您require()某个模块两次,它将返回已创建的模块。

// main.js file
function add (a, b) {return a + b;}
module.exports = add;  // Here we add our 'add' function to the exports object

// test.js file
const add = require('./main');
console.log(add(1,2));  // logs 3

我用另一种方法尝试了这个问题,

脚本导入的顺序,在这里没有影响。

index.html

<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Trials</title><meta name="viewport" content="width=device-width, initial-scale=1"><script src="main.js"></script><script src="scriptA.js"></script></head>
<body><h3>testing js in js (check console logs)</h3><button onclick="fnClick()">TEST</button></body>
</html>

main.js

function fnClick() {console.log('From\tAAAAA');var pro = myExpo.hello();console.log(pro);}

scriptA.js

myExpo = {hello: function () {console.log('From\tBBBBB');return "Hello";}}

结果

From    AAAAAFrom    BBBBBHello

按顺序动态加载多个脚本

如果你只加载一个脚本或者你不关心多个脚本的加载顺序,上述函数可以正常工作。如果你有一些脚本依赖于其他脚本,你需要使用Promise来指定加载顺序。这背后的原因是Javascript异步加载脚本和图像等资源。加载顺序不依赖于异步调用的顺序,这意味着即使你在调用dynamicallyLoadScript("scrip2")之前调用dynamicallyLoadScript("scrip1"),也不能保证script1在script2之前加载

所以这是另一个保证加载顺序的动态LoadScript版本:

// Based on: https://javascript.info/promise-basics#example-loadscriptfunction dynamicallyLoadScript(url) {return new Promise(function(resolve, reject) {var script = document.createElement("script");script.src = url;script.onload = resolve;script.onerror = () => reject(new Error(`Error when loading ${url}!`));document.body.appendChild(script);});}

有关Promises的更多信息,请参阅这个优秀的页面

这个新的动态LoadScript的用法非常简单:

dynamicallyLoadScript("script1.js").then(() => dynamicallyLoadScript("script2.js")).then(() => dynamicallyLoadScript("script3.js")).then(() => dynamicallyLoadScript("script4.js")).then(() => dynamicallyLoadScript("script5.js"))//...

现在脚本按script1.js、script2.js、script3.js等顺序加载。

脚本加载后运行依赖代码

此外,您可以在加载脚本后立即运行使用脚本的代码。只需在加载脚本后添加另一个.then

dynamicallyLoadScript("script1.js").then(() => dynamicallyLoadScript("script2.js")).then(() => foo()) // foo can be a function defined in either script1, script2.then(() => dynamicallyLoadScript("script3.js")).then(() => {if (var1){ // var1 can be a global variable defined in either script1, script2, or script3bar(var1); // bar can be a function defined in either script1, script2, or script3} else {foo(var1);}})//more .then chains...

处理加载错误

要显示未处理的Promise拒绝(错误加载脚本等),请将此unhandledrejection事件侦听器放在代码顶部:

// Based on: https://javascript.info/promise-error-handling#unhandled-rejectionswindow.addEventListener('unhandledrejection', function(event) {// the event object has two special properties:console.error(event.promise);// the promise that generated the errorconsole.error(event.reason); // the unhandled error object});

现在,您将收到任何脚本加载错误的通知。


快捷功能

如果您在加载后不立即执行代码而加载大量脚本,则此速记函数可能会派上用场:

function dynamicallyLoadScripts(urls) {if (urls.length === 0)return;
let promise = dynamicallyLoadScript(urls[0]);urls.slice(1).forEach(url => {promise = promise.then(() => dynamicallyLoadScript(url));});}

要使用它,只需传入一个脚本URL数组,如下所示:

const scriptURLs = ["dist/script1.js", "dist/script2.js", "dist/script3.js"];dynamicallyLoadScripts(scriptURLs);

脚本将按照它们在数组中出现的顺序加载。

您可以使用我的loadScript ES模块来加载JavaScript文件。

用法:

在你的head标签中,包含以下代码:

<script src="https://raw.githack.com/anhr/loadScriptNodeJS/master/build/loadScript.js"></script>

<script src="https://raw.githack.com/anhr/loadScriptNodeJS/master/build/loadScript.min.js"></script>

现在您可以使用window.load脚本来加载JavaScript文件。

loadScript.async(src,[选项])

异步加载JavaScript文件。

src:外部脚本文件的URL或脚本文件名数组。

options:以下选项可用

onload: function () The onload event occurs when a script has been loaded. Default is undefined.
onerror: function ( str, e ) The onerror event occurs when an error has been occurred. The default is undefined.
str: error details
e: event
appendTo: The node to which the new script will be append. The default is the head node.

例如

loadScript.async( "JavaScript.js",{onload: function () {
var str = 'file has been loaded successfully';console.log( str );},onerror: function ( str, e ) {
console.error( str );},} );

用法示例

Dan Dascalescu的回答 到图书馆的一个小扩展,取自Facebook的想法。

(function() {var __ = {};this._ = function(name, callback) {if(__[name]==undefined) {__[name] = true;var firstScript = document.getElementsByTagName('script')[0],js = document.createElement('script');js.src =  name;js.onload = callback;firstScript.parentNode.insertBefore(js, firstScript);}}})();
(new _('https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js', function() {snowStorm.snowColor = '#99ccff';}));

ES6模块

,在脚本标签(支持)中使用type=“模块”:

<script type="module" src="script.js"></script>

script.js文件中包含另一个像这样的文件:

import { hello } from './module.js';...// alert(hello());

在'module.js'中,您必须导入导出函数/类

export function hello() {return "Hello World";}

工作例子在这里

所以这是一个边缘情况。但是如果您需要从远程源加载JavaScript,大多数现代浏览器可能会由于CORS或类似的原因阻止您的跨站点请求。所以正常

<script src="https://another-domain.com/example.js"></script>

不会工作。做document.createElement('script').src = '...'也不会削减它。相反,你可以做的是通过标准GET请求将JavaScript代码作为资源加载,并执行以下操作:

<script type="text/javascript">var script = document.createElement('script');script.type = 'text/javascript';
let xhr = new XMLHttpRequest();xhr.open("GET", 'https://raw.githubusercontent.com/Torxed/slimWebSocket/master/slimWebSocket.js', true);xhr.onreadystatechange = function() {if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {script.innerHTML = this.responseText; // <-- This onedocument.head.appendChild(script);}}xhr.send();</script>

通过自己抓取内容,浏览器不会注意到恶意意图并允许您执行请求。然后您将其添加到<script>innerHTML中。这仍然会导致浏览器(至少Chrome)解析/执行脚本。

同样,这是一个边缘用例。你可能没有向后兼容性或浏览器合规性。但有趣/有用的事情要知道。

我没有看到一个答案,即您在文件中创建一个包含所有函数和变量的对象,然后使该对象成为在另一个文件中引用它的参数。

例如,您有名为“jsMod.js”、“jsView”和“jsContr.js”的文件:

文件jsMod.js

JSMODOBJ = {};JSMODOBJ.valueAddition = function(/* element value 1 */ val1, /* element value 2 */ val2) {return val1 + val2;}

文件jsView.js

JSVIEWOBJ = {};JSVIEWOBJ.elementColour = function(/* element id to change colour */ id, /* css colour classname */ col) {document.getElementById(id).className = col;}

文件jsContr.js

JSCONTROBJ = {};var jsMod = JSMODOBJ;var jsView = JSVIEWOBJ;
JSCONTROBJ.changeColourByValue = function (val1, val2, id, clss) {if (jsMod.valueAddition(val1,val2) !== 0) {jsView.elementColour(id, clss);}}

然后,您可以通过将scripts回显到您的. html或. php文件中来动态设置. js文件:

<?phpecho "<script src = './js/dleafView.js'></script><script src = './js/dleafModule.js'></script><script src = './js/dleafContr.js'></script>";?>

然后只需调用<script type="text/javascript"></script>标签中的控制函数。当然,这在开始时需要花费大量时间来设置,但从长远来看可以节省您的时间。

我用的方式略有不同,但这种方式也有效。

您还可以将gulpgulp-concatgulp-typescript/// <reference path=一起使用,包括:

文件packages.json

{"scripts": {"gulp": "gulp main"},"dependencies": {"@types/gulp": "^4.0.6","@types/gulp-concat","@types/gulp-typescript","gulp": "^4.0.2","gulp-concat": "^2.6.1","gulp-resolve-dependencies": "^3.0.1","gulp-typescript": "^6.0.0-alpha.1","typescript": "^3.7.3"}}

文件src/someimport.ts

class SomeClass {delay: number;}

文件src/main.ts

/// <reference path="./someimport.ts" />
someclass = new SomeClass();someclass.delay = 1;

这个mainGulp.js任务(在gulpfile.js上)仅针对src/main.js文件,解析其所有/// <reference path=...包含引用。这些包含被称为Triple-Slash Directives,它们仅用于组合文件的转译器工具。在我们的例子中,它们被.pipe(resolveDependencies({和TypeScript本身在检查文件是否缺少类型、变量等时显式使用。

  1. 三斜杠指令
  2. 什么时候需要三斜杠引用?

如果您想自定义var tsProject = ts.createProject调用而不使用tsconfig.json文件或覆盖其参数,请参阅

文件gulpfile.js

var gulp = require("gulp");var concat = require('gulp-concat');var resolveDependencies = require('gulp-resolve-dependencies');
var ts = require("gulp-typescript");var tsProject = ts.createProject("tsconfig.json");
gulp.task("main", function() {return gulp.src(["src/main.ts"]).pipe(resolveDependencies({pattern: /^\s*\/\/\/\s*<\s*reference\s*path\s*=\s*(?:"|')([^'"\n]+)/gm})).on('error', function(err) {console.log(err.message);}).pipe(tsProject()).pipe(concat('main.js')).pipe(gulp.dest("build/"));});

纯javascript版本

如果您想定位所有TypeScript项目文件而不是仅src/main.ts,您可以替换以下内容:

  return gulp.src(["src/main.ts"]).pipe(resolveDependencies({...// -->return tsProject.src().pipe(resolveDependencies({...

如果您不想使用TypeScript,您可以使用这个简化的gulpfile.js并从package.json中删除所有TypeScript包含:

文件gulpfile.js

var gulp = require("gulp");var concat = require('gulp-concat');var resolveDependencies = require('gulp-resolve-dependencies');
gulp.task("main", function() {return gulp.src(["src/main.js"]).pipe(resolveDependencies({pattern: /^\s*\/\/\/\s*<\s*reference\s*path\s*=\s*(?:"|')([^'"\n]+)/gm})).on('error', function(err) {console.log(err.message);}).pipe(concat('main.js')).pipe(gulp.dest("build/"));});

文件packages.json

{"scripts": {"gulp": "gulp main"},"dependencies": {"gulp": "^4.0.2","gulp-concat": "^2.6.1","gulp-resolve-dependencies": "^3.0.1"}}

然后,在运行命令npm run gulp之后,将创建文件build/main.js,其内容如下:

文件构建/main.js

class SomeClass {}/// <reference path="./someimport.ts" />someclass = new SomeClass();someclass.delay = 1;

这允许我在提供build目录文件后,将其包含在带有script标签的浏览器中:

<html><head><script src="main.js"></script></head><body><script type="text/javascript">console.log(someclass.delay);</script></body></html>

相关问题:

  1. TypeScript: Gulp
  2. 我可以使用TypeScript而不必使用需要的JS吗?
  3. 需要另一个JavaScript文件的主文件的简单连接,使用Gulp.js
  4. Node.js客户端:未捕获的引用错误:未定义
  5. TypeScript浏览器Node.js模块如何编译Gulp.js?
  6. 使用Babel连接文件
  7. 如何在浏览器中“要求”Common JS模块?
  8. 是否有其他方法可以替代Browserfy?

你应该使用这个:

<script src="your_file.js"></script>

放松!

fetch请求,eval结果。

我的一般解决方案取自EdgeS(我写的)efekt.js.st库。

无耻的插头警报-我在其他stackExchange网络站点上。这是#0的重新链接。

您将使用什么代码或设计来支持cssscripts的动态加载?

职位要求:

  • 支持Promise-wait-async异步包括错误处理
  • 支持一次性加载缓存,包括重新加载
  • 支持加载headbody或当前script-element
  • 支持加载cssjsmjs模块或其他脚本类型
  • 支持其他标签attrs,如noncecrossorigin
static loadScriptOrStyle(url, options) {// provenance :<# **Smallscript EdgeS efekt** `efekt.js.st` github libraries #>// returns    :<Promise#onload;onerror>// options    :<# `fIgnoreCache`, `fAppendToHead`, `fUrlIsStyle`, `attrs:{}` #>const head = document.head; let node = options?.fAppendToBody ? document.body : head;const url_loader_cache = document.head.url_loader_cache? head.url_loader_cache: (head.url_loader_cache = {script:{},link:{}})const kind = (options?.fUrlIsStyle || /\.css(?:(?:\?|#).*)?$/i.test(url))? 'link' : 'script';// check already-loaded cacheif(url_loader_cache[kind][url]) {const el = url_loader_cache[kind][url];// support `fIgnoreCache` reload-option; should not use on `head`if(options?.fIgnoreCache)el.remove();elsereturn(new CustomEvent('cache',{detail:el}));}// (re)create and record itconst self = document.currentScript;const el = url_loader_cache[kind][url] = document.createElement(kind);const append = (!self || options?.fAppendToHead || options?.fAppendToBody)? el => node.appendChild(el): el => self.parentNode.insertBefore(el, self);const load = new Promise((resolve, reject) => {el.onload  = e => {e.detail = el;resolve(e)};el.onerror = e => {e.detail = el;reject(e)};// `onload` or `onerror` possibly alter `cache` value// throw(new URIError(`The ${url} didn't load correctly.`))});// configure `module` attr, as appropriateif(/\.mjs(?:(?:\?|#).*)?$/i.test(url))el.type = 'module'// configure other attrs as appropriate (referrer, nonce, etc)for(const key in options?.attrs) {el[key] = attrs[key]}// trigger itif(kind === 'link') el.rel = 'stylesheet', el.href = url; else el.src = url;append(el);return(load);}

在后端,您可以使用通用文档模块。例如:

//a.jsfunction func () {var result = "OK Bro";return result;}
module.exports = { func };
//b.jsvar a = require('./a.js');console.log(a.func);

所以如果你想快速,简单…试试这个:

function include(filename){var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');script.src = filename;script.type = 'text/javascript';
head.appendChild(script)}

就这么简单:

var js = document.createElement("script");
js.type = "text/javascript";js.src = jsFilePath;
document.body.appendChild(js);

您可以只使用需要();标签。

例如,如果我有一个addition.js模块,我想添加到math.js,我会这样做:

//this is math.js
//varslet a = 1;let b = 3;
//start of codeconst additionfile = require('addition.js');window.alert("You added " + a + " and " + b + " together, to get " + additionfile.add(a,b) + "!");

如果你想要addition.js文件应该是这样的

function add(a,b) {const sum = a + b;return sum;}

这是最简单的解决方案。使用像Vite.js这样的捆绑器,然后简单地执行:

import "./path/to/js/file";

就是它了! OP要求类似于“@import in CSS”的东西,这正是如此。它也是没有火箭科学综合体作为一些旧方法。它至少无疑是对初学者最友好的方法,但我相信非初学者也喜欢它。

要开始使用Vite进行vanilla JavaScript项目,只需安装Node.js和[NPM3,然后执行以下操作:

npm create vite@latest <your-vanilla-js-app-name> --template vanilla

例如:

npm create vite@latest my-js-app --template vanilla

现在添加输入,就像这个答案开头提到的那样,今天就到此为止。

作为旁注:还有一件事可能会突然出现在你的脑海中是名称空间问题,例如,如果你在包含的文件中使用的名称与你当前文件中已经使用的名称相似怎么办?但这是JavaScript的本质,对吧?这不是这个方法特有的问题。

所以你需要制定单独处理的策略。如果你想了解更多,Addy Osmani的博客上有一篇综合文章:在JavaScript中处理全局命名空间的设计模式

要在JavaScript中导入另一个脚本,请使用import关键字:

import '/src/js/example.js';
// both types of quotes workimport "/src/js/example2.js";