ES6:JavaScript开发者的速成手册(二)

前言

本教程将分为两大部分深入解读ES6的精髓。将带你领略ES6的基础语法,将深入探讨ES6的高级特性,通过浅显易懂的语言和大量精炼的代码示例,为你揭开现代JavaScript的神秘面纱。帮助你深入理解并掌握ES6的强大功能。无论你是初学者还是资深开发者,本教程都将是了解ES6、提升编程技能的宝贵资源,亦可作为你随时查阅的参考手册。

在这里插入图片描述


Reflect API

优点:

  • 让Object操作都变成函数行为。
    • 比如name in objdelete obj[name],而Reflect.has(obj, name)Reflect.deleteProperty(obj, name)让它们变成了函数行为。
  • Reflect对象的方法与Proxy对象的方法一一对应, 只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。
  • 有了Reflect对象以后,很多操作会更易读。

常用语 转换成 Reflect语法:

let Obj = {
  name: "jack",
  gender: "男",
};
Obj.name; // Reflect.get(Obj,'name')
Obj.name = "proxyName";  // Reflect.set(Obj, 'name', 'proxyName');
"name" in Obj;  // Reflect.has(Obj, 'name');
delete Obj.name;  // Reflect.deleteProperty(Obj, 'name');
Object.keys(Obj) // Reflect.ownKeys(Obj); // ['name','gender']

Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。 , 结合上面Reflect的语法,我们可以函数化所有对象的操作

所有可以用的对象实例操作 , 对应的的代理操作

var handler =
{
  // target.prop
  get: ...,
  // target.prop = value
  set: ...,
  // 'prop' in target
  has: ...,
  // delete target.prop
  deleteProperty: ...,
  // target(...args)
  apply: ...,
  // new target(...args)
  construct: ...,
  // Object.getOwnPropertyDescriptor(target, 'prop')
  getOwnPropertyDescriptor: ...,
  // Object.defineProperty(target, 'prop', descriptor)
  defineProperty: ...,
  // Object.getPrototypeOf(target), Reflect.getPrototypeOf(target),
  // target.__proto__, object.isPrototypeOf(target), object instanceof target
  getPrototypeOf: ...,
  // Object.setPrototypeOf(target), Reflect.setPrototypeOf(target)
  setPrototypeOf: ...,
  // Object.keys(target)
  ownKeys: ...,
  // Object.preventExtensions(target)
  preventExtensions: ...,
  // Object.isExtensible(target)
  isExtensible :...
}

部分代码实例

let target = function (name) {
  this.name = name;
  return "I am the target";
};
let handler = {
  get: function (receiver, key) {
    console.log("get:", receiver, key);
    return Reflect.get(receiver, key);
  },
  set: function (receiver, key, value) {
    console.log("set:", receiver, key, value);
    return Reflect.set(receiver, key, value);
  },
  has: function (receiver, key) {
    console.log("has:", receiver, key);
    return Reflect.has(receiver, key);
  },
  deleteProperty: function (receiver, key) {
    console.log("deleteProperty:", receiver, key);
    return Reflect.deleteProperty(receiver, key);
  },
  // 函数调用
  apply: function (receiver, ...args) {
    console.log("apply:", receiver, args);
    return Reflect.apply(receiver, ...args);
  },
  // 函数new
  construct: function (receiver, ...args) {
    console.log("construct:", receiver, args);
    return Reflect.construct(receiver, ...args);
  },
  ownKeys: function (receiver) {
    console.log("ownKeys:", receiver);
    return Reflect.ownKeys(receiver);
  },
};
//创建代理对象,后面所有的操作就对代理操作进行操作就行
let p = new Proxy(target, handler);
p.name;
p.name = "proxyName";
"name" in p;
delete p.name;
p("ziyu");
let p1 = new p("ziyu");

console.log(Object.keys(p));

在这里插入图片描述

Proxy 与 defineProperty 的区别

可以阅读下我之前写的 Object.defineProperty与Proxy对比【简单易懂】

Symbols

  • ES5 的对象属性名都是字符串,这容易造成属性名的冲突。所以我们要保证每个属性的名字都是独一无二就成了发展的目标。
  • ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
  • Symbol 值通过Symbol函数生成。对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型
let s = Symbol('foo');
let s1 = Symbol('foo');
console.log(typeof s)   // "symbol"
console.log(s === s1);

//有时,我们希望重新使用同一个 Symbol 值,Symbol.for()方法可以做到这一点。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
console.log(s1 === s2) // true

// Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key。
Symbol.keyFor(s1) // "foo"

内置的 Symbol 值

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.species
  • Symbol.match
  • Symbol.replace
  • Symbol.search
  • Symbol.split
  • Symbol.iterator 前文提到的 遍历器
  • Symbol.toPrimitive
  • Symbol.toStringTag
  • Symbol.unscopables

Generators

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。,执行 Generator 函数会返回一个遍历器对象, 可以依次遍历 Generator 函数内部的每一个状态。

Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hw = helloWorldGenerator();
// 这是不是跟前文 遍历器 结构很像
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }

Generator 函数可以不用yield表达式,这时就变成了一个单纯的暂缓执行函数。

function* f() {
  console.log('执行了!')
}
var generator = f();

setTimeout(function () {
  generator.next()
}, 2000);

generator处理异步代码

这里使用到了 Promise 来让代码拥有异步功能,Promise 概念下面会介绍到

function* asyncGenerator() {
  yield Promise.resolve(1);
  yield Promise.resolve(2);
  yield Promise.resolve(3);
}

 function useAsyncGenerator() {
 for  (const value of asyncGenerator()) {
   value.then(e=>{
    console.log(e);
   })
 }
}

useAsyncGenerator();
//1
//2
//3

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

详细介绍见 这篇文章 手写Promise原理全过程【看了就会】

Async

  • ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
  • async 函数是什么?一句话,它就是 Generator 函数的语法糖。
  • async函数就是将 Generator 函数的星号(*)替换成async,将 yield 替换成await,仅此而已。

特点:

  • Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器
  • 返回值是 Promise。可以使用then方法添加回调函数
  • 当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
async function f() {
  try {
    await Promise.reject('出错了'); // 类似同步代码,异常能被捕获
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}
f().then(v => console.log(v)) // hello world

Module

  • 在 ES6 之前,最主要的有 CommonJSAMD 两种。前者用于服务器,后者用于浏览器。
  • ES6 模块的设计思想是尽量的静态化使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
// CommonJS模块
let { stat } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
// ES6模块
import { stat } from 'fs';

上面代码的实质是从fs模块加载 stat 方法,其他方法不加载。这种加载称为“编译时加载” 或者 静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。由于 ES6 模块是编译时加载,使得静态分析成为可能。

API介绍

模块功能主要由两个命令构成:exportimport export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
特点:

  • importexport 命令只能在模块的顶层,不能在代码块之中 ,但是 import()函数 可以在代码块中,支持动态加载模块
if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}
// profile.js
let firstName = 'Michael';
let lastName = 'Jackson';
let year = 1958;
//变量导出
export { firstName, lastName, year };
//默认导出
export default function () {
  console.log('foo');
}
//index.js 
import defaultFn , { firstName, lastName, year } from './profile.js'
//这些导出的变量都是只读的不能修改

// firtName = "zs" // error 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子羽bro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值