vue基础 ES6 import、module.exports、原型、原型链(四)
ES6 import/export/module.exports用法
当模块化的概念越来越重要的时候,在es6中,引入了模块的语法:import ,下面我们简单了解一下,import是怎么使用的。一下内容,参考 官方文档
1、export#
一个js文件,可以理解成一个模块,这个模块可以被任意其他的模块引入,引入的结果,就是对这个模块进行执行后,所持有的对象。那么随之而来就有一个问题,文件模块被引入后,所有的东西,都是在自己的作用域中,主动发起引入行为的那个文件,虽然获取到了被引入的对象,但是并不能访问作用域里的东西,所以提供了export,来决定一个模块对外暴露什么东西。
export的作用,就是用于从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们.
在import 一个文件的时候,会获取这个文件对象,默认是空对象,代表我们不能访问文件的东西。使用export,来给这个对象添加内容
用法:
module1.js
:
function f1 (){
console.log("module - 1 : functino 1")
}
let b = {
name:"test_obj"
}
let str = "hell绿绿绿"
export {
f1,b,str
}
在main.js
中进行引入
// 先忽略 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
:
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
:
import * as m1 from "./m1.js"
console.log(m1)
示例中的m1
命名空间对象,可以访问到文件对象的所有对外接口,包括export,和export default。
4.2 导出export的部分接口
在实际开发中,我们并不需要导出所有的接口。例如在vue项目中,使用某个组件库中的某个组件,我们只需要引入这一个组件,不必要引入所有组件。
我们知道,import 导出的是整个文件对象,那么我们直接在 import
语句中,对这个对象进行解构,就可以获得其中某一部分接口:
main.js
:
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
文件内容为:
import d from "./m1.js"
console.log(d)
打印出来,惊奇的发现,d 竟然和 export default 的内容一样。
所以,现在可以这么理解,所谓的默认导入,就是毫无花哨的直接导入一个模块,然后赋值给一个命名空间,这种时候,这个命名空间,持有的就是 文件对象的default 对象,也就是export default 出来的东西。
其实,默认导入可以理解为也是解构的一个语法糖(仅仅用作理解,实际是语法错误的):
import d from "./m1.js" 可以等价为 import {default as d} from "./m1.js"
5、import动态导入#
还有一种高端的玩法,在项目中也是很有用处的。
import不光是一个关键字,同时也是一个函数,函数的参数是需要导入模块的路径,函数返回一个promise对象。
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
:
import './lib/init.js';
使用import直接引用一个文件时,会执行一遍这个文件,而不获取任何文件对象。
拓展一 import:#
-
需要注意的是 import是在代码编辑阶段执行的,和export配套使用。
-
导入from相对路径与绝对路径都可以,
.js
文件后缀可以省略。 -
导入的变量名必须与输出的名称保持一致。
//导入变量 import {name, age} from './login'; //导入别名 import {name as otherName } from './login';
-
export default与export的主要区别是
不需要知道导出的具体变量名
与导入时不需要{}
-
一个模块中
只能有一个export default默认输出
,但是可以有多个export
//export default export default function fn(){}; import fn from 'fn'; //export export function fn() {}; import {fn} from 'fn';
-
module.exports用法
module.exports
和require
是配套使用的1、返回一个JSON Object
//返回一个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、返回一个构造函数
//CLASS.js: var CLASS = function(age){ this.age = age; } module.exports = CLASS //调用 var CLASS = require('./CLASS.js'); varc = new CLASS('arguments')
3、返回一个实例对象
//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__访问到),这个属性指向构造函数的原型对象
”每个构造函数都有一个原型对象,
原型对象都包含一个指向构造函数的指针,
实例都包含一个指向原型对象的内部指针。”
——此段话摘自《JavaScript高级程序设计》。
每个构造函数都有一个原型对象
原来为每个构造函数专门设置了一个原型对象,用来存取一些共享属性,并且可以构成原型链。
那么可以用一个别的独享,替换这个原型对象吗?答案是可以的。
通过对象的形式设置原型对象(共享库)的属性和方法,效果一样的,这样也证明了对象被修改了
function Person(){
}
Person.prototype={
muzhi:10,
run:function(){
console.log("我们都会跑")
}
}
有人会问:哪里证明原型对象可以更改,首先原型对象我们要怎么获取,有以下两种
1.Person.prototyte,这就可以明白为什么上面让他等于对象就替代了的原因。
2.p.proto(__proto__在实际中一般不适用,因为作用是在方便调试产生的)。
图片看了,还不清楚,我们来一一打印一下
function Person(){
}
Person.prototype={
muzhi:10,
run:function(){
console.log("我们都会跑")
}
}
var p1=new Person();
原型链
原型链,从一个实例对象向上找有一个构造实例的原型对象,这个原型对象又有构造它的上一级原型对象,如此一级一级的关系链,就构成了原型链。原型链的最顶端就是Object.prototype ;
JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些
当我们访问一个属性值的时候, 它会沿着原型链向上查找, 直到找到或者到Object.prototype.proto(为null)截止.
假如我们有以下例子:
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
那么
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对象
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?