关于阅读 ES6- Module整理的问题

1、ES5的模块加载方案有哪些

答:① 主要有CommonJS和AMD两种,CommonJS用于服务器,AMD用于浏览器。
② CommonJS和AMD都是运行时加载(即先加载整个模块,生成一个对象,然后从对象中取出想要的方法),因为CommonJS只有运行时才能得到这个对象,所以没办法在编译时做‘静态化’
③ CommonJS模块树池的是值得缓存,不存在动态更新
// CommonJS模块
let {stat, exists, readfile} = require(‘fs’)

2、ES6的编译时加载(也叫静态加载)

答:① 直接从模块中加载需要的方法,其他方法不进行加载,这种加载叫做‘编译时加载’或者静态加载。
② 编译时加载比CommonJS模块的效率要高
import {run , dance} from ‘index.js’

3、ES6模块是什么方式加载

答:静态加载(编译时加载)。

4、ES6模块有哪些好处

答:① ES6模块是以静态加载的,这样拓展JS的语法就更方便了,且有利于静态分析的进行
② 不需要UMD模块格式了,以后服务器和浏览器都会支持ES6模块格式了
③ 以后浏览器的新的API就能用模块格式提供,不用做成全局变量或者navigator对象的属性
④ 不再需要对象作为命名空间,以后的广告狗男女都可以通过模块提供

5、ES6自动采用严格模式,严格模式的限制有哪些呢

答:① 变量必须声明后再使用
② 函数的参数不能有同名属性,否则报错
③ 不能使用with语句
④ 不能对只读属性进行复制,否则报错
⑤ 不能使用前缀0表示八进制数
⑥ 不能删除不可删除的属性,否则报错
⑦ 不能删除变量,会报错,只能删除对象的属性
⑧ eval不会再它的外层作用域引入变量
⑨ eval和arguments不能被重新赋值
⑩ arguments不会自动反映函数参数的变化
① 不能使用arguments.callee
② 不能使用arguments.caller
③ 禁止this指向全局对象,ES6中顶层的this指向undefined,所以不应该在顶层代码中使用this
④ 不能使用fn.caller和fn.arguments获取函数调用的堆栈
⑤ 增加了保留字如protected、static和interface

6、ES6模块的export命令和import命令

答:① export命令用于规定模块的对外接口
② import命令用于输入其他模块提供的功能

7、export命令

答:① export命令有两种写法来对外输出接口。
② 可以逐一进行输出,也可以使用大括号输出一组变量
③ export输出的变量是本来的名字,可以使用as关键字重命名进行输出多次
④ export命令必须输出对外的接口,必须和模块内部的变量建议意义对应的关系
⑤ export输出的接口中的值是实时的,与CommonJS输出的值的缓存不同

// ① 方式一
export var num = 1
export const a = 22
export function fun(){}
// ② 方式二,优先考虑下面这样的写法,更加清晰明了
var num = 1
const a = 22
function fun(){}
export {
  num as n1, 
  num as n2, 
  a, 
  fun
}
// 报错的写法
export 1 // 报错
var m = 1
export m //报错,需要写成 export {m}
function f(){}
export f // 报错
// export输出的接口中的值是实时的
export var foo = 111
setTimeout(() =>foo = 2, 3000) // foo先输出111,3秒后变量foo值变成 2

8、import命令

答:① import命令可以将文件中export出来的接口进行引入
② 如果想要为输入的名字重新取名,可以使用as关键字
③ import命令输入的变量是只读的,不能进行接口的改写
④ 如果import进来的变量是一个对象,可以改写对象的属性,建议不要改
⑤ import后面路径可以是相对路径也可以是绝对路径。
⑥ import如果不带路径表示是一个模块名,需要配置文件,告诉JS引擎模块的位置
⑦ import有提升效果,会提升到整个模块的头部,先执行
⑧ import是静态执行,所以不能使用变量和表达式和if语句
⑨ import可以后面直接跟模块名,加载一整个模块 import ‘lodash’
⑩ 多次重复执行同一条import语句,只会执行一次,即import语句是Singleton模式。
① 可以使用 * 来加载一个模块的所有输出的接口
② import命令可以同时输入默认方法和其他接口,如 import _, {each, forEach} from ‘loadash’

fun() // 不会报错,因为import有提升的效果
import{num as n, a,  fun, obj} from './index.js'
import * as o from './index.js2'
n = {} // 报错
obj.name = 'name' // 报错
import {'n'+'um'} from './index.js' //报错
let url = 'index.js'
import {num} from url // 报错
// 报错
if(x === 1){
  import {num} from './index1.js'
}else{
  import {num} from './index2.js'
}

9、export default命令

答:① 当用户调用模块文件的时候,不需要知道模块文件中具体有哪些方法的时候,那么模块在输出接口时,可以用export default为模块指定默认输出。
② 用export default输出的模块文件,使用import时可以为匿名的模块指定任何名字。
③ import引入export default模块,不需要{}进行引入
④ export default除了用在匿名的函数,也可以用于非匿名函数
⑤ export default本质上是输出一个叫做default的变量或方法,然后系统循序你为它取任意名字
⑥ export default命令是输出一个叫default的变量,所以后面不能跟变量声明语句,会报错。如 export default let a = 111;
⑦ export default 本质上是将后面的值赋值给default变量,所以后面可以直接跟着一个值,如 export default 111
⑧ export default 可以用于输出类

// 直接输出匿名函数,import引入时可以取任意姓名且不用{}进行引入
export default function(){} // index.js 文件
import index from './index.js' // user.vue文件
// 用于非匿名函数,直接输出
export default function f1(){}
// 先声明非匿名函数,后进行输出
function f2(){}
export default f2
// export default本质上是输出default变量,引入时可以任意命名
function f3(){}
export default f3 // 相当于 export {f3 as default}
import ff3 from 'index2.js' // 相当于 import {default as ff3} from 'a.js'
//可以输出类
export default class{} // class.js文件
import MyClass from 'class'
var c = new MyClass()

10、export和export default有什么区别

答:① export default用于模块的默认输出,export用于输出多个接口
② export default 模块输出的时候需要{},export批量输出接口需要{},如果不适用{},则需要在每个接口定义前加上export关键字进行一个一个的输出
③ export输出的接口,import引入时要用{}进行引入
④ export default输出的接口,import引入时可以用任意名且不加{}引入
⑤ export default后面可以直接跟一个值,export后面需要跟一个接口名

export deafult 11
export{a}

11、模块之间可以进行继承

答:假如 child模块继承了father模块,那么child模块就有了father模块的所有属性和方法

// child.js
export * from 'father'//对外输出从father那继承的接口,*会忽略default方法
export var a = 1 // 对外输出自己的接口
export function fun(){}// 对外输出自己的接口

12、跨模块常量

答:当常量在很多个模块进行共享的时候,这个时候可以把常量提取到一个单独的模块文件。

// const.js
export const A = 1
export const B= 2
export const C = 3
// a.js
import * as consts from './const.js'
console.log(conts.A)
console.log(conts.B)

// b.js
import {A, C} consts from './const.js'
console.log(conts.A)
console.log(conts.C)

13、简述import()

答:① import命令会被JS进行静态解析(静态加载),先于模块内的其他语句执行。所以要放在文件顶部,放在if语句中会报错
② require是运行时进行加载
③ import(url)函数,支持动态加载,参数url是模块的位置
④ import()函数可以用于任何位置,不仅仅是模块,非模块的脚本也是可以使用 的。
⑤ 当JS运行到import()函数这句时,就会加载指定得到模块
⑥ import()函数类似于Node的require方法,import()函数是异步加载,require()是同步加载

14、import()函数的使用场合

答:① 按需加载某个模块

button.addEventListener('click', event => {
  import('./dialogBox.js').then(dialogBox => {
     dialogBox.open()
  }).catch(error => {})
});
② 条件加载。import()函数可以放在if代码块中,根据不同的条件加载不同的模块
if(a){
 import('moduleA').then()
}else{
 import('moduleA').then()
}
③ 动态的模块路径。允许模块路径动态生成
import(f()).then() // 根据函数f的返回结果,加载不同的模块

15、使用import()函数的注意事项

答:① import()加载模块成功后,这个模块会作为一个对象,当做then方法的参数,所以可以用解构的方法获取这个模块的接口
② 模块中如果有default输出接口,可以用参数拿到这个接口
③ import()可以同时加载多个模块
④ import()函数可以用在async函数中

// then方法入参就是加载的模块对象
// index.js文件中
export let a = 1
export let num = 2
export function run(){}
// user.vue文件
import('./index.js').then(({a, run, num}) => {})

// 模块中如果有default输出接口,可以用参数拿到这个接口
import('./a.js').then((aModule) => {
   console.log(aModule.default)
})
import('./b.js').then(({default: bDefault}) => {
   console.log(bDefault)
})

// import()可以同时加载多个模块
Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
]).then(([module1, module2, module3]) => {});

// import()函数可以用在async函数中
async function fun(){
  const a = await import('./a.js')
  const {num, n} = await import('/.index.js')
  const {module1, module2} = await Promise.all([
import('./module1.js'),
import('./module2.js')
   ])
}

16、简述浏览器加载JS脚本

答:① 浏览器通过script标签进行加载JS脚本文件或script标签内直接写JS脚本
② script标签的默认type是 application/javascript,可以进行省略
③ 浏览器默认是同步加载JS脚本的,也就是渲染引擎遇到script标签就停下来,等脚本执行完了就接着进行渲染,如果是外部脚本还要在脚本执行之前进行脚本的下载。

<script type="application/javascript">
  // 内部脚本
</script>
<script type="application/javascript" src="a.js"></script><!--内部脚本-->

17、浏览器怎么进行JS脚本的异步加载

答:① 当JS脚本体积过大,会造成浏览器阻塞
② script标签提供了 defer和async两种属性,会让脚本进行异步加载
③ 渲染引擎遇到defer和async属性,就会开始去下载外部脚本,不会等到甲苯下载和执行,继续执行脚本之后的命令
④ defer要等到DOM结构完全生成及其他脚本执行完了(整个页面在内存中正常渲染结束),才会去执行(即:渲染完再执行)
⑤ async是一旦脚本下载完了,渲染引擎就会中断,来执行这个脚本,等到这个脚本执行后再继续渲染(即:脚本下载完就执行)

<script type="application/javascript" src="a.js" async></script>
<script type="application/javascript" src="a.js" defer></script>

18、浏览器加载ES6模块的规则是什么

答:① 使用script标签,type为‘module’来异步加载模块,不会阻塞浏览器,等到整个页面渲染完,再执行模块脚本(有点等同于打开了script标签的defer属性)
② 当网页有多个模块文件,会按页面的顺序依次执行
③ 可以加上script标签的async属性,这样模块文件一加载完成,就会中断渲染引擎来执行这个脚本文件。这时如果有多个模块文件,就是按谁先加载完成就执行谁的规则来。
④ ES6模块可以内嵌在网页中,跟外部模块文件脚本的引入一样

<script type="module" src="./foo.js"></script>
<!-- 等同于 -->
<script type="module" src="./foo.js" defer></script>

// ES6模块可以内嵌在网页中,跟外部模块文件脚本的引入一样
<script type="module">
  import utils from "./utils.js";
  // other code
</script>

19、浏览器加载ES6模块需要注意哪些

答:① 代码是在模块作用域上运行,而不是在全局作用域运行,外部不可见
② 模块脚本自动采用严格模式
③ 模块之中可以import其他模块(.js后缀不可以省略,提供绝对URL或相对URL)
④ 模块之中,顶层this返回undefined,而不是window,所以不要在模块中使用this。这个特性可以用来检测当前代码是不是在ES6模块之中。
⑤ 同一个模块如果加载多次,只执行一次

20、ES6模块和CommonJS模块的差异

答:① CommonJS模块输出的是一个值得拷贝,ES6模块输出的是值的引用
② CommonJS模块是运行时加载,ES6模块是编译时输出接口
③ CommonJS模块的require()是同步加载,ES6模块的import命令是异步加载,有一个独立的模块依赖的解析阶段
④ CommonJS加载的是一个对象(即module.exports属性),该对象只在脚本运行完才会生成。ES6模块不是对象,他的对外接口只是一种静态定义,在代码静态解析阶段就会完成
⑤ CommonJS模块会缓存运行结果,ES6模块不会缓存运行结果
⑥ CommonJS模块是Node.js专用的,与ES6模块不兼容。Node.js的13.2版本开始,打开了对ES6的支持,要求ES6模块采用.mjs后缀文件名。
⑦ CommonJS模块使用 require()和module.exports,ES6模块使用的是import和export
⑧ ES6顶层this是undefined,CommonJS顶层this是当前模块

21、JavaScript的两种模式

答:一种是ES6模式,简称ESM
另一种是CommonJS模式,简称CJS

22、Node.js的模块加载方法

答:① Node.js从版本13.2后开始支持ES6模块,要求ES6模块的文件后缀名为.mjs。如果不希望用这个后缀名,可以在package.json指定type为module。
② 当Node遇到.mjs文件,会认为它是ES6的模块,默认启用严格模式
③ 如果Node遇到.cjs文件,会认为是CommonJS模块
④ Node中,如果package.json文件中的type为commonjs时,那么模块文件会被解释成CommonJS模块
⑤ Node中ES6模块和CommonJS模块尽量不要混用,因为require命令不能加载.mjs文件,.mjs文件中也不能使用require命令,都会报错。

23、模块的入口文件可以使用package.json文件中的哪些字段指定

答:① main和exports字段,
② exports字段优先级高于main字段
③ exports字段可以指定脚本或者子目录的别名
④ 当用exports字段指定了别名,就可以使用“模块名+别名”这种形式加载脚本
⑤ 如果exports的别名是. ,就代表是模块的主入口,优先级高于main字段,且可直接写成exports字段的值
⑥ exports字段只有新版本的Node支持,老版本不支持,所以老版本入口文件还是以main字段对应的值为主,新版本Node中exports对应值为入口文件,如果没有才以main字段对应的值为入口文件。
⑦ exports字段中可以指定在不同方式加载时的入口文件,例如CommonJS加载时入口文件为 index.js,ES6模块加载时入口文件为main.js

{ 
   "type": "module",
   "main": "./src/index.js"
}

// 先在 ./node_modules/es-module-package/package.json 中指定别名
{
  "exports": {
    "./submodule": "./src/submodule.js"
  }
}
// 后面就可以使用别名进行加载
import submodule from 'es-module-package/submodule'; // 相当于加载 ./node_modules/es-module-package/src/submodule.js

//main的别名
{
   "exports":{
      ".": "./main.js"
  }
}
// 等同于
{
  "exports": "./main.js"
}

//新版本Node入口文件为 main-modern.cjs,旧版本的入口文件为 main-legacy.cjs
{
  "main": "./main-legacy.cjs",
  "exports": {
    ".": "./main-modern.cjs"
  }
}

// 条件加载:CommonJS模块加载时入口为index.js文件,其他情况的入口文件为main.js文件;指定了./lib/other.js目录文件别名为other
{
  "type": "module",
  "exports": {
      "require": "./index.js",
      "default": "./main.js",
       "./other": "./lib/other.js"
   }
}

24、CommonJS模块加载ES6模块

答:① 不能加载会报错。
② ES6只能使用import()方法加载。
③ require()不支持ES6模块的一个原因是,他是同步加载,而ES6模块内部可以使用顶层的await命令,导致无法被同步加载。

25、ES6模块加载CommonJS模块

答:① ES6模块的import()命令可以加载CommonJS模块,但只能整体加载,不能只加载单一的输出项
② ES6模块需要静态代码分析,而CommonJS模块输出接口时module.exports,是一个对象,无法静态分析,只能整体加载
③ 可以使用Node.js内置的module.createRequire()方法进行加载CommonJS模块,不建议使用,会将ES6和CommonJS混在一起

26、什么是循环加载

答:指的是a脚本执行依赖b脚本,而b脚本的执行又依赖a脚本

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值