Logan
Logan
# 实现数组方法(下) 所有数组方法的实现均忽略参数校验、边界条件判断,主要关注核心逻辑的实现。 部分数组方法会基于`Array.prototype.reduce`方法来实现,关于`reduce`方法的讲解及实现详见[彻底搞懂数组reduce方法](https://github.com/logan70/Blog/issues/40) ## Array.prototype.push() [MDN - Array.prototype.push()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/push) `push()`方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。 `push()`方法可用于类数组对象,需要注意的是length不存在或无法转为数值时,将被设置为0,并从索引0开始添加元素。 ```js Array.prototype._push = function(...args) { const len = Number(this.length) || 0 this.length = len for (arg of args) {...
# 实现数组方法(上) 所有数组方法的实现均忽略参数校验、边界条件判断,主要关注核心逻辑的实现。 部分数组方法会基于`Array.prototype.reduce`方法来实现,关于`reduce`方法的讲解及实现详见[彻底搞懂数组reduce方法](https://github.com/logan70/Blog/issues/40) ## Array.prototype.concat() [MDN - Array.prototype.concat()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) `concat()` 方法用于合并两个或多个数组。此方法**不会更改现有数组,而是返回一个新数组。** ```js Array.prototype._concat = function(...arrs) { return arrs.reduce((newArr, cur) => { return Array.isArray(cur) ? [...newArr, ...cur] // 传入项为数组则展开后合并 : [...newArr,...
# 理解ECMAScript和JavaScript的关系 ## ECMA ECMA国际(Ecma International)是一家国际性会员制度的信息和电信标准组织。1994年之前,名为欧洲计算机制造商协会(European Computer Manufacturers Association)。因为计算机的国际化,组织的标准牵涉到很多其他国家,因此组织决定改名表明其国际性。现名称已不属于首字母缩略字。 ECMA国际负责了很多标准的制定: - CD-ROM格式(之后被国际标准化组织批准为ISO 9660) - C#语言规范 - C++/CLI语言规范 - 通用语言架构(CLI) - ECMAScript语言规范(JavaScript) - Eiffel语言 - 电子产品环境化设计要素 - Universal 3D标准 - OOXML...
# 如何在保证页面运行流畅的情况下处理海量数据 ## 如何保证流畅 从用户的输入,再到显示器在视觉上给用户的输出,这一过程如果超过100ms,那么用户会察觉到网页的卡顿。 由于JS是单线程的,并且JS线程和UI渲染线程是互斥的,所以保证页面流畅的关键在于**避免长耗时任务阻塞主线程**。 W3C性能工作组在 [LongTask规范](https://developer.mozilla.org/zh-CN/docs/Web/API/Long_Tasks_API) 中也将超过50ms的任务定义为长任务。50ms这个阈值标准来源于 [《RAIL Model》](https://developers.google.com/web/fundamentals/performance/rail#response)。 避免长任务的一种方案是使用Web Worker,将长任务放在Worker线程中执行,缺点是无法访问DOM,另一种方案就是下面要讲的**时间切片**。 ## 时间切片及基础实现 时间切片是一种概念,也可以理解为一种技术方案,核心思想是:如果任务不能在规定时间内执行完,那么为了不阻塞主线程,这个任务应该让出主线程的控制权。 我们可以利用Generator 函数可以暂停执行和恢复执行的特性来实现时间切片。 ```js // 任务列表 const tasks = [ () => 'task1', () =>...
# Node与浏览器Event Loop的差异 ## Node.js 运行机制  `Node.js`采用V8作为JS的解析引擎,而I/O处理方面使用了自己设计的libuv,libuv是一个基于事件驱动的跨平台抽象层,封装了不同操作系统一些底层特性,对外提供统一的API,`Node.js`内的事件循环机制也由其实现。 Node.js运行机制简化如下: 1. V8引擎将JavaScript代码解析为机器码。 2. 解析后的代码,调用Node API。 3. libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。 4. V8引擎再将结果返回给用户。 ## Node.js 事件循环 `Node.js`内的事件循环机制由`libuv`实现,分6个阶段反复进行。 ``` ┌───────────────────────────┐ ┌─>│ timers │ │...
# 复杂异步嵌套逻辑分析 ## Async/Await 在事件循环中的表现 在分析之前,有必要了解一下`Async/Await`在事件循环中的表现,先看如下代码。 ```js async function async1() { console.log('a') await async2() console.log('b') } async function async2() { console.log('c') } async1() new Promise((resolve) => { console.log('d') resolve() }).then(()...
# 宏任务和微任务分别有哪些 ## 为何区分宏任务和微任务 ### 确保一致的执行顺序 假设有以下代码,对请求结果作缓存: ```js let data function getData() { if (data) { console.log('loaded data') } else { ajax().then(data => { console.log('loaded data') }) } } ```...
# JavaScript异步编程及Event Loop ## 异步编程 ### 为何需要异步编程 JavaScript是单线程语言,也就是说同一时间只能运行一个任务。一般来说这没什么问题,但是如果运行耗时过长的任务,将会阻塞后续任务的执行,包括UI渲染。 所以一些非密集计算的任务,比如文件I/O,HTTP Request,定时器等任务,完全没必要在主线程等待其完成,而是应该在创建任务后交出主线程控制权,去执行其他任务,待其完成后再处理。这就引出了**异步编程**。 需要注意的是,ECMAScript(JavsScript的语言规范)并没有定义这些异步特性,所以异步特性的实现都需要依赖于JavaScript运行环境,例如浏览器、Node等。 ### 如何实现异步编程 浏览器提供了JS引擎不具备的特性,我们称之为`Web API`,例如我们常见的DOM事件监听、Ajax、定时器等。通过这些特性可以实现**异步、非阻塞**的行为。其执行机制会在下个部分 [Event Loop](#event-loop) 中详细讲解。 ### 异步编程语法 JavaScript发展至今,异步编程语法主要有以下几种: - 回调函数Callback - Promise - Generator - Async /...
# try-catch-finally执行机制 > [ECMA标准定义](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-try-statement-runtime-semantics-evaluation) ## 执行过程 1. 执行 `try` 中代码,将执行结果标记为`Result`; 2. 若 `try` 中执行代码报错,则执行 `catch` 中代码,并用执行结果更新 `Result`; 3. 执行 `finally` 中代码,若有返回值,则用返回值更新 `Result`,完成执行过程。 ## 主要有以下几个**坑点**要注意避免: - `try` 和 `catch` 中的`return`语句不影响 `finally`中代码的执行...
# 了解模块化及其典型方案 ## 模块化解决的问题 - **命名空间污染**:如果变量都挂载在全局对象上,容易命名冲突,变量覆盖,也就是我们常说的“全局变量污染”; - **维护性差**:模块化将各部分功能分割开来,高内聚低耦合,提升代码的可维护性,降低维护成本; - **复用性差**:没有模块化时,复用全靠复制粘贴,模块化后,需要时只需引入相应依赖即可,一处定义、多处使用。 ## 各模块化方案 ### ES Module ES Module是ES6提出的模块化标准,属于**编译时加载**(静态加载),只能存在于顶层作用域。 > 动态import已通过提案,列入最新 [ECMA标准](https://tc39.es/ecma262/#sec-hostresolveimportedmodule) 中。 ```js /* ----- Export Syntax ---------- */ // default...