Logan
Logan
# 如何处理循环的异步操作 > 示例代码中tasks为异步操作队列,代码忽略任务执行结果的记录和错误处理 ## 并行异步操作 ### Promise.all ```js Promise.all(tasks.map(task => task())) .then(() => doSomethingAfter()) // 也可结合 async/await使用 ;(async () => { await Promise.all(tasks.map(task => task())) doSomethingAfter() })() ``` ###...
# 堆栈溢出和内存泄漏的原理及防范 ## 堆栈溢出 ### 产生原因 - **上溢**:栈满时再做进栈必定产生空间溢出 - **下溢**:栈空时再做退栈也产生空间溢出 最常见的就是**无限递归**或**递归层级过深**,导致调用栈空间不足,从而导致栈上溢。 ```js // 阶乘,若用递归实现,层级不能过深 const factorial = n => n n { let result = 1 while (n > 1)...
# 闭包的实现原理和作用 ## 闭包是什么 MDN对闭包描述如下: > A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). 闭包是**函数**和**创建函数的环境**的组合。 由 [标准](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-functioninitialize) 可知,JavaScript中函数被创建时都会记录当前词法环境,所以说JavaScript中,每次创建函数,都会生成闭包。...
# this的原理以及几种不同使用场景的取值 ## 了解函数 在具体谈论this取值的各种情况前,我们先来看看一个函数从创建到执行的过程中对我们了解`this`有帮助的一些规范信息。 ### 函数的this模式 在**函数创建阶段**会标记该函数的this模式,有以下三种模式,由上往下进行判定,详见 [ECMAScript#FunctionInitialize](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-functioninitialize): 1. **lexical** :箭头函数的this模式标记为 `lexical`; 2. **strict** :严格模式下函数的this模式标记为 `strict`; 3. **global** :其他情况的函数的this模式标记为 `global`。 ### 函数的执行 无论函数通过何种方式调用,最终JS引擎都会通过函数对象内部的 `[[Call]] ( thisArgument, argumentsList )` 方法来调用函数并执行。第一个参数为指定this的值,不传则为`undefined`,第二个参数为函数被调用时的参数列表,详见...
# JavaScript的执行上下文栈 ## 执行上下文(Exexution Contexts) JavaScript可执行代码有以下四种类型,每个类型的代码均在其自己的执行上下文内运行: > 模块代码 和 eval代码 在本文中不作讨论 - 全局代码 - 函数代码 - 模块代码(即`ES Module`,平常用的`import`、`export`即属于此类型的关键字) - eval代码 **执行上下文** 是一个描述代码运行时所在环境的抽象概念。 JS引擎再开始执行代码前,会创建 **全局执行上下文** ,全局代码(不属于任何函数的代码)在全局执行上下文中执行。 **全局执行上下文** 在每个JS程序中只有一个。 当执行全局代码时,可能会碰到函数调用,这时JS引擎会创建 **函数执行上下文** 并执行函数代码,也就是说在一个执行上下文中可以创建另一个执行上下文。函数中再调用函数或函数中调用自身也是如此。这些执行上下文就构成了...
> **原文**: [《JavaScript Visualized: Event Loop》 - By Lydia Hallie](https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif)\ > 本文主要通过生动形象的动图讲解事件循环的一些基本概念,主要面向初学者,译者已取得原作者的同意。本文一些部分采用意译,以帮助大家更好地理解。\ > \ > 本文首发于个人博客 [Logan's Blog](https://github.com/logan70/Blog),其他JS相关内容也可前往小弟博客共同学习探讨。 **事件循环(Event Loop)**,是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑。我是一个视觉型学习者,所以打算通过gif动图的可视化形式帮助大家理解它。 首先我们来看看,什么是事件循环,我们为什么要了解它呢? 众所周知,JavaScript是 **单线程(single-threaded)** 的,也就是同一时间只能运行一个任务。一般情况下这并没有什么问题,但是假如我们要运行一个耗时30秒的任务,我们就得等待30秒后才能执行下一个任务(这30秒期间,JavaScript占用了主线程,我们什么都不能做,包括页面也是卡死状态)。这都9012年了,不带这么坑爹的吧? 好在浏览器向我们提供了JS引擎不具备的特性:`Web API`。`Web API`包括`DOM API`、`定时器`、`HTTP请求`等特性,可以帮助我们实现**异步、非阻塞**的行为。 当我们调用一个函数时,函数会被放入一个叫做**调用栈**(call stack,也叫执行上下文栈)的地方。调用栈是JS引擎的一部分,并非浏览器特有的。调用栈是一个*栈数据结构*,具有*后进先出*的特点(Last...
# JavaScript的作用域和作用域链 ES6之后作用域概念变为**词法环境**概念,标准定义详见 [ECMAScript#Lexical Environment](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-lexical-environments) ## 词法环境(Lexical Environment) 词法环境由以下两部分组成: - **环境记录(Environment Record)**:记录相应代码块的标识符绑定,可理解为代码块内变量、函数等都绑定于此; - **对外部词法环境的引用(outer)**:用于形成多个词法环境在逻辑上的嵌套结构,以实现可以访问外部词法环境变量的能力。 ## 作用域链 上一点所有的词法环境中的 **对外部词法环境的引用(outer)**,可以实现内部词法环境访问外部词法环境,从而实现了一个嵌套结构,即所说的 **作用域链**。 词法环境在ECMAScript定义中,也是构成 [执行上下文](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-execution-contexts) 的一部分。众所周知执行上下文在函数执行时才会创建,那么为什么又说JS的作用域是静态作用域呢,下面一起来看一下: 1. JS在定义函数时不仅会记录函数代码、形参等信息,还会将函数被定义时所处的词法环境记录下来; > 此处可参考 [ECMAScript#functioninitialize](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-functioninitialize) 2. 执行函数时创建执行上下文、创建词法环境(包括环境记录和外部引用),并将外部引用指向第一点中记录的函数被定义时所处的词法环境。 >...
# 词法作用域和动态作用域 ## 什么是作用域 作用域是指程序源代码中定义变量的区域,规定了如何查找变量,也就是确定了当前执行代码对变量的访问权限。 ## 词法作用域 **词法作用域** 也叫静态作用域,即变量的作用范围在代码编写时就已确定,`JavaScript`使用词法作用域。 通过下面`JavaScript`代码例子来理解词法作用域(引自 [冴羽的博客](https://github.com/mqyqingfeng/Blog/issues/3) ): ```js const scope = 'global scope' function checkscope1(){ const scope = 'local scope 1' function f(){ return scope...
# ES6 Class的底层实现原理 > ES6 中的类`Class`,仅仅只是基于现有的原型继承的一种语法糖,我们一起来看一下`Class`的底层实现原理。 ## Class的底层实现要素 1. 只能使用new操作符调用`Class`; 2. `Class`可定义实例属性方法和静态属性方法; 3. 子`Class`的实例可继承父`Class`上的实例属性方法、子`Class`可继承父`Class`上的静态属性方法。 ### 只能使用new操作符调用`Class` **实现思路**:使用`instanceof`操作符检测实例是否为指定类的实例。 ```js function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot...
# new的详细过程及其模拟实现 ## `new`一个对象的详细过程 1. 创建一个全新对象,并将该对象原型指向构造函数的原型对象; 2. 将构造函数调用的this指向这个新对象,并执行构造函数; 3. 如果构造函数执行结果为对象类型(包含Object,Functoin, Array, Date, RegExg, Error等),则返回执行结果,否则返回创建的新对象。 ## 模拟实现`new` ```js function newOperator(Ctor, ...args) { if (typeof Ctor !== 'function') { throw new TypeError('First...