首页 > 其他分享 >前端发展演变

前端发展演变

时间:2023-01-11 10:12:37浏览次数:57  
标签:发展 演变 前端 导出 module 导入 export 模块 import

前端演变

html、css、javascript

最早,我们可以通过html、css、js就可以完成一个静态页面的渲染,js负责页面的交互,随着交互的逻辑与操作越来越多,以下缺点逐渐暴露出来。

  • 变量名冲突:越来越多的js文件内容导致变量名冲突
  • 加载缓慢:加载的时候浏览器会停止网页渲染,加载的文件越多,网页失去相应的时间就越长
  • 依赖顺序:js文件内容直接存在依赖关系,必须保证正确的加载顺序,否则无法加载,依赖关系复杂时,维护困难
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <script type="text/javascript" src="main.js"></script>
    <link rel="stylesheet" href="main.css">

    <h1 class="myH" onclick="myFun()">hello</h1>
</body>
</html>
function myFun(){
    console.log('hello')
}
.myH {
    color: red;
}

模块化出现

为了解决上一章中说的缺点,可以将变量及方法写到一个对象中。然后通过对象的形式调用属性及方法。

var module = new Object({
    m1: function () {
    },
    m2: function () {
    }
});
module.m1()
module.m2()

主流模板规范

在es6出现之前,主流的模板规范有两种:CommonJSAMD

CommonJS规范

CommonJS中,暴露模块使用module.exports[1]exports[2]

全局方法require(),用于加载模块,比如在同级路径下有一个main.js文件

var math = require('math');
math.add(2,3);

浏览器不兼容CommonJS,因为NodeJS自己定义了四个变量module,exports,require,global,由于浏览器中没有这四个变量所以没法解析(实际上这四个变量的作用是全局变量,module.exports存储我们的JS导出的变量,然后通过require来加载存储再里面的变量)从而达到文件分发的目的。

AMD规范

有了服务器端模块以后,很自然地,大家就想要客户端模块。而且最好两者能够兼容,一个模块不用修改,在服务器和浏览器都可以运行。

但是,由于一个重大的局限,使得CommonJS规范不适用于浏览器环境。还是上一节的代码,如果在浏览器中运行,会有一个很大的问题

var math = require('math');
math.add(2, 3);

第二行math.add(2, 3),在第一行require(‘math6’)之后运行,因此必须等math.js加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等。

这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。
因此,浏览器端的模块,不能采用”同步加载”(synchronous),只能采用”异步加载”(asynchronous)。这就是AMD规范诞生的背景。

AMD是”Asynchronous Module Definition”的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

模块必须采用特定的define()函数来定义。

define(id?, dependencies?, factory)

如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。

define(function (){
    var add = function (x,y){
      return x+y;
    };
    return {
      add: add
    };
  });

如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。

define(['Lib'], function(Lib){
    function foo(){
      Lib.doSomething();
    }
    return {
      foo : foo
    };
  });

当require()函数加载上面这个模块的时候,就会先加载Lib.js文件。

AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:

require([module], callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:

require(['math'], function (math) {
 math.add(2, 3);
});

math.add()与math模块加载不是同步的,浏览器不会发生假死。所以很显然,AMD比较适合浏览器环境

目前,主要有两个Javascript库实现了AMD规范:require.jscurl.js

CMD规范

CMD (Common Module Definition), 是seajs推崇的规范,CMD则是依赖就近,用的时候再require。它写起来是这样的:

define(function(require, exports, module) {
     var clock = require('clock');
         clock.start();
});

CMD与AMD一样,也是采用特定的define()函数来定义,用require方式来引用模块

define(id?, dependencies?, factory)

CMD和AMD的区别

  • 对依赖模块的执行时机处理不同
  • AMD依赖前置,js可以方便知道依赖模块是谁,立即加载
  • CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。

ES6时代的到来

ES6标准发布后,module成为标准,标准使用是以export指令导出接口,以import引入模块,但是在我们一贯的node模块中,我们依然采用的是CommonJS规范,使用require引入模块,使用module.exports导出接口。

export导出模块

export语法声明用于导出函数、对象、指定文件(或模块)的原始值。

注意:在node中使用的是exports,不要混淆了

export有两种模块导出方式:命名式导出(名称导出)默认导出(定义式导出),命名式导出每个模块可以多个,而默认导出每个模块仅一个。

export { name1, name2, …, nameN };
export { variable1 as name1, variable2 as name2, …, nameN };
export let name1, name2, …, nameN; // also var
export let name1 = …, name2 = …, …, nameN; // also var, const
 
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
 
export * from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
  • name1… nameN-导出的“标识符”。导出后,可以通过这个“标识符”在另一个模块中使用import引用
  • default-设置模块的默认导出。设置后import不通过“标识符”而直接引用默认导入
  • -继承模块并导出继承模块所有的方法和属性
  • as-重命名导出“标识符”
  • from-从已经存在的模块、脚本文件…导出

命名式导出

模块可以通过export前缀关键词声明导出对象,导出对象可以是多个。这些导出对象用名称进行区分,称之为命名式导出。


export { myFunction }; // 导出一个已定义的函数
export const foo = Math.sqrt(2); // 导出一个常量

我们可以使用*和from关键字来实现的模块的继承:

export * from 'article';

模块导出时,可以指定模块的导出成员。导出成员可以认为是类中的公有对象,而非导出成员可以认为是类中的私有对象:


var name = 'IT笔录';
var domain = 'http://itbilu.com';
 
export {name, domain}; // 相当于导出
{name:name,domain:domain}

模块导出时,我们可以使用as关键字对导出成员进行重命名


var name = 'IT笔录';
var domain = 'http://itbilu.com';
 
export {name as siteName, domain};

默认导出

默认导出也被称做定义式导出。命名式导出可以导出多个值,但在在import引用时,也要使用相同的名称来引用相应的值。而默认导出每个导出只有一个单一值,这个输出可以是一个函数、类或其它类型的值,这样在模块import导入时也会很容易引用。


export default function() {}; // 可以导出一个函数
export default class(){}; // 也可以出一个类

命名式导出与默认导出

默认导出可以理解为另一种形式的命名导出,默认导出可以认为是使用了default名称的命名导出。

下面两种导出方式是等价的:

const D = 123;
 
export default D;
export { D as default };

export使用示例

命名导出

// "my-module.js" 模块
export function cube(x) {
     return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { foo };
import { cube, foo } from 'my-module';
  console.log(cube(3)); // 27
  console.log(foo); // 4.555806215962888

默认导出

// "my-module.js"模块
export default function (x) {
    return x * x * x;
}
// 引用 "my-module.js"模块
import cube from 'my-module';
console.log(cube(3)); // 27

import引入模块

import语法声明用于从已导出的模块、脚本中导入函数、对象、指定文件(或模块)的原始值。

import模块导入与export模块导出功能相对应,也存在两种模块导入方式:命名式导入(名称导入)和默认导入(定义式导入)。

import的语法跟require不同,而且import必须放在文件的最开始,且前面不允许有其他逻辑代码,这和其他所有编程语言风格一致。

import defaultMember from "module-name";
import * as 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 defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name";
  • name-从将要导入模块中收到的导出值的名称
  • member, memberN-从导出模块,导入指定名称的多个成员
  • defaultMember-从导出模块,导入默认导出成员
  • alias, aliasN-别名,对指定导入成员进行的重命名
  • module-name-要导入的模块。是一个文件名
  • as-重命名导入成员名称(“标识符”)
  • from-从已经存在的模块、脚本文件等导入

命名式导入

我们可以通过指定名称,就是将这些成员插入到当作用域中。导入时,可以导入单个成员或多个成员:

注意,花括号里面的变量与export后面的变量一一对应

import {myMember} from "my-module";
import {foo, bar} from "my-module";

通过*符号,我们可以导入模块中的全部属性和方法。当导入模块全部导出内容时,就是将导出模块(’my-module.js’)所有的导出绑定内容,插入到当前模块(’myModule’)的作用域中:

import * as myModule from "my-module";

导入模块对象时,也可以使用as对导入成员重命名,以方便在当前模块内使用:

import {reallyReallyLongModuleMemberName as shortName} from "my-module";

导入多个成员时,同样可以使用别名:

import {reallyReallyLongModuleMemberName as shortName, anotherLongModuleName as short} from "my-module";

导入一个模块,但不进行任何绑定

import "my-module";

默认导入

在模块导出时,可能会存在默认导出。同样的,在导入时可以使用import指令导出这些默认值。

直接导入默认值:

import myDefault from "my-module";

也可以在命名空间导入和名称导入中,同时使用默认导入:

import myDefault, * as myModule from "my-module"; // myModule 做为命名空间使用
或
 
import myDefault, {foo, bar} from "my-module"; // 指定成员导入

import使用示例

// --file.js--
function getJSON(url, callback) {
    let xhr = new XMLHttpRequest();
        xhr.onload = function () {
        callback(this.responseText)
           };
        xhr.open("GET", url, true);
        xhr.send();
}
export function getUsefulContents(url, callback) {
        getJSON(url, data => callback(JSON.parse(data)));
}

// --main.js--
import { getUsefulContents } from "file";
        getUsefulContents("http://itbilu.com", data => {
        doSomethingUseful(data);
});

default关键字

// d.js
export default function() {}
 
// 等效于:
function a() {};
export {a as default};

在import的时候,可以这样用

import a from './d';
 
// 等效于,或者说就是下面这种写法的简写,是同一个意思
import {default as a} from './d';

这个语法糖的好处就是import的时候,可以省去花括号{}。

简单的说,如果import的时候,你发现某个变量没有花括号括起来(没有*号),那么你在脑海中应该把它还原成有花括号的as语法。

所以,下面这种写法你也应该理解了吧:

import $,{each,map} from 'jquery';

import后面第一个$是{defalut as $}的替代写法

as关键字

as简单的说就是取一个别名,export中可以用,import中也可以用:


  1. module.exports对象是由模块系统创建的。 有时这是难以接受的;许多人希望他们的模块成为某个类的实例。 为了实现这个,需要将期望导出的对象赋值给module.exports。 注意,将期望的对象赋值给exports会简单地重新绑定到本地exports变量上,这可能不是你想要的。 ↩︎

  2. exports变量是在模块的文件级别作用域内有效的,它在模块被执行前被赋于 module.exports 的值。它有一个快捷方式,以便 module.exports.f = … 可以被更简洁地写成exports.f = …。 注意,就像任何变量,如果一个新的值被赋值给exports,它就不再绑定到module.exports(其实是exports.属性会自动挂载到没有命名冲突的module.exports.属性) ↩︎

标签:发展,演变,前端,导出,module,导入,export,模块,import
From: https://www.cnblogs.com/lensener/p/17042946.html

相关文章

  • 前端如何实现网页变灰功能?
    今天来从前端的角度看看网页置灰是如何实现的,以及相关使用技巧!实现思路先来看看一些主流网站是如何实现置灰的:BiliBili:image.png淘宝:image.png京东:i......
  • Java课程设计之——Web前端设计
    0、团队课程设计1、主要使用的技术HTML/CSSBootstrap5javascript/jQuery/jQuery-UIJSP2、前期调查与设计搜索引擎主要分为两个界面,主界面和搜索结果界面主界面......
  • 大前端html学习06-宽高自适应
    一、自适应网页布局中经常要定义元素的宽和高。但很多时候我们希望元素的大小能够根据窗口或子元素自动调整,这就是自适二、宽度自适应高度自适应(1)宽度自适应元素宽度的默......
  • Web前端高频面试题全解析记录
    ##var变量提升var申明的变量会被提升到当前作用域的最顶端所谓作用域是`function`这样的函数才算是,`if``else``for`等带`{}`的是没有作用域的无论嵌套多少......
  • 前端开源项目 CDN | 网站整理
    官网描述BootCDN附带搜索,编辑好格式可以直接复制百度静态资源公共库百度的,支持搜索,不支持直接复制新浪js库不算很方便七牛云存储开放静态文件国内知......
  • 38、商品服务--属性分组---前端组件抽取&VUE中父子组件的交互
    一、父子组件传递数据:1、子组件给父组件传递数据:事件机制即子组件给父组件发送一个事件,携带上数据this.$emit("事件名",携带的数据...)1.1)使用elementui的树形控件的n......
  • 提高适应性,企业未来发展的引导力量
    在近几年充满着众多不确定性因素的市场环境中,企业竞争日趋激烈,迅速做出重要调整、提高适应性成为了企业未来发展的关键要素。企业不得不对收入、需求、支出和预测进行反复的......
  • 2023 年汽车行业向好发展,火山引擎 VeDI 助力车企数智转型
    更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,并进入官方交流群2023年的汽车市场,预计能有一个向好的转型。据中汽协公布的2022年1-11月累计汽车销量......
  • 2023年汽车行业向好发展,火山引擎VeDI助力车企数智转型
    更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,并进入官方交流群2023年的汽车市场,预计能有一个向好的转型。据中汽协公布的2022年1-11月累计汽车销量数据,达到24......
  • 聚焦操作系统迁移实践与生态发展 | openEuler Meetup 长沙站圆满结束
    活动回顾12月23日,由openEuler社区和湖南欧拉生态创新中心主办,麒麟信安和湖南省鲲鹏生态创新中心协办的openEuler Meetup 长沙站举办。本次活动集聚社区开发者、用户、企业......