ES6语法(4)—— 模块化开发之import和export命令详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dkr380205984/article/details/81909312

  在了解import和export之前,不如先抛出一个问题,为什么要用模块化开发?

  来看一下传统的开发模式,一个简单的前后端分离的业务系统

  前端可能要在页面中引用一个common.js文件,该文件里面包含了一些常用的函数,如ajax的二次封装,常用数值处理器等

function myAjax(){
    //...
}
function myMath(){
    //...
}
//.......

  然后在使用的时候你可以用script标签把这些封装好的工具引入到项目中。

<script src='common.js'></script>

  在实际开发中,我们经常遇到这样的问题,我们常常需要因为要引入阿里图标库的某个小图标,就把整个阿里图标库下载到本地,当然这只是个夸张的举例说明,图标是支持单个引入的,那么js库呢?在多页面应用开发的过程中,我们常常会遇到这种情况,今天你要用到某个库的某个函数,你就把那个库整个引入了,隔天产品又觉得另一家插件不错,于是你就把另一个插件库也引入了,你肯定不会在引入代码的时候把你需要的部分理出来,这样就导致代码的冗余量越来越高,并且会随着时间的累积,你的代码变得越来越不可维护。因为你也不知道哪个库有用,哪个库没用,当你不需要某个函数时,你根本不知道这个函数出自哪个库,于是,管他呢,全留着好了,又不报错是吧

  早些年我还没学代码的时候,无意间打开了百度首页的控制台(一不小心按到了F12),控制台打印了了一段百度的招聘,and当时看不懂的english,红色的一大片报错,调包带来的代码冗余问题使得百度这样的产品都没法处理这些报错,当然现在你去打开百度的搜索控制台还是一大堆的报错,最终这些问题都可以归咎为历史遗留问题,问题的产生就是在开发的过程中调了一大堆不知道该不该用,有没有用,能不能用的冗余代码。

  为了解决上述问题,前端已经逐渐实现了模块化开发的编程方式。ES6中提供了export和import命令,来实现模块化开发,每个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。一般情况下,你可以放心的将当前模块的所有有用变量和函数都输出,因为在使用import命令导入你所需要的变量和函数的时候可以过滤掉不需要的部分,因此在进行模块化开发的时候不建议使用import * from ...,这有点像数据库查询语句select * from,尽管全部获取不会有什么问题,但这确实不是一个良好的编程习惯。

1.export 命令

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

  export命名式导出有三种方式

  第一种

// 注意我这里定义变量都用了let,建议用const定义,只要知道const的性能更优就可以了
export let json = {'name': 'dkr'}
export let str = '字符串'
export function multiply (x, y) {
  return x * y
}

  上面的写法等同于(第二种)

let json = {'name': 'dkr'}
let str = '字符串'
function multiply (x, y) {
  return x * y
}
export {json, str, multiply}

  这两种方法可以混合使用,当然个人不推荐混合使用。推荐使用第二种写法,便于管理,你可以在最后导出所有你想导出的公共模块,便于别人阅读你的模块,他只需要拉到最后,通过英文变量的输出名推测这个模块的功能即可。

 第三种

 你可以用as关键字重命名想要输出的变量,函数或者类名,当你这么做的时候,注意要用as重命名的值去接收

export {json as newJson, str as newStr, multiply as newMultiply}

通常情况下这个功能并没有什么软用,当然你可以拿他来输出同一个值的多种命名规则,如下

export {json as myJson, json as youJson, json as newJson}

这样你就可以用多种名字去接收json了,尽管他们是同一个值

2.import 命令

  使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。

  我们可以通过下面的方式,引入刚才模块中的一些函数和变量

import {json, str, multiply, number} from './export.js'

 当然你可以有选择性的加载模块中的部分函数或变量,如你只需要加载Math模块的add模块,无需其他的复杂运算就可以用import导入add from Math模块,尽量不要为了方便和偷懒,import * from Math。

 导入变量和函数后,就可以使用这些数据了,在使用的过程中要注意一个点,虽然import导入的东西并不是完全“只读”的,但请尽量不要去改变里面的值,就当作“只读”来用。

import {json, str, multiply, number} from './export.js'
json.name = 'hello' // 对象的值可改,但不推荐修改import导入的数据
console.log(json)
console.log(str)
// str = '改写字符串' //报错,非对象引入不能改写,属于只读
console.log(multiply(2, 3))

  上述代码说明了,对象内部的值可以修改,但对string类型的值修改会直接报错,总之,尽量不要去修改外部模块的值,“只读”即可。

  import也支持引入的时候对变量名进行修改和使用,注意是变量名,不是修改变量,如下所示

import {json as myJson} from './export.js'
console.log(myJson)

 关于import的使用,有个小tips,import模块导入拥有提升效果,这有点类似于var的变量提升效果,你可以先使用,后定义,当然不推荐这样使用。

console.log(myJson) //这样写并不会报错
import {json as myJson} from './export.js'

  关于import的其他特殊特性,可以去阮大神的ES6教程中学习,这里只说明一些常用配置。

3.模块的整体加载

  除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在自定义的对象上面。你需要通过自定义的对象去访问里面的变量或函数。

import * as Math from './export.js'
console.log(Math.json)

4.export defaul命令

  从前面的例子可以看出,使用import命令的时候,你需要知道所要加载的变量名或函数名,这对于传统的"上手就能用"的开发带来了很多困扰。为了给用户提供方便,让他们不用阅读文档就能加载模块,可以用export default命令,为模块指定默认输出。先来看一下demo

export default function (...msg) {
  msg.forEach((item) => {
    console.log(item)
  })
}

  上面的代码等同于

function hello (...msg) {
  msg.forEach((item) => {
    console.log(item)
  })
}
export default hello

  上面的模块输出一个函数,用于打印信息.你可以在import导入的时候为该函数指定任意名字,不管这个函数导出的时候是匿名函数还是非匿名函数,在模块外部是无效的。加载的时候,视同匿名函数加载。

import print from './exportDefault.js'
print('hello', 'world')

  上面代码的import命令,可以用任意名称指向exportDefault.js输出的方法,这时就不需要知道原模块输出的函数名。需要注意的是,这时import命令后面,不使用大括号。

  本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。

5.export中的异步操作

  讲完了一些模块操作基本用法(只是基本用法),来看一个比较有意思的东西,如果我在模块中,对一个要输出的内容做一个异步操作,会发生什么事情.

export let number = 1
// 开启定时器
setInterval(() => {
  number++
}, 1000)

上述代码输出了一个一秒钟+1的number.

<template>
  <div class="">
    <span>{{number}}</span>
    <span>{{numberC}}</span>
  </div>
</template>
<script>
import {number} from './export.js'
export default {
  data: function () {
    return {
      number: number
    }
  },
  computed: {
    numberC: function () {
      return number
      // 这里return的number是外层的number,他没有挂载到data,也就是没有经历vue的数据双向绑定,所以是不可能监听到变化的
      // 如果你用return this.number也是监听不到变化的,因为this.number在初始化的时候只能赋值一次,不会去监听赋给他的那个外层变量的值有没有改变
    }
  },
  created () {
    // vue里面少用ES6的箭头函数,会造成this指针指向不正确的问题,这里我只是偷懒,不推荐
    setInterval(() => {
      this.number = number
    }, 1000)
  }
}
</script>

<style>

</style>

  在import引入number后,我在当前的js开了一个定时器,用于接收export.js模块的number的变化,事实证明,number会不断增加,并反应到dom中,有兴趣的可以看上面的注释自己试一下.

猜你喜欢

转载自blog.csdn.net/dkr380205984/article/details/81909312