模块化
本文主要记录了如下内容:
- JS模块化
- 扩展符
- ES6解构赋值
本文适用于刚接触ES6
的新手小白, 很基础,前端和全栈大佬勿喷!
JavaScript
模块化有好几种,如 ES6
支持的模块化、CommandJS
或者AMD
等,这里介绍的是 ES6 的模块化。
在 ES6 中,模块化相关的指令有 import
和 export
这两个指令,export
主要用于规定模块的对外接口,提供给其他模块使用;import
主要用于在需要使用的引入需要用的接口功能。
模块:通常指的是一个独立的文件,该文件内部的变量,函数不export
则其他文件无法使用。就像在Java中需要import
其他的包名或者类的作用一致。只不过Java不需要export
。
如在 UserService.js
中,通过输出一个insertNewUser
给其他模块使用。
export const insertNewUser = (user) => {
return axiosUtil.post('/manage/user/insert.do', user)
}
在需要使用的地方如UserAdd.vue
中引入即可使用。
import { insertNewUser } from '../../service/UserService'
同样的,我们也可以抛出一个成员属性如export const m = 1;
这样也是可以的,但是如下的写法是会出错的。
// 方式一
export 1;
// 方式二
const n = 1
export n;
正确的写法如下:
const n =1
export n;
export {
n
}
// eg2
const age = 10
export {
age as year
}
以第二例子为例说明,age
和age
变量同名,向外提供一个名为year
的接口[相当于取别名],供外部访问。同样的上面的函数也可以改写为如下方式:
const insertNewUser = (user) => {
return axiosUtil.post('/manage/user/insert.do', user)
}
export {
insertNewUser as addUser
}
需要说明的是,export
输出的接口和其值是动态绑定的即源文件中的age
发生变化之后,其他模块也能访问到变化的值。这一点与CommonJS
不同。后者导出的是值的缓存。
上述的export
导出的方式,在使用import
命令导入时,需要我们知道导出的名称才可以。如果将新增用户的函数改名为addUser
之后,就需要改变其他文件引入的函数名称,否则将会出现错误。
为了解决这个问题,我们可以使用提供的export default
作为模块的默认输出,这样在import
时就可以使用任意名称命名,书写方式如下:
// 错误写法 [原因见后文]
export default const insertNewUser = (user) => {
return axiosUtil.post('/manage/user/insert.do', user)
}
// 正确写法 01
export default function insertNewUser (user) {
return axiosUtil.post('/manage/user/insert.do', user)
}
// 正确写法 02
var insertNewUser = "";
export default insertNewUser = (user) => {
return axiosUtil.post('/manage/user/insert.do', user)
}
import addUser from '../../service/UserService'
这样引入时,也就不需要添加{}
,直接引入即可。
使用 export default
有利就有弊,既然作为一个模块的默认输出,也就代表这一模块文件里面只能有一个export default
。本质上,export default
就是输出一个叫做default
的变量或方法,然后系统允许我们取任意名字。正因为如此在default
不能跟着变量申明语句。
扩展符
扩展运算符
扩展运算符是三个点...
【类比于Java中的不定长参数】,可以用来打开一个数组或者一个对象,这样在进合并对象时,或者对象赋值时,就可以省略掉一个属性一个属性的赋值,就可以快速操作!PS:Object.assign()
常用来这么干。写在这里主要是在看别人代码的一些骚操作时,能看懂。
const obj ={
name :123,
age:10
}
const obj2 = {
grade:10,...obj
}
// name age
console.log(obj)
// name age grade
console.log(obj2)
const obj3 = {
...obj
}
// false
console.log(obj === obj3)
可以看到 obj3
是对obj
的值的赋值,而不是引用的赋值。同样也适用于数组如
const array = [1,2,3];
const array2 = [...array]
array2[1] = 4
// output 4
console.log(array2[1])
// output 2
console.log(array[1])
对象的扩展
简洁表达式
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法【建议对比看一下es5的写法】。如
const name = '壹贰是只猫';
const cat = {name};
cat // {name: "壹贰是只猫"}
这样就避免了在赋值对象是需要这样写
const name = '壹贰是只猫';
const cat = {
name:name
}
简化了代码。除了属性名之外,也支持方法的简化书写:
const user = {
getUserName(){
retun "username";
}
}
// 等价于
const user = {
getUserName: function(){
retun "username";
}
}
属性名表达式
在JavaScript
定义对象属性时,可以通过如下方式进行属性定义:
user.name = "壹贰是只猫";
user['gender'] = "雌"
在上面的例子中,中括号里面可以接受一个表达式,将该表达式的运算的结果作为对象的key
如
let name = e.target.dataset.name;
user[name] = "xxxx"
这里就会将name
变量的值运算出来作为user
的属性,其值为xxxx
。
这样的写法简化了很多写法如:当有很多的输入控件需要监听时,我们就可以写一个通用的监听输入函数,而不必一个一个的去写。ps:现在基本上都提供了双向绑定语法糖。一般用不到如下写法。
onChangeInput(e){
// 控件上的name属性
let name = e.target.dataset.name;
// 他的值
let value = Number(e.detail);
this.setData({
[name]:value
})
},
链式判断符和Null值判断符
链式判断运算符主要用在需要读取嵌套对象属性的时候,如在写Java开发时会遇到如下情况
if(user != null){
if(user.address != null){
if(user.address.detail != null){
System.out.println(user.address.detail.code);
}
}
}
此种情况下就可以使用链式运算判断符
user?.address?.detaill?.code
这样就简化了很多代码,?.
的运算逻辑就是左侧对象是否为null
或者undefined
。如果是则不继续运行,如果不是则执行后续的代码【与Kotlin中的?.
操作符类似】。
Null
判断运算符主要用于在读取对象属性时,如果某个属性是null
或者 undefined
,需要为他们指定默认值。在ES5
的写法是有时候会见到如下的代码:
const msg = responseData?.data?.message || "操作失败!";
messageUtil.errorMessage(msg);
在这里我们通过||
指定了默认值,这样是能够实现我们的需求的,但是这样的写法是有问题的,假定我们只需要在undefined
或者null
的情况下指定默认值,但是上述的写法会在左侧的值为 0、false、空字符串
也会指定默认值。这就出现了预期之外的错误。而Null
判断运算符??
就可以避免这种情况。
const msg = responseData?.data?.message ?? "操作失败!";
Null
判断运算符也可以用于函数内部参数赋值:
function successMessage(prop){
const msg = prop.data.message ?? "操作成功";
}
解构赋值
ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,这个过程为解构,常使用的数组解构,对象解构,函数参数解构。【感觉像高中数学里面的等价替换】
数组解构
数组结构,只要左右两边的模式相同,左边的变量就会被赋予对应的值。如简单数组的解构赋值
// a = 1,b = 2 c = 3
let [a,b,c] = [1,2,3]
嵌套数组的解构赋值
// a = 1,b=2,d=4
let [a, [b], d] = [1, [2, 3], 4]
这里b = 2
就进行了不完全解构,只匹配一部分的数组。在进行解构时,也可以指定默认值,因为解构失败时,左边的值会有undefined
,这样我们可以通过指定默认值的情况去避免。
let [a,b,c = 4] = [1,2]
在上面的例子中c
就会解构失败,如果不指定默认值,其值为就为undefined
。
对象解构
数组解构时,是按照元素位置来进行匹配的,而对象解构,则是根据变量名进行模式匹配的
let { name, age } = { name: '对象解构', age: 35 };
name // "对象解构"
age // 35
如果没有相同的变量名,则值为undefined
let { address } = { name: '对象解构', age: 35 };
address // undefined
如果变量名与属性名不一致,又要解构成功就必须指定属性名,写法如下
let {address:addressInfo} = {address:"成华大道"}
addressInfo // 成华大道
左边的address
和右边对象的address
属性一致,然后将值赋值给addressInfo
实际上在第一个对象解构的例子中,可以看作如下代码:
let { name:name, age:age } = { name: '对象解构', age: 35 };
只不过是将name:name,age:age
进行了简写!
函数参数的默认值
在ES6之前,并不能直接给函数的形参指定默认值,只能以如下的方式指定。
function getFullName(firstName,lastName){
firstName = firstName || "Tom";
lastName = lastName || "Jerry"
return firstName " & " + lastName;
}
这样写法的缺点在前面已经描述过了,如果为了更好的判断,还需要添加typeof firstName == 'undefined'
,增加额外的代码书写。为了更好的处理这种情况,ES6提供了简便的写法:
function getFullName(firstName = "Tom",lastName = "Jerry"){
return firstName " & " + lastName;
}
但值得注意的是,ES6这种写法不能有同名参数,且不能用let/const
再次声明。
函数参数+对象解构赋值这样在进行AJAX
请求时,就可以指定默认的请求参数:
// 获取用户列表
export const fetchUserList = ({ currentPage = 1, currentSize = 10, username = '', } = {}) => {
const params = {
currentPage,
currentSize,
}
···
return axiosUtil.get('/manage/user/list.do', { params })
}
如按照上面的请求封装,我们就可以不传递参数进行数据请求。
参考资料: