es678910语法糖

Posted pengdt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了es678910语法糖相关的知识,希望对你有一定的参考价值。

傲娇: 新es是js的进步,是编程的进步,es6已经过去了5年了,兼容率达到了90%,还是有10%的手机不兼容,那到底应不应该去照顾那些跟不上的人,我觉得是不应该的,新es能5行写出来的功能,我为什么要用旧的写50行,还那么难理解,难维护,但我还是兼容了,人在屋檐下,不得不低头

Label是es向下兼容的工具,这个在node分类下提及,这里不说

所有的内容都来自 阮一峰大神的博客 2019年11月09日中午12点,博客里的内容从【0前言到31参考链接】 经常用的api有

  • let和const
  • 解构赋值 和 拓展运算符
  • 字符串拓展
  • 数字的拓展
  • 函数的拓展 和 拓展运算符
  • 数组的拓展 和 Iterator
  • 对象的拓展
  • 新类型Set 和 Iterator
  • 新类型Map 和 Iterator
  • Reflect
  • Proxy观察者
  • Promise
  • async
  • class
  • module

let和const

  • let代替了var,let没有变量提升,也可以理解为解析js代码流程中,遇到let会自动跳过,在执行过程中才能识别
  • const不是变量,而是固定常亮,如果是基础数据类型第一次赋值后不能被修改值,如果是复杂数据类型,可以修改内部的内容,但是不能修改数据类型,而且一个函数作用域里只能声明一次,也就是不能声明两次aa,会报错,能保护这个值不轻易被另一个程序员重新声明或者改了 还有些详细内容放在下一篇写

解构赋值 解构赋值分为数组解构和对象解构

数组解构,是按顺序来的,并且左边用数组解构,右边一定要是数组

// 基础应用
// 可以理解为右边的数组是ajax请求来的res
let [a, b, c] = [1, 2, 3];
console.log(a,b,c)

// 跳过使用
let [ , , c] = ["foo", "bar", "baz"];
console.log(c)  // "baz"

// 二级数组
let [a, b, d] = [1, [2, 3], 4];
console.log(b)  //[2,3]

// 拓展运算符
// 拓展运算符一次赋值只能用一次,而且只能用在最后一位
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

对象解构 对象解构是用key赋值的,没有顺序 对象解构比数组解构用得多得多

// 基础应用
// 可以理解为右边的数组是ajax请求来的res
let { bar,foo,ceshi} = { foo: ‘aaa‘, bar: ‘bbb‘ };
console.log(bar,foo,ceshi)  // ‘bbb‘,‘aaa‘,undefined

// 上面的写法其实是对象的省略写法,因为key-value同名所以缩写
// 如果不缩写是 let { bar:bar,foo:foo,ceshi:ceshi} = { foo: ‘aaa‘, bar: ‘bbb‘ };
// 所以不缩写可以重命名
let { bar:newBar,foo:newFoo,ceshi:newCeshi} = { foo: ‘aaa‘, bar: ‘bbb‘ };
console.log(newBar,newFoo,newCeshi)  // ‘bbb‘,‘aaa‘,undefined

// 默认值
var {x = 1} = {};
console.log(x) //1

// 上面的默认值也是省略写法
var {x:newX = 1} = {x: 5};
console.log(newX) //5

//清除对象里不要的key
let {_internal, tooBig, ...cleanObject} = {el1: ‘1‘, _internal:"secret", tooBig:{}, el2: ‘2‘, el3: ‘3‘};
console.log(cleanObject); // {el1: ‘1‘, el2: ‘2‘, el3: ‘3‘}

字符串拓展 上代码自己理解

var basket = {
   count: 10,
   onSale: "aa"
}
// 原先的字符串拼接
$(‘#result‘).append(
  ‘There are <b>‘ + basket.count + ‘</b> ‘ +
  ‘items in your basket, ‘ +
  ‘<em>‘ + basket.onSale +
  ‘</em> are on sale!‘
);

// 新版的字符串拼接,两端是``斜点
// 数据是${...},
// 可以用默认值 ${ name || "pdt" }
// 可以用简单的方法${ time2date(time) }
$(‘#result‘).append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

数字的拓展 之前把字符串转数字用的是减零

Number("123")

// 转不了的就是NaN
Number("123a")  //NaN

函数的拓展 有参数默认值,参数解构,参数拓展运算符,箭头函数

// 参数默认值
// 以往的参数默认值是这样的
function init(name){
   var name = name || "pdt"
}

// es6可以
function init(name = "pdt"){ ... }
// 参数解构
// 老版本
function init(arr,obj){ ... }
init([1,2],{name:"pdt",age:18})

// 新写法
function init([,b],{name="无名"}){
   //比如我只需要数组的第二个和name属性
   console.log(a,b,name)
}
init([1,2],{name:"pdt",age:18})

//参数必填
const required = () => {throw new Error(‘Missing parameter‘)};
const add = (a = required(), b = required()) => a + b;
add(1, 2) //3
// 箭头函数,是function的缩写
// 但是不能作为对象的value,不能作为数组的值,不能作为构造函数
// 箭头函数没有自己的this
// 箭头函数没有三个改变this的方法
// 箭头函数没有arguments

// 声明
var init = () => { ... }

// 作为参数
function init(cb){
   cb(111)
}
// 旧版
init(function(num){ console.log(num )})
// 箭头函数
init((num)=>{ console.log(num })

箭头函数是用来留住this的,具体查看下一篇

数组的拓展 新es给给数组增加了一个叫Iterator的东西,这个查看《遍历总结》 新增了大量的遍历方式,这个查看《遍历总结》 还有拓展运算符代替function的apply方法(apply是什么查看《上下文和作用域》)

// ES5取数组的最大值
Math.max.apply(null, [14, 3, 77])
// ES6取数组的最大值
Math.max(...[14, 3, 77])

// ES5合并数组
arr1.concat(arr2, arr3);
// [ ‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘ ]
// ES6合并数组
[...arr1, ...arr2, ...arr3]

// ES5把伪数组转成数组
Array.prototype.slice.apply(null,ArrayLike)
// ES6把伪数组转成数组
[...ArrayLike]
// 或者新api
Array.from(ArrayLike)

// ES5查看是否含有,返回第一个出现的位置,没有是-1
arr.indexOf("xx")
// ES6查看是否含有,返回true/false
arr.include("xx")

对象的扩展

// 最后一个key-value可以加逗号了
var obj = {
   name: "name",
   age: 18,  //以前这里结束加逗号是不行的
}

// key-value同名可以省略
// 比如要ajax传个参数
var name = "name",age = 18;
ajax({
   // 以前
   // data:{ name: name, age:  gae }
   // 现在可以
   data:{name,age}
})

// 对象的value是function的写法优化
// 老写法
var obj = {
   say: function(){ ... }
}
// 新写法
var obj = {
   say(){ ... }
}

// 对象的遍历,查看《遍历的总结》
// 增加可Obj.vaules() 和 Object.entries()

// 对象的合并assign,这个api是浅拷贝
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
// 也可以
let target = {...target, ...source1}

新类型Set【集合】 Set跟数组差不多,同样是一个畸形的对象 他会自动去重,但只能去重基础数据类型

// 需要通过new去创建,参数是一个数组或者伪数组
let set = new Set([undefined,undefined,NaN,NaN,"",""]); //  set{"undefined",NaN,""}

// set的长度属性
set.size  //3

// 添加某个值,返回set本身,所以可以无限add()
set.add(value)
// 删除某个值,返回一个布尔值,表示删除是否成功
set.delete(value)
// 返回一个布尔值,表示该值是否为Set的成员
set.has(value)
// 清除所有成员,没有返回值
set.clear()

// Set没有办法取值,只能转数组再取值
[...set]
// 或者
Array.from(set)

// Set的遍历,set.keys(),set.values(),set.entries()
// 具体查看《遍历总结》

// 还有一个WeakSet,不重要
// 他跟Set一样,只是他只能存对象,并且带有垃圾回收功能,面试题来着
const ws = new WeakSet();

集合的几个特性

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);

// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter(x => b.has(x)));//ES6
var intersect = new Set([...a].filter(function(x){
    return b.has(x);
}))
// set {2, 3}

// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}

新类型Map【字典】 Map 结构提供了value-value的对应,相比于Object,他的key可以是任一类型

// 通过new创建,参数是一个数组,数组里的值必须都是两个长度的数组
const map = new Map([
  [‘name‘, ‘张三‘],
  [‘title‘, ‘Author‘]
]);

// map的长度属性
map.size // 2


// 添加某个值,返回set本身,所以可以无限add()
map.set(key, value)
// 返回一个布尔值,表示该值是否为Set的成员
set.has(key)
// 
map.get(key) 
// 删除某个值,返回一个布尔值,表示删除是否成功
map.delete(key)
// 清除所有成员,没有返回值
map.clear()

// Map的遍历,map.keys(),map.values(),map.entries()
// 具体查看《遍历总结》

// Map转数组,其实map挺好用的,没必要转,除非是要传给后端
[...map]


// 还有一个WeakMap,不重要
// 只接受对象作为键名(null除外),不接受其他类型的值作为键名
const wm = new WeakMap();

其实Set和Map也非常的稀有,因为数组和对象就已经很好用了,而且还要去兼容,而且还要去转格式转来转去的

Reflect Reflect是ES6为了操作对象而新增的API,配合proxy对数据进行操作简直完美

Reflect.get(target, name, receiver)
Reflect.set(target,name,value,receiver)
Reflect.apply(target,thisArg,args)
Reflect.construct(target,args[, newTarget])
Reflect.defineProperty(target,name,desc)
Reflect.deleteProperty(target,name)
Reflect.has(target,name)
Reflect.ownKeys(target)
Reflect.preventExtensions(target)
Reflect.isExtensible(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

Proxy观察者 这个一般来说是用不到的,是属于架构层面的api了,Vue3.0就是以这个为基础架构的,跟Object.defineProperty一样,这个放在《vue的原理设计》说

// 贴个基础代码
var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});

Promise 查看《promise篇》 Promise里装的都应该是异步函数,如果是同步的反而是产生BUG

// 贴个基础代码
new Promise(function(resolve, reject) {
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
}).then((value)=>{ ... },(error)=>{ ... })

Async 查看《promise篇》 await后面跟着的都是promise异步函数,如果是同步的反而是产生BUG

// 贴个基础代码
async function main() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);
    console.log(‘Final: ‘, val3);
  }
  catch (err) {
    console.error(err);
  }
}

class 查看《class》篇 class就是一个新型的构造函数

// 贴个基础代码
class A {
  constructor(name) {
     // 静态属性/方法
    this.name = name;
  }
  // 相当于原型方法,class不支持原型属性
  print() {
    console.log(this.name);
  }
  // 带有static是私有方法/属性,通过A.myMethod()执行
  static myMethod() {
    console.log(‘static‘);
  }
}

class B extends A {
  constructor(name,age) {
    //继承的
    super();
    this.name = name;
    this.age= age;
  }
  m() {
    console.log(this.age);
  }
}

let b = new B("pdt",18);
b.m() // 18
b.print() // "pdt"

module 查看《模块化》篇 引入js文件的新api但是不被支持,浏览器没支持连nodejs都没支持

// 开放多个,只能全是export,不能有export default
// fs.js
export function A(){ ... }
export B = { ... }
export C = []
export D = "D"

// 引入并且解构赋值
import { A, B, C, D } from ‘fs‘;
// 只能出现一个export default,并且不能有其他export
// default就不需要名字了
// fs.js
export default function(){ ... }
// 或者对象,其他格式都行
export default {}

// 引入并且解构赋值
import fs from ‘fs‘;

除了上面常用的 还有Symbol,Decorator【装饰器】

装饰器文章

  1. Method Decorator 函数装饰器
  2. Property Decorators 熟悉装饰器
  3. Class Decorator 类装饰器
  4. Parameter Decorator 参数装饰器 将来装饰器会变成新的框架,会被制造出像Spring的框架

说几句 这些api升级了js的难度,生产出了大量的玩法和框架,他让前端不再是个jq打天下的菜鸡,他需要学的东西越来越多,这些api高仿自很多的语言,特别是java 比如说拓展运算符,Iterator遍历器,Set,Map,await的原生就是一个yeild,这个也是java的,还有class,model的import,Decorator就是java的注解以及NodeJs的stream流等等

以上是关于es678910语法糖的主要内容,如果未能解决你的问题,请参考以下文章

2020-2-2 语法糖

ES6 语法糖

es6类只是javascript中原型模式的语法糖吗?

常用处理数据用法es6 语法糖总结

详解es6 class语法糖中constructor方法和super的作用

重新认识ES6中的语法糖