vue基础 ES6 import、module.exports、原型、原型链(四)

ES6 import/export/module.exports用法

当模块化的概念越来越重要的时候,在es6中,引入了模块的语法:import ,下面我们简单了解一下,import是怎么使用的。一下内容,参考 官方文档

1、export#

一个js文件,可以理解成一个模块,这个模块可以被任意其他的模块引入,引入的结果,就是对这个模块进行执行后,所持有的对象。那么随之而来就有一个问题,文件模块被引入后,所有的东西,都是在自己的作用域中,主动发起引入行为的那个文件,虽然获取到了被引入的对象,但是并不能访问作用域里的东西,所以提供了export,来决定一个模块对外暴露什么东西。

export的作用,就是用于从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们.

在import 一个文件的时候,会获取这个文件对象,默认是空对象,代表我们不能访问文件的东西。使用export,来给这个对象添加内容

用法:
module1.js :

Copy Highlighter-hljs
function f1 (){ console.log("module - 1 : functino 1") } let b = { name:"test_obj" } let str = "hell绿绿绿" export { f1,b,str }

main.js 中进行引入

Copy Highlighter-hljs
// 先忽略 import 的写法,后面再说明 import * as m1 from "./m1.js" console.log(m1)

在这个文件中,我们对外暴露了 一个函数,一个变量,一个对象。所以,在使用 import 导入的文件对象,就不在是一个空对象,而是包含了export 内容的对象。

所以,export 导出的内容,都会添加到文件对象中,可以简单的先理解为深拷贝。

2、export default#

很多初学者很困惑,既然有了 export ,为什么还要有个 export default 呢?网上给出的答案往往是,作为文件的默认导出接口。那什么又是文件的默认导出接口呢?

其实这个问题很简单,我们先抛开 import ,不考虑import 的语法,仅考虑 export default具体做了什么。

修改 module1.js :

Copy Highlighter-hljs
function f1 (){ console.log("module - 1 : functino 1") } let b = { name:"test_obj" } let str = "hell绿绿绿" export { f1,b,str } export default{ name:"default" }

main.js不变,在执行一遍,继续查看打印出来的文件对象,

发现export default 的作用,是给文件对象,添加一个 default属性,default属性的值也是一个对象,且和export default导出的内容完全一致。

3、文件导出的总结#

那么到这里,我们明白了,一个js文件被当做一个模块引入,会暴露为一个对象(也就是被导入后,可以当做一个对象来操作)。

export的作用,是在这个文件对象中添加属性,export出来的东西,全部会添加到文件对象中。

export default 的作用,是给文件对象的 default 属性,添加值。

4、import#

在上面的例子中,我们明白了模块对外暴露的都是什么东西,那么我们如何来使用文件对外暴露的东西呢?

首先我们已经明白,文件对象是什么。

4.1导出整个文件对象

那么首先,我们就导出整个文件对象,看一看是什么样子的。就是上面例子中,我们使用到的语法,import * 来导出文件模块的所有接口,as m_name 来指定一个命名空间对象。

main.js

Copy Highlighter-hljs
import * as m1 from "./m1.js" console.log(m1)

示例中的m1 命名空间对象,可以访问到文件对象的所有对外接口,包括export,和export default。

4.2 导出export的部分接口

在实际开发中,我们并不需要导出所有的接口。例如在vue项目中,使用某个组件库中的某个组件,我们只需要引入这一个组件,不必要引入所有组件。

我们知道,import 导出的是整个文件对象,那么我们直接在 import 语句中,对这个对象进行解构,就可以获得其中某一部分接口:

main.js :

Copy Highlighter-hljs
import {f1,b} from "./m1.js" console.log(f1) console.log(b)

但是这种方式,仅限于获取文件对象的正常属性,default属性是获取不到的,原因有两个:

  • 未解构的对象全部进行了丢弃
  • default是关键字,不能再解构中当做变量进行使用

4.3 导入export default 的接口

export default是文件的默认导入,其实这句话的重点,并不在于 export default,而是在于 import 语句是如何处理文件默认导入的。

修改main.js 文件内容为:

Copy Highlighter-hljs
import d from "./m1.js" console.log(d)

打印出来,惊奇的发现,d 竟然和 export default 的内容一样。

所以,现在可以这么理解,所谓的默认导入,就是毫无花哨的直接导入一个模块,然后赋值给一个命名空间,这种时候,这个命名空间,持有的就是 文件对象的default 对象,也就是export default 出来的东西。

其实,默认导入可以理解为也是解构的一个语法糖(仅仅用作理解,实际是语法错误的):

Copy Highlighter-hljs
import d from "./m1.js" 可以等价为 import {default as d} from "./m1.js"

5、import动态导入#

还有一种高端的玩法,在项目中也是很有用处的。

import不光是一个关键字,同时也是一个函数,函数的参数是需要导入模块的路径,函数返回一个promise对象。

Copy Highlighter-hljs
import("./m1.js").then(m=>{ console.log('then:',m) })

在这段代码中,then中回调的m,就是文件模块的整个文件对象(包括export和export default)。

6、import不导入文件对象#

import还可以不导入文件对象,仅仅是使用文件模块提供的功能。也就是传说中的,import将文件模块仅仅最为副作用进行导入,而不获取文件模块的接口。

在项目中,实践的地方,例如一个vue项目,我们需要给vue对象挂载很多东西,但是全部写在src/main.js 文件中,又会显得特别啰嗦,不利于维护,也没能体现工程化的理念。所以我们常常单独新建一个文件lib/init.js ,然后在这个 init.js 文件中,编写相关逻辑。这个文件的作用,仅仅是执行一遍,我们不期望这个文件暴露什么变量,所以没必要获取文件对象。那么这个时候,import 关键字的另一个作用就体现出来了:
main.js

Copy Highlighter-hljs
import './lib/init.js';

使用import直接引用一个文件时,会执行一遍这个文件,而不获取任何文件对象。

拓展一 import:#

  • 需要注意的是 import是在代码编辑阶段执行的,和export配套使用。

  • 导入from相对路径与绝对路径都可以, .js文件后缀可以省略。

  • 导入的变量名必须与输出的名称保持一致。

    Copy Highlighter-hljs
    //导入变量 import {name, age} from './login'; //导入别名 import {name as otherName } from './login';
  • export default与export的主要区别是不需要知道导出的具体变量名导入时不需要{}

  • 一个模块中只能有一个export default默认输出,但是可以有多个export

    Copy Highlighter-hljs
    //export default export default function fn(){}; import fn from 'fn'; //export export function fn() {}; import {fn} from 'fn';
  • module.exports用法

    module.exportsrequire是配套使用的

    1、返回一个JSON Object

    Copy Highlighter-hljs
    //返回一个JSON Object var app = { name: 'app', age: '18', sayName: function(name){ console.log(this.name); } } module.exports = app; //引入调用 var app = require('./app.js'); app.sayName('hello');//hello

    2、返回一个构造函数

    Copy Highlighter-hljs
    //CLASS.js: var CLASS = function(age){ this.age = age; } module.exports = CLASS //调用 var CLASS = require('./CLASS.js'); varc = new CLASS('arguments')

    3、返回一个实例对象

    Copy Highlighter-hljs
    //CLASS.js var CLASS = function(){ this.name = "class"; } CLASS .prototype.func = function(){ alert(this.name); } module.exports = new CLASS(); //调用 var c = require('./CLASS.js'); c.func();//"class"

拓展二原型、原型链:#

js中 函数也是对象,一个函数是一个Funciton对象,所有对象都有constructor属性.通过这个属性可以查看这个对象的构造函数信息.

构造函数、原型对象与实例对象

什么是构造函数

在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写。

首先每一个函数都有一个prototype属性,这个属性指向一个对象,这个对象就是原型对象;
默认情况下,所有原型对象都会自动获得一个constructor属性,这个属性指向prototype属性所在的函数,也就是构造函数
当调用构造函数创建一个实例对象后,该实例对象有一个内部属性:[[prototype]](在部分浏览器中可通过__proto__访问到),这个属性指向构造函数的原型对象

Copy Highlighter-hljs
”每个构造函数都有一个原型对象, 原型对象都包含一个指向构造函数的指针, 实例都包含一个指向原型对象的内部指针。” ——此段话摘自《JavaScript高级程序设计》。

每个构造函数都有一个原型对象

原来为每个构造函数专门设置了一个原型对象,用来存取一些共享属性,并且可以构成原型链。

那么可以用一个别的独享,替换这个原型对象吗?答案是可以的。

通过对象的形式设置原型对象(共享库)的属性和方法,效果一样的,这样也证明了对象被修改了

Copy Highlighter-hljs
function Person(){ } Person.prototype={ muzhi:10, run:function(){ console.log("我们都会跑") } }

有人会问:哪里证明原型对象可以更改,首先原型对象我们要怎么获取,有以下两种

1.Person.prototyte,这就可以明白为什么上面让他等于对象就替代了的原因。

2.p.proto(__proto__在实际中一般不适用,因为作用是在方便调试产生的)。

图片看了,还不清楚,我们来一一打印一下

Copy Highlighter-hljs
function Person(){ } Person.prototype={ muzhi:10, run:function(){ console.log("我们都会跑") } } var p1=new Person();

原型链

原型链,从一个实例对象向上找有一个构造实例的原型对象,这个原型对象又有构造它的上一级原型对象,如此一级一级的关系链,就构成了原型链。原型链的最顶端就是Object.prototype ;

JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些

当我们访问一个属性值的时候, 它会沿着原型链向上查找, 直到找到或者到Object.prototype.proto(为null)截止.

假如我们有以下例子:

Copy Highlighter-hljs
var foo = {}, F = function(){}; Object.prototype.a = 'value a'; Function.prototype.b = 'value b'; console.log(foo.a) // value a console.log(foo.b) // undefined console.log(F.a) // value a console.log(F.b) // value b

那么

Copy Highlighter-hljs
foo.a的查找路径: foo自身: 没有 ---> foo.__proto__(Object.prototype): 找到value a foo.b的查找路径: foo自身: 没有 ---> foo.__proto__(Object.prototype): 没有 ---> foo.__proto__.__proto__ (Object.prototype.__proto__): 没有 F.a的查找路径: F自身: 没有 ---> F.__proto__(Function.prototype): 没有 ---> F.__proto__.__proto__(Object.prototype): 找到value a F.b的查找路径: F自身: 没有 ---> F.__proto__(Function.prototype): 找到value b
总结:

Object、Function和其他对象的关系:

  • 一切对象都最终继承自Object对象,Object对象继续自根源对象null
  • 一切函数对象都直接继承自Function对象
  • Function对象最终继承自Object对象
posted @   caibaotimes  阅读(1811)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示
CONTENTS