《前端面试手记》之ES6重难点整理

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

? 内容速览 ?

  • let和const
  • Set和Map
  • Generator和yield
  • Promise、async/await介绍
  • Proxy代理器

关注微信公众号 「心谭博客」,前往 「xin-tan.com
专注前端与算法的系列干货分享,欢迎关注(¬‿¬)

let和const

ES6新增了letconst,它们声明的变量,都处于“块级作用域”。并且不存在“变量提升”,不允许重复声明。

同时,const声明的变量所指向的内存地址保存的数据不得改变:

  • 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
  • 对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),不能保证指向的数据结构不可变。

如果要保证指向的数据结构也不可变,需要自行封装:

/**
 * 冻结对象
 * @param {Object} obj 
 * @return {Object}
 */
function constantize(obj) {
  if(Object.isFrozen(obj)) {
    return obj
  }

  Reflect.ownKeys(obj).forEach(key => {
    // 如果属性是对象,递归冻结
    typeof obj[key] === 'object' && (obj[key] = constantize(obj[key]))
  });

  return Object.freeze(obj)
}

/********测试代码 **********/

const obj = {
  a: 1,
  b: {
    c: 2,
    d: {
      a: 1
    }
  },
  d: [
    1,
    2
  ]
}

const fronzenObj = constantize(obj)
try {
  fronzenObj.d = []
  fronzenObj.b.c = 3
} catch(error) {
  console.log(error.message)
}

Set和Map

题目:解释下SetMap

  • Set元素不允许重复
  • Map类似对象,但是它的键(key)可以是任意数据类型

①Set常用方法

// 实例化一个set
const set = new Set([1, 2, 3, 4]);

// 遍历set
for (let item of set) {
  console.log(item);
}

// 添加元素,返回Set本身
set.add(5).add(6);

// Set大小
console.log(set.size);

// 检查元素存在
console.log(set.has(0));

// 删除指定元素,返回bool
let success = set.delete(1);
console.log(success);

set.clear();

其他遍历方法:由于没有键名,values()keys()返回同样结果。

for (let item of set.keys()) {
  console.log(item);
}

for (let item of set.values()) {
  console.log(item);
}

for (let item of set.entries()) {
  console.log(item);
}

②Map常用方法

Map接口基本和Set一致。不同的是增加新元素的API是:set(key, value)

const map = new Map();

// 以任意对象为 Key 值
// 这里以 Date 对象为例
let key = new Date(); 
map.set(key, "today");

console.log(map.get(key));

Generator与yield

generator函数是es6提供的新特性,它的最大特点是:控制函数的执行。让我们从网上最火的一个例子来看:

function* foo(x) {
  var y = 2 * (yield x + 1);
  var z = yield y / 3;
  return x + y + z;
}

var b = foo(5);
b.next(); // { value:6, done:false }
b.next(12); // { value:8, done:false }
b.next(13); // { value:42, done:true }

通俗的解释下为什么会有这种输出:

  1. 给函数foo传入参数5,但由于它是generator,所以执行到第一个yield前就停止了。
  2. 第一次调用next(),这次传入的参数会被忽略暂停**。
  3. 第二次调用next(12),传入的参数会被当作上一个yield表达式的返回值。因此,y = 2 * 12 = 24。执行到第二个yield,返回其后的表达式的值 24 / 3 = 8。然后函数在此处暂停。
  4. 第三次调用next(13),没有yield,只剩return了,按照正常函数那样返回return的表达式的值,并且donetrue

难点:在于为什么最后的value是42呢?

首先,x的值是刚开始调用foo函数传入的5。而最后传入的13被当作第二个yield的返回值,所以z的值是13。对于y的值,我们在前面第三步中已经计算出来了,就是24。

所以,x + y + z = 5 + 24 + 13 = 42

看懂了上面的分析,再看下面这段代码就很好理解了:

function* foo(x) {
  var y = 2 * (yield x + 1);
  var z = yield y / 3;
  return x + y + z;
}

var a = foo(5);
a.next(); // Object{value:6, done:false}
a.next(); // Object{value:NaN, done:false}
a.next(); // Object{value:NaN, done:true}

只有第一次调用next函数的时候,输出的value是6。其他时候由于没有给next传入参数,因此yield的返回值都是undefined,进行运算后自然是NaN

Promise介绍

简单归纳下 Promise:三个状态、两个过程、一个方法

  • 三个状态:pendingfulfilledrejected
  • 两个过程(单向不可逆):
    • pending->fulfilled
    • pending->rejected
  • 一个方法thenPromise本质上只有一个方法,catchall方法都是基于then方法实现的。

请看下面这段代码:

// 构造 Promise 时候, 内部函数立即执行
new Promise((resolve, reject) => {
  console.log("new Promise");
  resolve("success");
});
console.log("finifsh");

//  then 中 使用了 return,那么 return 的值会被 Promise.resolve() 包装
Promise.resolve(1)
  .then(res => {
    console.log(res); // => 1
    return 2; // 包装成 Promise.resolve(2)
  })
  .then(res => {
    console.log(res); // => 2
  });

async/await介绍

async函数返回一个Promise对象,可以使用then方法添加回调函数。

当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

这也是它最受欢迎的地方:能让异步代码写起来像同步代码,并且方便控制顺序

可以利用它实现一个sleep函数阻塞进程:

function sleep(millisecond) {
  return new Promise(resolve => {
    setTimeout(() => resolve, millisecond)
  })
}

/**
 * 以下是测试代码
 */
async function test() {
  console.log('start')
  await sleep(1000) // 睡眠1秒
  console.log('end')
}

test() // 执行测试函数

虽然方便,但是它也不能取代Promise,尤其是我们可以很方便地用Promise.all()来实现并发,而async/await只能实现串行。

function sleep(second) {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(Math.random());
      resolve();
    }, second);
  });
}

async function chuanXingDemo() {
  await sleep(1000);
  await sleep(1000);
  await sleep(1000);
}


async function bingXingDemo() {
  var tasks = [];
  for (let i = 0; i < 3; ++i) {
    tasks.push(sleep(1000));
  }

  await Promise.all(tasks);
}

运行bingXingDemo(),几乎同时输出,它是并发执行;运行chuanXingDemo(),每个输出间隔1s,它是串行执行。

ES6对象和ES5对象

题目:es6 class 的new实例和es5的new实例有什么区别?

ES6中(和ES5相比),classnew实例有以下特点:

  • class的构造参数必须是new来调用,不可以将其作为普通函数执行
  • es6class不存在变量提升
  • 最重要的是:es6内部方法不可以枚举。es5的prototype上的方法可以枚举。

为此我做了以下测试代码进行验证:

console.log(ES5Class()) // es5:可以直接作为函数运行
// console.log(new ES6Class()) // 会报错:不存在变量提升

function ES5Class(){
  console.log("hello")
}

ES5Class.prototype.func = function(){ console.log("Hello world") }

class ES6Class{
  constructor(){}
  func(){
    console.log("Hello world")
  }
}

let es5 = new ES5Class()
let es6 = new ES6Class()

// 推荐在循环对象属性的时候,使用for...in
// 在遍历数组的时候的时候,使用for...of
console.log("ES5 :")
for(let _ in es5){
  console.log(_)
}

// es6:不可枚举
console.log("ES6 :")
for(let _ in es6){
  console.log(_)
}

参考/推荐《JavaScript创建对象—从es5到es6》

Proxy代理器

他可以实现js中的“元编程”:在目标对象之前架设拦截,可以过滤和修改外部的访问。

它支持多达13种拦截操作,例如下面代码展示的setget方法,分别可以在设置对象属性和访问对象属性时候进行拦截。

const handler = {
  // receiver 指向 proxy 实例
  get(target, property, receiver) {
    console.log(`GET: target is ${target}, property is ${property}`)
    return Reflect.get(target, property, receiver)
  },
  set(target, property, value, receiver) {
    console.log(`SET: target is ${target}, property is ${property}`)
    return Reflect.set(target, property, value)
  }
}

const obj = { a: 1 , b: {c: 0, d: {e: -1}}}
const newObj = new Proxy(obj, handler)

/**
 * 以下是测试代码
 */

newObj.a // output: GET...
newObj.b.c // output: GET...

newObj.a = 123 // output: SET...
newObj.b.c = -1 // output: GET...

运行这段代码,会发现最后一行的输出是 GET ...。也就是说它触发的是get拦截器,而不是期望的set拦截器。这是因为对于对象的深层属性,需要专门对其设置Proxy

更多请见《阮一峰ES6入门:Proxy》

EsModule和CommonJS的比较

目前js社区有4种模块管理规范:AMD、CMD、CommonJS和EsModule。 ES Module 是原生实现的模块化方案,与 CommonJS 有以下几个区别:

  • CommonJS 支持动态导入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案:import(xxx)
  • CommonJS 是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响
  • commonJs输出的是值的浅拷贝,esModule输出值的引用
  • ES Module 会编译成 require/exports 来执行的

更多系列文章

⭐在GitHub上收藏/订阅⭐

专注前端与算法的系列干货分享,欢迎关注(¬‿¬)

Retinanet训练自己的数据(2):模型准备   在上一篇博客中,我们已经处理好了模型需要的数据集,下一步就是准备模型去训练数据。这里提醒一句,在制作数据时,最好将训练集和测试集人为分开。像Google tensorflow API,在制作数据时可以按比例自动生成,但是在上一篇文章中产生的数据(annotation.csv )其实都是用来训练的,如果你把自己的数据集全都转换了,那么恭喜你,最后你会发现没有数据集去测试了。   下面开始模型准... 阅读详情

相关推荐

基于EtherCAT的AM402与SV660N、IS620N伺服运动控制实战指南

本文详细介绍了基于EtherCAT总线的汇川AM402 PLC与SV660N、IS620N伺服驱动器构建运动控制系统的完整实战流程。内容涵盖硬件平台搭建、软件组态、关键参数设置、InoProShop编程及调试技巧,旨在帮助工程师快速掌握这一高精度、高响应的工业自动化解决方案。

weixin_29204205的博客 371

async与await 写法详解

async 与 await 可以使异步代码写法更加简洁,是在es2017引入的新特性,在最新版的nodejs及Chrome中都已经支持。 async 函数 const fetch = require('node-fetch'); // function getZhihuColumn(id) { // const url = `https://zhuanlan.zhihu.com/api/columns/${id}`; // fetch(url) // .then(re

Jack, what else can you do besides holding your little darling? 1250

ADS124S08配置避坑指南:从SPI时序到寄存器设置,手把手教你调通24位ADC

本文详细解析了ADS124S08 24位ADC的SPI时序配置、寄存器设置及外围电路设计中的关键细节,帮助工程师避开常见陷阱。从SPI通信模式选择到DRDY引脚读取优化,再到基准电压启动时间调整,提供了实战验证的解决方案,确保高精度数据采集的稳定性。

weixin_29192365的博客 258

js中await用法

将返回被解决的值,否则它将抛出一个被拒绝的。时需要在一个异步函数中使用,否则会报错。对象都解决后,再返回结果。在JavaScript中,用于暂停异步函数执行,等待。数据,最后打印结果。需要注意的是,在使用。

weixin_59525879的博客 5384

JS关键字export default,export const,async,await

JS关键字

m0_55321004的博客 3190

JavaScript】async & await 解决了那些问题

async/await更加优雅的异步编程的写法。

day day up 3329

async和await

async和await 1.async基本用法 async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。 例如:① async function myFunc(){ return "Hello World!"; } console.log(myFunc()); 控制台...

weixin_46314560的博客 219

异步解决方案----Promise与Await

前言 异步编程模式在前端开发过程中,显得越来越重要。从最开始的XHR到封装后的Ajax都在试图解决异步编程过程中的问题。随着ES6新标准的到来,处理异步数据流又有了新的方案。我们都知道,在传统的ajax请求中,当异步请求之间的数据存在依赖关系的时候,就可能产生很难看的多层回调,俗称'回调地狱'(callback hell),这却让人望而生畏,Promise的出现让我们告别回调函数,写出更优雅的异步...

weixin_33809981的博客 388

JavaScript ES6特性

从 let 和 const 到 async/await,这些新特性不仅提升了代码的可读性,还极大地简化了常见的编程任务。随着 ECMAScript 2015 (ES6) 及其后续版本的发布,JavaScript 语言引入了许多新特性,使得编写代码变得更加简洁、高效和易于维护。// 输出 [1, 2, 3, 4, 5, 6]console.log(greet());// 输出 1 2 3。

weixin_43717498的博客 432

浅析Javascript——async/await

一、async 带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。 async function test() { return 'test' } test(); 返回值为Promise {<resolved>: "test"}。 二、await await等待右侧表达式的结果,这个结果是promise对象或者其他值。 如果它等到的不是一个 promise .

全栈-菜鸟 337

Promise && async/await的理解和用法

Promise && async/await的理解和用法 为什么需要promise(承诺)这个东西 在之前我们处理异步函数都是用回调这个方法,回调嵌套的时候会发现 阅读性 和 调试 的难度会增加很多; 怎么理解promise 想象一下,你把一个任务交给一个不错的小伙子,他叫承诺;不用担心你交给他的任务会丢失,他总会返回的,...

weixin_34354945的博客 180

await

function sleep(ms) { return new Promise((resolve) =&gt; { $.ajax({ url:"http://crawlerapi.buji.net.cn/api/Crawler/projects?pageIndex=1&amp;pageSize=10", async:true,...

Oh_My_Godjun的博客 826

JS中的async/await的用法和理解

1、首先需要理解async 和 await的基本含义 async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作,返回的值即为then方法的传入函数 // 0. async基础用法测试 async function fun0() { console.log(1) return 1 } fun0().then( x => { console.log(x) }) // 输出结果 1,..

刘泽海的博客 2万+

ES6总结()

4.注意promiss的then在执行后才会放到为任务队列里。3.不能argument 能rest(...)底层运用,generator+promise。1.let ,var ,const 区别。1.基本使用为什么使用(解决回调地狱)3.解构赋值和argument。5.async 和 await。2.promiss缺点。4.const 不能改。1.this指向问题。3.all和race。解决异步回调顺序问题。

m0_52289188的博客 153

前端:你不知道的async await

你是否知道async是什么?作用是什么?await是什么执行逻辑是怎样的?await下面的代码是什么样的执行顺序?

接着奏乐接着舞的博客 5752

深入理解ES6新特性之Set结构

深入理解ES6新特性之Set结构

道阻且长 536

ES6新特性let/var/const 箭头函数 解构 promise generator async/await等详解

let 与var const的区别 let不存在变量提升 变量提升(原生js的语法):在最上面定义变量,但是没有赋值 相同的变量名不允许重复声明 块级作用域(ES5内只有全局作用域 函数作用域) 暂时性死区(也叫临时失效区),let声明的变量在当前函数内不允许同名的变量进来 const:声明一个只读的变量,一旦声明,常量的值就不能改变。 const实际上保证的,并不只是表面上的变量的值不得改动,而...

低眉的博客 1221

async和await_注意事项

async和await_注意事项

w_meng_zhao的博客 559

除了try catch优雅捕获await错误的方法

日常开发中相信大家或多或少会使用异步函数,那么异步函数应该如何优雅地捕获错误呢?如果跟我一样只会try catch的话就一起来学习一下的用法跟源码吧!

weixin_46669844的博客 774

Elasticsearch之es学习工作中遇到的坑(陆续更新)

        1:es集群脑裂问题(不要用外网ip,节点角色不要混用)   原因1:阿里云服务器,外网有时候不稳定。     解决方案:单独采购服务器,内网安装   原因2:master和node节点没有分开   解决方案:     分角色:master节点(三台),data节点(随着数据增加而增加),client(随着查询压力而增加)节点     Master节点:node...

weixin_33963594的博客 614

es 精确查找思路以及实现过程

先交代几个概念: 1. 题库 题库中保存了所有的题目数据。 2.es es 是 elasticsearch ,es 同步了题库中的所有题目。 3. 重题 两道题目内容完全一样的题,肉眼看起来是一样的。题目里有 latex 公式,不同的 latex 公式展示后看起来可能是一样的。 4. es 打分 es 会对匹配到的结果集进行打分,分值越高的结果越排在前面。 另外,还涉及到分词、倒排索引这两个概念,这是搜索引擎的基本原理。 5. 分词 一段文本在保存到倒排索引之前需要先分词,查询的时候都是按分词来匹配的。 英

5228
上一篇: JavaScript设计模式实践:18份笔记、例子和源码
下一篇: HTML5原生拖放事件的学习与实践
心谭
博客等级 码龄9年 140粉丝 143原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值