ES6真题合集(二)

6. ES6中 Module

模块(Module)是一个重要的特性,它允许开发者将代码分割成独立的、可复用的单元,每个单元都有自己的作用域。ES6模块通过import和export关键字来实现模块之间的导入和导出。

6.1 导出(Export)

可以使用export关键字来导出函数、对象、原始值或类。一个模块可以导出多个值。

// math.js  
export function add(x, y) {  
  return x + y;  
}  
  
export function subtract(x, y) {  
  return x - y;  
}  
  
// 或者使用花括号({})来导出多个值  
// 这种方式也允许你重命名导出的值  
function multiply(x, y) {  
  return x * y;  
}  
  
export { multiply as mult };  
  
// 还可以导出整个模块的内容  
export * from 'anotherModule';  
  
// 导出默认值  
const pi = 3.14159;  
export default pi;

6.2 导入(Import)

在另一个模块中,你可以使用import关键字来导入已导出的函数、对象或值。

// main.js  
// 导入命名导出  
import { add, subtract } from './math.js';  
  
console.log(add(1, 2)); // 输出 3  
console.log(subtract(2, 1)); // 输出 1  
  
// 导入重命名的导出  
import { mult as multiply } from './math.js';  
  
console.log(multiply(2, 3)); // 输出 6  
  
// 导入整个模块的内容  
import * as math from './math.js';  
  
console.log(math.add(1, 2)); // 输出 3  
  
// 导入默认值  
import pi from './math.js';  
  
console.log(pi); // 输出 3.14159(注意:这里默认导出的是pi,而不是整个math模块)  
  
// 导入默认值并给它一个别名  
import myPi from './math.js';  
  
console.log(myPi); // 输出 3.14159

注意点:
1.ES6模块是静态的,这意味着在编译时(而不是运行时)就确定了导入和导出的内容。
2.ES6模块默认是严格模式(strict mode),即代码在严格模式下运行。
3.ES6模块支持循环依赖,但应该尽量避免,因为它们可能导致难以预料的结果。
4.在浏览器中,可以通过<script type="module">标签来加载ES6模块。在Node.js中,从v12开始,可以使用.mjs文件扩展名或package.json中的"type": "module"字段来启用ES6模块支持。
5.ES6模块提供了一个内置的模块作用域,这意味着模块顶层的变量和函数声明在模块内部是私有的,只有通过export才能被外部访问。

7. ES6中 Generator

Generator(生成器)是一种特殊的函数,它允许你暂停和恢复函数的执行。这主要通过function*语法和yield关键字来实现。Generator函数在执行过程中,遇到yield表达式就暂停执行,并返回一个遍历器对象。这个遍历器对象可以记录当前Generator函数的执行上下文,以便后续再次调用时从该位置继续执行。

7.1 基础用法

Generator函数的声明方式是在function关键字后添加一个星号*。函数体内部使用yield表达式来定义每次返回的表达式。

function* generatorFunction() {  
  yield 'Hello';  
  yield 'World';  
  return 'ending';  
}  
  
const generator = generatorFunction();  
  
console.log(generator.next().value); // 输出 "Hello"  
console.log(generator.next().value); // 输出 "World"  
console.log(generator.next().value); // 输出 "ending"  
console.log(generator.next().value); // 输出 undefined,因为已经执行完毕

7.2 特点

  • 暂停执行:Generator函数在执行过程中,遇到yield表达式就会暂停执行,返回遍历器对象的指针。
  • 恢复执行:通过调用遍历器对象的next()方法,可以恢复Generator函数的执行,并从上次暂停的位置继续执行。
  • 状态可控:由于Generator函数可以暂停和恢复执行,因此可以通过编程来控制其执行状态。
  • 返回值:每次调用next()方法时,会返回一个对象,该对象包含两个属性:value和done。value属性表示当前yield表达式的值,done属性表示Generator函数是否已经执行完毕。当done为true时,value表示返回的最终结果。

7.3 应用场景

  • 异步编程:Generator函数常与Promise结合使用,实现异步编程的流程控制。通过yield表达式来等待异步操作的结果,然后恢复执行后续的代码。这种方式可以使异步代码看起来更加同步,易于理解和维护。
  • 控制流程:Generator函数可以用于控制函数的执行流程,例如实现迭代器、协程等。
  • 数据懒加载:由于Generator函数可以暂停和恢复执行,因此可以实现数据的懒加载。即只有在需要时才加载数据,从而节省内存和网络带宽。
  • 简化复杂操作:对于一些复杂的操作,可以将其拆分成多个步骤,并使用Generator函数来组织这些步骤。这样可以使代码更加清晰、易于理解和维护。

案例:

异步编程的同步化表达

function* fetchData(url) {  
  try {  
    const response = yield fetch(url); // 发起异步请求  
    if (!response.ok) {  
      throw new Error(`HTTP error! status: ${response.status}`);  
    }  
    const data = yield response.json(); // 等待异步请求结果并解析为JSON  
    console.log(data); // 输出获取到的数据  
  } catch (error) {  
    console.error('There has been a problem with your fetch operation:', error);  
  }  
}  
  
// 实例化Generator函数  
const getData = fetchData('https://api.example.com/data');  
  
// 启动Generator函数  
getData.next().value // 返回一个Promise对象  
  .then(response => getData.next(response).value) // 传入response到下一个yield  
  .then(data => getData.next(data)) // 如果没有yield,则不需要传入值  
  .catch(error => getData.throw(error)); // 如果有错误,则抛出异常

控制抽奖次数

function draw() {  
  // 具体抽奖逻辑  
  console.log('抽奖一次!');  
}  
  
function* residue(count) {  
  while (count > 0) {  
    count--;  
    yield draw(); // 每次抽奖都yield一个表达式(在这里是draw函数的调用)  
  }  
  console.log('抽奖结束!');  
}  
  
// 实例化Generator函数并传入初始抽奖次数  
let star = residue(5);  
  
// 模拟用户点击抽奖按钮  
for (let i = 0; i < 5; i++) {  
  star.next(); // 每次点击都调用next()方法  
}

8. ES6中 Decorator

在ES6中,Decorator(装饰器)是一个实验性的特性,用于修改类的行为或属性。它本质上是一个用于类声明、方法、属性或参数上的设计模式,它允许你添加额外的功能到类声明、方法、属性或参数上,而无需修改其本身的代码。 要在TypeScript或某些Babel转译的JavaScript环境中使用Decorator,你需要相应的插件或配置。

8.1 基础用法

@decoratorName(parameters)  
class MyClass {  
  // ...  
}  
  
// 或者用于方法、属性等  
class MyClass {  
  @decoratorName(parameters)  
  myMethod() {  
    // ...  
  }  
}

示例:用于记录类实例化的次数

function Loggable(target) {  
  let counter = 0;  
  return class extends target {  
    constructor(...args) {  
      super(...args);  
      counter++;  
      console.log(`${this.constructor.name} instantiated ${counter} times`);  
    }  
  };  
}  
  
@Loggable  
class MyClass {  
  // ...  
}  
  
// 实例化MyClass  
new MyClass(); // 输出 "MyClass instantiated 1 times"  
new MyClass(); // 输出 "MyClass instantiated 2 times"

9. ES6新增Set、Map两种数据结构

9.1 Set

Set 对象是一种值的集合,它类似于数组,但成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成 Set 数据结构。

  • 创建Set:使用new Set()创建一个空的Set,或者使用new Set(iterable)从一个可迭代对象(如数组)中创建Set。
  • 添加成员:使用add()方法向Set中添加新的成员。
  • 删除成员:使用delete()方法从Set中删除指定的成员。
  • 检查成员:使用has()方法检查Set中是否包含指定的成员。
  • 清除成员:使用clear()方法清除Set中的所有成员。
// 创建一个 Set 实例  
const mySet = new Set();  
  
// 添加元素  
mySet.add(1);  
mySet.add(2);  
mySet.add(2); // 重复添加,Set 中不会有重复值  
  
// 遍历 Set  
for (let item of mySet) {  
  console.log(item); // 1, 2  
}  
  
// 检查元素是否存在  
console.log(mySet.has(1)); // true  
console.log(mySet.has(3)); // false  
  
// 删除元素  
mySet.delete(2);  
console.log(mySet.has(2)); // false  
  
// 获取集合大小  
console.log(mySet.size); // 1

9.2 Map

Map 对象保存键值对,并且可以记住键的原始插入顺序。任何值(对象或者原始值)都可以作为一个键或一个值。

  • 创建Map:使用new Map()创建一个空的Map,或者使用new Map(iterable)从一个可迭代对象(如数组)中创建Map,其中可迭代对象的元素是键值对数组。
  • 添加键值对:使用set()方法向Map中添加新的键值对。
  • 获取值:使用get()方法通过键获取对应的值。
  • 检查键:使用has()方法检查Map中是否包含指定的键。
  • 删除键值对:使用delete()方法从Map中删除指定的键值对。
  • 清除所有键值对:使用clear()方法清除Map中的所有键值对。
// 创建一个 Map 实例  
const myMap = new Map();  
  
// 添加键值对  
myMap.set('key1', 'value1');  
myMap.set('key2', 'value2');  
  
// 遍历 Map  
for (let [key, value] of myMap) {  
  console.log(key + ' => ' + value); // "key1 => value1", "key2 => value2"  
}  
  
// 检查键是否存在  
console.log(myMap.has('key1')); // true  
  
// 获取键对应的值  
console.log(myMap.get('key1')); // "value1"  
  
// 删除键值对  
myMap.delete('key1');  
console.log(myMap.has('key1')); // false  
  
// 获取集合大小  
console.log(myMap.size); // 1

9.3 对比

特性/方法SetMap
数据结构值的集合,成员唯一键值对的集合,键唯一
成员类型成员是任意类型的值键和值都是任意类型的值
成员重复性成员的值是唯一的,没有重复键是唯一的,值可以重复
有序性无序(但迭代时按插入顺序)有序(迭代时按插入顺序)
获取大小size 属性返回成员数量size 属性返回键值对数量
添加成员add(value)set(key, value)
删除成员delete(value)delete(key)
检查成员has(value)has(key)
获取成员通过迭代获取值get(key) 获取与键对应的值
清空集合clear()clear()
遍历值迭代Set即可遍历所有值使用 values() 方法或 […map.values()]
遍历键无直接方法,但迭代Set即遍历所有值使用 keys() 方法或 […map.keys()]
遍历键值对无直接方法使用 entries() 方法或 […map.entries()]
默认迭代器迭代Set时默认遍历值迭代Map时默认遍历键值对
应用场景数组去重、交集、并集等集合操作对象存储、缓存、统计数据等需要键值对结构的情况

9.4 案例

数组去重

let arr = [1, 2, 2, 3, 4, 4, 5];  
let uniqueArr = [...new Set(arr)]; // 使用扩展运算符将Set转换回数组  
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

交集、并集、差集

let set1 = new Set([1, 2, 3]);  
let set2 = new Set([2, 3, 4]);  
  
// 交集  
let intersection = new Set([...set1].filter(x => set2.has(x)));  
console.log(intersection); // 输出: Set { 2, 3 }  
  
// 并集  
let union = new Set([...set1, ...set2]);  
console.log(union); // 输出: Set { 1, 2, 3, 4 }  
  
// 差集 (set1中存在于set2中不存在的元素)  
let difference = new Set([...set1].filter(x => !set2.has(x)));  
console.log(difference); // 输出: Set { 1 }

对象存储

let obj1 = { id: 1, name: 'Alice' };  
let obj2 = { id: 2, name: 'Bob' };  
let map = new Map();  
map.set(obj1, 'Alice\'s data');  
map.set(obj2, 'Bob\'s data');  
  
console.log(map.get(obj1)); // 输出: 'Alice\'s data'  
console.log(map.get(obj2)); // 输出: 'Bob\'s data'

缓存

let cache = new Map();  
  
// 存储数据到缓存  
cache.set('key1', 'value1');  
cache.set('key2', 'value2');  
  
// 从缓存中获取数据  
console.log(cache.get('key1')); // 输出: 'value1'  
  
// 检查缓存中是否存在某个键  
console.log(cache.has('key2')); // 输出: true  
  
// 删除缓存中的某个键值对  
cache.delete('key1');  
  
// 遍历缓存中的所有键值对  
for (let [key, value] of cache) {  
    console.log(key, value); // 输出: 'key2' 'value2'  
}

统计数据

let text = 'hello world hello es6';  
let wordMap = new Map();  
  
// 分割文本为单词数组,并统计每个单词的出现次数  
text.split(' ').forEach(word => {  
    if (wordMap.has(word)) {  
        wordMap.set(word, wordMap.get(word) + 1);  
    } else {  
        wordMap.set(word, 1);  
    }  
});  
  
// 遍历Map并打印结果  
for (let [word, count] of wordMap) {  
    console.log(`${word}: ${count}`); // 输出: hello: 2, world: 1, es6: 1  
}

10. ES6中 Proxy

Proxy 对象用于定义一个自定义的行为,包括基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。通过使用 Proxy,你可以拦截并修改一个对象上的底层操作。

10.1 基础用法

Proxy 接收两个参数:一个目标对象(即需要被代理的对象)和一个处理器对象(一个定义了各种拦截行为的对象)。

const target = {}; // 目标对象  
  
const handler = {  
  get(target, propKey, receiver) {  
    // 拦截 get 操作  
    console.log(`Getting ${propKey}`);  
    return Reflect.get(...arguments);  
  },  
  set(target, propKey, value, receiver) {  
    // 拦截 set 操作  
    console.log(`Setting ${propKey} = ${value}`);  
    return Reflect.set(...arguments);  
  },  
  // ... 可以定义其他陷阱函数  
};  
  
const proxy = new Proxy(target, handler); // 创建一个代理对象  
  
// 现在对 proxy 的操作会触发 handler 中的陷阱函数  
proxy.foo = 'bar'; // "Setting foo = bar"  
console.log(proxy.foo); // "Getting foo", 然后输出 "bar"

10.2 处理器对象

处理器对象定义了各种陷阱函数(trap),用于拦截不同的操作。

陷阱函数参数描述
get(target, propKey, receiver)target: 目标对象
propKey: 属性名(字符串或Symbol)
receiver: 最初被调用的对象(通常是代理对象本身)
拦截对象属性的读取操作
set(target, propKey, value, receiver)target: 目标对象
propKey: 属性名(字符串或Symbol)
value: 要设置的值
receiver: 最初被调用的对象(通常是代理对象本身)
拦截对象属性的设置操作
has(target, propKey)target: 目标对象
propKey: 属性名(字符串或Symbol)
拦截 in 操作符的行为
deleteProperty(target, propKey)target: 目标对象
propKey: 属性名(字符串或Symbol)
拦截 delete 操作符删除属性的行为
defineProperty(target, propKey, desc)target: 目标对象
propKey: 属性名(字符串或Symbol)
desc: 属性描述符
拦截 Object.defineProperty 的行为
getOwnPropertyDescriptor(target, propKey)target: 目标对象
propKey: 属性名(字符串或Symbol)
拦截 Object.getOwnPropertyDescriptor 的行为
getPrototypeOf(target)target: 目标对象拦截 Object.getPrototypeOf 的行为
setPrototypeOf(target, proto)target: 目标对象
proto: 新的原型对象
拦截 Object.setPrototypeOf 的行为
isExtensible(target)target: 目标对象拦截 Object.isExtensible 的行为
preventExtensions(target)target: 目标对象拦截 Object.preventExtensions 的行为
ownKeys(target)target: 目标对象拦截 Object.keys、Object.getOwnPropertyNames、Object.getOwnPropertySymbols 以及 for…in 循环的行为
apply(target, thisArg, argumentsList)target: 目标函数
thisArg: 函数调用时使用的 this 值
argumentsList: 函数的参数数组
拦截函数调用或 Function.prototype.apply 调用
construct(target, argumentsList, newTarget)target: 目标构造函数
argumentsList: 构造函数的参数数组
newTarget: 最初被 new 操作符调用的构造函数
拦截 new 操作符的行为
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值