blog
blog copied to clipboard
📒 Yang's Notes & Blog
## 概念 函数节流和函数防抖,两者都是优化高频率执行 JS 代码的一种手段。 - **函数防抖**:是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。 比如生活中的坐公交,一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。 - **函数节流**:是指一定时间内 JS 方法只跑一次。 比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释。 ## 函数防抖 debounce 函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后(或者停止输入后),前端才需要去触发查询的请求,如果不正确,再弹出提示语。以下还是以页面元素滚动监听的例子,来进行解析: **函数防抖就是让某个函数在上一次执行后,满足等待某个时间内不再触发此函数后再执行,而在这个等待时间内再次触发此函数,等待时间会重新计算**。 ```js // 函数防抖 var timer = false; document.getElementById("debounce").onscroll = function (){ clearTimeout(timer);...
最近在做一个基于Vue的项目,顺便把文档的东西都拿出来复习一下。 在实现某个细节的时候,需要兄弟组件之间通信,问题就来了,如何传递信息呢? 在没去翻文档的情况下,自己取巧想了一个解决方案: 1. 子组件A `$emit` 触发具体事件,由父组件 `@` 监听得到数据 2. 父组件再利用 `$refs` 直接访问子组件B的方法,间接实现数据从子组件A传递至子组件B 这样的方式虽然实现了兄弟组件的通信,但只能是在简单的场景下,随着组件增多,嵌套复杂,这样的方式实在是不够优雅。 随后去认真翻了Vue文档,提到了**解决兄弟组件通信的方式—— Event Bus**。 简单来说就是使用一个空的Vue实例作为事件总线 ``` // bus.js export default new Vue(); ``` 在组件A中引入bus.js,监听事件 ``` // component...
> 是时候来一波总结了,之前的文章也有提到,虽然不全面,但如果你是 JS rookie,建议先看那篇再回来:[深入理解 JS 的坑和细节](https://n-y.io/understand-js-part1/) 的 单线程和异步机制 > 本文重头戏在后半部分的 `macrotask` & `microtask` ### 那让我们开始吧! 首先,我们要有一个共同的认知:`Javascript` 是一门单线程语言,尽管 HTML5 标准中提出了 Web-Worker,但本质上 JS 是单线程这一核心仍未改变。 ## JavaScript 事件循环 任务可以分成两种,一种是`同步任务(synchronous)`,另一种是`异步任务(asynchronous)`。 - 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务; - 异步任务指的是,不进入主线程、而进入"任务队列"(task...
# Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 [devtools extension](https://github.com/vuejs/vue-devtools),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。 # 什么是“状态管理模式”? 状态自管理应用包含以下几个部分: - state,驱动应用的数据源; - view,以声明方式将 state 映射到视图; - actions,响应在 view 上的用户输入导致的状态变化。 “单向数据流”理念的极简示意:  但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:...
> 本文是作者学习 Vue 官方文档,根据自身总结的知识点笔记,更全面的文档请见官方: # Vue 实例 #### 1. 每个 Vue 应用都是通过 Vue函数创建一个新的Vue实例 开始的 #### 2. 生命周期钩子函数的 this 指向 Vue实例 ,所以不要用 `()=>{}` #### 3. 生命周期 # 模板语法 ### 插值 1....
### 排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。 用一张图概括:  ### 关于时间复杂度: 1. 平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。 2. 线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序; 3. O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序 4. 线性阶 (O(n)) 排序...
## JS设计模式 **常见** 设计模式有 1. 构造函数模式 constructor 2. 工厂模式 factory 2. 混合模式 mixin 3. 模块模式 module 4. 单例模式 singleton 5. 订阅发布模式 subscibe & pulish 6. 观察者模式 observer ## 构造函数模式 constructor...
### 更全面的理解请看新写的:[全面认知 JavaScript 执行机制](https://n-y.io/event-loop/) ## 开始 随着对JavaScript学习的深入和实践经验的积累,一些原理和底层的东西也开始逐渐了解。早先也看过一些关于js单线程和事件循环的文章,只留了一个大概的印象:浏览器中的js程序时是单线程的。当时也有些疑问:既然是单线程的,那异步调用是怎么实现的?计时器是靠谁来计时的,这单线程总不能一边执行程序一边计时吧?那些耗时的I/O操作为啥没把线程阻塞,不是说好的单线程么?相信很多不了解JavaScript单线程的同学也有过类似的疑问。 最近看了些相关的资料,就简单地总结一下,希望能帮到大家,同时自己也梳理一下知识点。 ## 一、JavaScript单线程 在浏览器的一个页面中,该页面的JS程序只有一个线程,故曰单线程。因为是单线程,所以程序的执行顺序就是从上到下依次执行,同一时间内只能有一段代码被执行。那为什么不用多线程,这样不是更能充分利用CPU,提高效率么? 早期的网页内容非常简单,单线程足以应付,所以在设计之初,我估计设计者就没考虑使用多线程。另外,JavaScript主要用来处理用户与页面产生的交互,以及操作DOM;如果以多线程的方式来操作DOM,一个线程要求删除该DOM,另一个要求修改DOM样式,那么浏览器该听谁的?这大大增加了程序设计的复杂度,本来前端都不好学,不是么~~~简简单单多好。 虽然JavaScript是单线程的,**可是浏览器内部不是单线程的**。你的一些I/O操作、定时器的计时和事件监听(click, keydown…)等都是由浏览器提供的其他线程来完成的。 如果想利用多线程处理一些耗时较长的任务,可以使用HTML5提出的Web Worker。 ## 二、任务队列和事件循环 提到异步机制,不得不说到任务队列和事件循环,这里理解JS异步机制的要点。 首先理解浏览器的并发模型,来看下面这个图:  左边的栈存储的是同步任务,所谓同步的任务就是那些能立即执行、不耗时的任务,如变量和函数的初始化、事件的绑定等等那些不需要回调函数的操作都可归为这一类。右边的堆用来存储声明的变量、对象。下面的队列就是**任务队列**,一旦某个异步任务有了响应就会被推入队列中。如用户的点击事件、浏览器收到服务的响应和后面提到的setTimeout插入的事件。每个异步任务都和一个回调函数相关联。 一个js程序的单线程用来执行栈中的同步任务,**当所有同步任务执行完毕后**,栈被清空,然后读取任务队列中的一个待处理任务,并把相关回调函数压入栈中,单线程开始执行新的同步任务,执行完毕。 单线程从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有新的任务,就会等待,直到有新的任务,这就叫任务循环。因为每个任务都由一个事件所触发,所以也叫**事件循环**。 ## 三、异步机制 有了上面两节做铺垫,理解异步机制就容易多了。拿ajax来说,当页面的单线程执行xhr.send()之后,对于页面来说发送任务已经完成了。怎么发送,那是浏览器的事,和单线程无关;什么时候响应,这事说不准。为了及时地得到响应的内容,在单线程中注册相应的事件就好xhr.onreadystatechange = fn() {...}。注册之后,浏览器会在内部的其他线程中自动地帮我们监听该事件。直到该事件被触发,浏览器会在任务队列中添加一个任务等待该单线程执行。...
## JavaScript 对象 因为JavaScript是基于原型(prototype)的,没有类的概念(ES6有了,这个暂且不谈),我们能接触到的都是对象,真正做到了一切皆为对象 ## Object 我们知道JavaScript有null、undefined、number、boolean、string五种简单类型,null和undefined分别表示没有声明和声明后没有初始化的变量、对象,是两个简单的值,其余三个有对应的包装对象Number、Boolean、String 其它的就都是object类型了,比如常用的Array、Date、RegExp等,我们最常用的Function也是个对象,虽然 ```javascript typeof function(){}; // "function" ``` 但是Function实例和其它类型的实例没有什么区别,都是对象,只不过typeof操作符对其做了特殊处理 在JavaScript中使用对象很简单,使用**new操作符执行Obejct函数**就可以构建一个最基本的对象 ```javascript var obj = new Object(); ``` 我们称new 调用的函数为构造函数,构造函数和普通函数区别仅仅在于是否使用了new来调用,它们的返回值也会不同 所谓“构造函数”,就是专门用来生成“对象”的函数。它提供模板,作为对象的基本结构。一个构造函数,可以生成多个对象,这些对象都有相同的结构 我们可以通过.来为对象添加属性和方法 ```javascript //1.原始模式,Object构造函数方式 obj.name...
## 检测数据类型的4种方案 在 ECMAScript 规范中,共定义了 7 种数据类型,分为 基本类型 和 引用类型 两大类,如下所示: - **基本类型**:String、Number、Boolean、Symbol、Undefined、Null - **引用类型**:Object 基本类型也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈中,即按值访问。 引用类型也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆(heap)中,而存储在变量处的值,是一个指针,指向存储对象的内存处,即按址访问。引用类型除 Object 外,还包括 Function 、Array、RegExp、Date 等等。 鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型,对于这个问题,JavaScript 也提供了多种技术方案,但遗憾的是,不同的方案得到的结果也参差不齐。 下面介绍常用的 4 种方案,并对各个方案存在的问题进行简单的分析。 ##...