Оригинальная ссылка:GitHub.com/осень-зима/…
Эта статья представляет собой статью, ориентированную на приложения, в которой обобщаются различные варианты использования ES6 в соответствии с реальными сценариями проекта. В этой статье не будет слишком подробно объясняться особенности или принципы синтаксиса ES6, а основное внимание будет уделено пониманию нового синтаксиса и новых функций ES6 из реальных сценариев приложений.
1. Объявление переменной
Чтобы решить (или стандартизировать) проблему области видимости на уровне блоков в JS, ES6 добавилletа такжеconstЕсть два способа объявить переменные, иvarРазница в следующем:
-
varОбъявленная переменная, область действия будет расширена, и переменная может быть переназначена; -
letа такжеconstОбъявленная переменная имеет объем уровня блока и временную мертвую зону, но без переменной продвижения; -
letОбъявленная переменная может быть переназначена,constнет.
В нашей ежедневной разработке проектов мы будем использовать помощь IDE при сохранении файлов или отправке Git.EslintИнструменты, подобные этому, проверяют спецификации кода.Одним из распространенных запросов проверки является:声明的变量xxx没有被再赋值,建议使用const.
Поэтому обычно, когда мы объявляем переменные с помощью ES6, мы можем следовать следующим принципам:
- Переменные, которые необходимо переназначить, используйте
letЗаказ; - Для переменных, которые не будут переназначаться, используйте
constЗаказ; - отказаться от использования
varЗаказ.
function submit(){
let loading = true
const postData = this.getParamData()
// ...
loading = false
}
2. Разрушающее назначение
Деструктурирующее присваивание — это процесс извлечения значений из строк, массивов или объектов и присвоения значений переменным. Его можно использовать в определениях переменных, параметрах функций и других сценариях.
// 解构数组
let [name, age, sex='male'] = ['安歌','18']
// output -> name: '安歌', age: 18, sex='male'
// 对象解构
const ange = {name: '安歌', sex: 'male'}
let {
name,
age=18,
sex
} = ange
// output -> name: '安歌', age: 18, sex: 'male'
// 字符串解构
const hi = 'hello'
let [a, b, c, d, e] = hi
let { length } = hi
// output -> a: 'h', b: 'e' ... length: 5
В-третьих, структура данных Set и Map
SetСтруктура данных требует, чтобы ее элементы были неповторяемыми, и эта уникальная особенность может значительно облегчить разработку проекта;MapСтруктура данных — это набор пар ключ-значение, который обеспечивает более широкую поддержку ключевых типов данных и имеет хороший набор API.
Здесь мы берем список данных в качестве сценария: сверка заказов на продажу, требующая, чтобы сверка ограничивалась только одним и тем же продуктом.
1. Неповторяемость набора
// 根据Set内元素不重复的特性,判断申请对账按钮是否可用
function canSubmit() {
const checkedListData = getCheckedList() // 获取选中的数据项列表
const productNos = new Set( // 取出商品ID列表
checkedListData.map(each => each.product_no)
)
return productNos.size === 1
}
2. Хранение картографических данных
/*
* 使用Map数据结构存储勾选数据列表
* 假设列表数据项 item={ id, order_no, product_no, product_name, isChecked }
*/
const checkedData = new Map()
// 选中操作
checkedData.set(item.id, item)
// 取消选中
checkedData.delete(item.id)
// 清空
checkedData.clear()
// 取出选中项ID集合
const recordIds = checkedData.keys()
// 如果需要对选中的数据进行二次筛选,可以取出数据集合
const data = checkedData.values()
// 从其他页码(比如第2页)返回到已访问过的页面(比如第一页),一般需要还原用户的选中状态
checkedData.has(item.id) && (item.isChecked = true)
В-четвертых, строка шаблона
Строки шаблона ES6 позволяют нам встраивать переменные в строку или определять многострочную строку для лучшей читабельности.
const orderNo = 'ON90509000001'
const msg = `订单${orderNo}对账失败!`
// output -> 订单ON90509000001对账失败!
5. Основные функции
1. Стрелочные функции
Стрелочные функции делают ваши выражения более краткими. Он имеет следующие особенности:
- внутри функции
this, это контекст, в котором определена стрелочная функцияthis, который неизменен. но черезbind,call,applyметод изменения контекстаthisнаправление; - Это не конструктор, т.е. его нельзя использовать
newЗаказ; - не существует в теле функции
argumentsОбъект, но может быть использованrestвместо этого параметр; - нельзя использовать
yieldкоманда, поэтому функции стрелок нельзя использовать в качествеGeneratorфункция.
const obj = {
name: '安歌',
hello: function () {
setTimeout(() => console.log(this.name), 1000)
}
}
obj.hello() // output -> '安歌'
obj.hello.call({name: 'Ange'}) // output -> 'Ange'
2. Параметры по умолчанию
function add(x, y, fixed=2) {
const result = (+x) + (+y)
return result.toFixed(fixed)
}
add(1,2) // output -> '3.00'
3. остальные параметры
function add(...args) {
let sum = 0
for (var val of args) {
sum += val
}
return sum
}
add(2, 5, 3) // 10
4. Деструктуризация параметров
function submit() {
this.$post('/login').then( ({code, data}) => {} )
}
6. Условное решение
Управление разрешениями является важной функцией в промежуточной и фоновой системах, от управления правами доступа к странице до полномочий операций определенной функции. Здесь управление разрешениями используется в качестве сценария приложения, чтобы увидеть, как использовать ES6 для элегантного выполнения условного суждения.
1. Контроль разрешений маршрутизации
function hasPer(route) {
const { permissions=[] } = userInfo // 获取用户权限列表
const routePer = route.meta.per // 预先为每个路由配置的访问权限
return permissions.includes(routePer)
}
2. Контроль разрешений системных функций (например, операция согласования)
function checkPer(per) {
const { permissions=[] } = userInfo // 获取用户权限列表
return Array.isArray(per) ?
// per是个列表,permissions需要包含per里面要求的所有权限
per.every(each => permissions.includes(each)) :
(
// per是个正则,permissions需要存在某个权限通过per的正则验证
per instanceof RegExp ? permissions.some(each => per.test(each)) :
// per是个字符串,
permissions.includes(per)
)
}
Семь, перепишите цикл for
Предположим, у нас есть список данных заказа:
const orderList = [
{oid: 'ON0001', pid: 'PN0001', pname: '蘸酱短袖', clinet: '杨过', total: 100, date: '2019-07-10'},
{oid: 'ON0002', pid: 'PN0002', pname: '椒盐短袖', clinet: '小龙女', total: 122, date: '2019-07-10'},
{oid: 'ON0003', pid: 'PN0001', pname: '蘸酱短袖', clinet: '郭襄', total: 100, date: '2019-07-14'},
{oid: 'ON0004', pid: 'PN0003', pname: '炭炙短袖', clinet: '郭襄', total: 137 , date: '2019-07-18'},
{oid: 'ON0005', pid: 'PN0001', pname: '蘸酱短袖', clinet: '小龙女', total: 100, date: '2019-07-20'}
]
1. Составьте карту данных
// 取出列表中的所有订单号
const oIds = orderList.map(each => each.oid)
2. forEach изменяет исходные данные
// 给列表每个订单加一个isCP属性,默认值为false
orderList.forEach(each => each.isCP = false)
3. Как продолжить
Если клиентами-покупателями являются Ян Го и Сяолуннв, идентифицируйте их как пару CP (другими словами, зацикливайте процесс списка и выполняйте его, когда встречается Го Сян).continueЗаказ):
orderList.forEach(each => ['杨过', '小龙女'].includes(each.clinet) && (each.isCP = true))
4. Как разбить
Продавец занимается преимущественной деятельностью и последовательно вычитает 5 юаней из общей стоимости каждого заказа (вычтенные 5 юаней возвращаются покупателю) до тех пор, пока не встретится первый заказ с нечетной общей стоимостью (другими словами, в фантомном процесс списка, первая нечетная общая цена будет выполненаbreakкоманда для завершения цикла).
orderList.some(each => each.total % 2 ? true : each.total -= 5)
// 可以验证,当循环到{oid: 'ON0004', pid: 'PN0003', pname: '炭炙短袖', clinet: '郭襄', total: 137 , date: '2019-07-18'},这条数据之后,因为结果返回true,循环将结束,即后面的数据不会再被循环。
Восемь, преобразование объектов и массивов
Сценарий «что, если». Добавьте стиль статуса к согласованию каждого заказа (success,warning,danger), со следующими данными:
// 状态码说明: 100->对账成功、101->对账中、102->审核中、103->对账失败、104->取消对账
// 规定有如下样式映射表:
const style2StatusMap = {
success: [100],
warning: [101,102],
danger: [103,104]
}
Функция реализации: преобразование таблицы сопоставления стилей в таблицу сопоставления состояний, например:
const status2styleMap = {
100: 'success',
101: 'warning',
102: 'warning',
103: 'danger',
104: 'danger'
}
Используйте ES6entriesа такжеreduceи т.д. Реализация API:
// 实现toPairs函数取出Map的键值对,函数返回形如[[key1,val1]...]的数组
const toPairs = (obj) => Object.entries(obj)
// 实现head/last函数取出列表头尾元素
const head = list => list[0]
const last = list => list.reverse()[0]
// 将对象转换为数组
const pairs = toPairs(style2StatusMap)
// 再将数组转化为对象
const status2styleMap = pairs.reduce((acc, curr) => {
const style = head(curr)
const status = last(curr)
return status.reduce((accer, each) => (accer[each] = style,accer), acc)
}, {})
// output -> {100: "success", 101: "warning", 102: "warning", 103: "danger", 104: "danger"}
9. Сбор данных
Иногда нам нужно вынести часть элемента данных в объект данных, а затем передать его компоненту или отправить на сервер после определенной сборки.
Сценарий «что, если».formПеременные хранят данные формы,routerс некоторыми параметрамиqueryData. Реализация повторно собирает измененные данные и отправляет их на сервер, но некоторые данные отправлять не нужно.
// 基础数据
let form = { name: '账单名', no: '对账单编号', oNo: '订单编号', pNo: '商品编号', pName: '商品名'@, pNum: '商品数量', applicant: 'ange@gmail.com(安歌)', ... }
const query= { id: '对账单ID'}
1. Object.assign данные извлечения
// 先覆写applicant参数
Object.assign(form, {
applicant: form.applicant.split('(')[0]
// ...其他可能需要覆写或追加的参数
}
2. фильтровать данные фильтра
// 采集出需要的数据项
const exclude = ['pName', 'pPrice']
const formData = Object.keys(form)
.filter(each => !exclude.includes(each))
.reduce((acc, key) => (acc[key] = form[key], acc), {}
3. Оператор распространения для объединения данных
// 使用扩展运算符组合form和query的参数
const postData = {
...formData,
...query
}
10. Асинхронные функции
ES6 обеспечиваетPromiseобъект иasyncФункции используются для обработки асинхронных операций, т.httpпросилaxiosбиблиотека основана наPromiseосуществленный. использоватьPromiseсвойства, мы можемhttpВозвращаемое содержимое запроса перехватывается без уведомления разработчика.
Сценарий приложения: Интерфейсы промежуточной и фоновой систем обычно имеют строгие требования к разрешениям, и нам необходимо фиксировать исключения интерфейса. Перехватывая и инкапсулируя, вы можете выполнить уровень проверки до того, как код бизнес-уровня получит данные.
1. Переупаковать пост на основе Promise
// 根据需要自定义创建Axios对象实例
const axios = new Axios.create()
// 封装post函数
const $post = (url, postData) => {
return axios.post(url, postData) // 在未封装的情况下,我们一般通过这种方式发起一个post请求
.then(interceptors.bind(this)) // 针对权限验证的拦截
.catch(reject.bind(this)) // 捕获接口异常
}
// 业务层调用
$post('./get_order_list', postData).then(res => {})
2. Перехватчик перехватчиков
// 预处理后端错误码
const interceptors = (res) => {
const code = res.data.code
if(code === 100) { // 未登录
console.log('请先登录') // or redirect to login_error_url
return Promise.reject('LoginError')
} else if (code === 101) { // 缺失访问/修改/删除权限
console.log('没有访问权限') // or redirect to permission_error_url
return Promise.reject('PermissionError')
} else { // 正常将数据返回
return response.data
}
}
3. Отказ от функции перехвата исключений
// 针对接口异常的捕获
const reject = (error) => {
if(error instanceof Error) {
const errMsg = error.message
let type = 'error'
let message = '服务器出错了',请联系管理员
if(/timeout/.test(errMsg)) { // 服务器请求超时
message = '请求超时...'
type = 'warning'
}
// ...
console.log(message)
}
return Promise.reject(error)
}
Эффект следующий:
4. Асинхронные функции делают асинхронный код более элегантным и лаконичным.
// 配合await关键字一起使用
const submit = async () => {
const data = await $post(url)
// ...
}
// 也可以用在Vue等框架的钩子函数中
async mounted () {
const data = await $post(url)
// ...
}
Одиннадцать, динамическая загрузка (импорт)
В системе могут быть некоторые функции (типа печати), требующие внедрения сторонних библиотек (html2canvas.js,print.jsи т. д.), но иногда некоторые сторонние библиотеки могут быть огромными по размеру, и пользователи, посещающие страницу, могут не обязательно запускать функцию, в этом случае можно рассмотреть динамическое внедрение.
function print () {
import('html2canvas.js').then((html2pdf) => {
html2pdf().outputPdf()
})
}
import()вернутьPromiseОбъект, который загружает указанный модуль только во время выполнения. Другой распространенный сценарий применения:VueМаршруты загружаются лениво.
const productListModule = () => import(/* webpackChunkName: "product" */ 'view/product/List') // 商品列表
Двенадцать, многомерная комбинированная сортировка
Предполагаемый сценарий: на странице со списком продуктов есть два сортируемых столбца: цена за единицу (price) и стили (style). Если сначала щелкнуть Сортировать по цене за единицу, а затем Сортировать по стилю, стили должны быть отсортированы в соответствии с порядком цены за единицу.
// 基础数据
const products = [
{ name: "椒盐T恤", price: 3, style: 'Japanese' },
{ name: "蘸酱短袖", price: 5, style: 'Chinese' },
{ name: "碳炙短袖", price: 4, style: 'Chinese' },
{ name: "印花短袖", price: 8, style: 'England' },
{ name: "写意短袖", price: 3, style: 'Chinese' },
{ name: "清蒸T恤", price: 4, style: 'Japanese' },
]
// 定义不同的排序规则
const byPrice = (a, b) => a.price - b.price
const byStyle = (a, b) => a.style > b.style ? 1 : a.style === b.style ? 0 : -1
// 利用reduce组合排序
const sortByFlattened = fns => (a,b) =>
fns.reduce((acc, fn) => acc || fn(a,b), 0)
// 组合后的排序函数,排序优先级按数组内元素位置编号
const byPriceStyle = sortByFlattened([byPrice,byStyle])
console.log(products.sort(byPriceStyle))
Результаты сортировки следующие: сначала по цене в порядке возрастания, затем по стилю в порядке возрастания.
Эпилог
Вышеприведенное является лишь кратким описанием использования ES6 в повседневной разработке отдельными лицами. Оно не включает все функции ES6. Есть еще много функций, которые используются реже.Приглашаем всех общаться и делиться применением ES6 в вашем реальном проекте..
Наконец, если вы считаете, что эта статья вдохновила вас, пожалуйста, не скупитесь на лайки, ха-ха~