- 博客(23)
- 收藏
- 关注
原创 DFS算法经典题目: Leetcode 51.N皇后
题目详情如下这道题如果使用暴力解法的话,需要对N个皇后放在每个地方都进行枚举并判断是否可行,时间复杂度非常之高,肯定是过不了的,所以需要使用其他解法。根据题目可以知道每两个皇后之间的位置关系不能是在同一条直线或同一条斜线上。所以,每个皇后只能位于不同行不同列。每一行有且只有一个皇后,每一列有且只有一个皇后,且任何两个皇后不能位于一条斜线上,所以想到了DFS算法解决,主要思路即是回溯。
2024-10-18 10:24:13
476
原创 解析Vue源码中是如何进行模版编译的
它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说是抽象的,是因为这里的语法并不会表示出真实语法中出现的每个细节。联系前文,讲了虚拟DOM的patch过程,而虚拟DOM的前提是先有VNode,那么VNode又是从哪里来的?接下来讲的模版编译便是:把用户写的模版进行编译,就会产生VNode。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现;用户在template中写的模版对于Vue来说就是一堆字符串,那么如何解析这一堆字符串并且从中提取出元素的各个属性呢?
2024-10-08 19:30:10
605
原创 解析Vue2源码diff算法更新子节点逻辑以及优化
如果有两个子节点数组如下newChildren = ['新子节点1','新子节点2','新子节点3','新子节点4']oldChildren = ['旧子节点1','旧子节点2','旧子节点3','旧子节点4']根据之前的算法,我们接下来操作是这样的:外层循环new数组,用第一个节点去比较old所有节点,找到相同之后到下一个节点,用第二个节点去比对old所有节点…这样看来,其实损耗的时间复杂度是很多的。那么该如何优化呢?先把数组里的所有未处理子节点的第一个子节点和。
2024-09-26 19:21:17
1074
原创 解析Vue2源码中的diff算法
如果新的没有的节点而旧的有的,就将其删除,如果都有但是内容不同的节点,就将其更新。如果旧节点不包含子节点,那么这个旧节点有可能是文本节点或者空节点,如果是文本节点就清空文本内容然后把新的子节点创建一份插入旧节点,如果旧节点是空节点,直接插入子节点。1.判断是否为元素节点只看它有没有tag标签,如果有则视为元素节点,则调用createElement方法创建元素节点,通常元素节点还会有子节点,就递归遍历创建所有子节点,将所有创建好后insert插入到当前元素节点,最后把该元素节点插入DOM中。
2024-09-26 18:14:27
748
原创 Vue源码探究虚拟DOM
把组成一个DOM节点的必要东西通过一个JS对象表示出来,那么这个JS对象就可以用来描述这个DOM节点,我们把这个对象成为真实DOM节点的虚拟DOM节点那么为什么需要这个虚拟DOM节点?我们知道VUE是数据驱动视图的,数据变化视图随之变化,在更新视图时需要操作DOM,而操作真实DOM节点是非常耗费性能的,这是因为浏览器把DOM节点设计的非常复杂,一个真实DOM节点是非常庞大的。所以对于需要时常更新的视图我们不能每次都去操作真实DOM,这是不合理的。
2024-09-26 09:32:43
889
原创 根据源码解析Vue2中对于数组的变化侦测
首先我们分析了对于Array型数据也在getter中进行依赖收集;其次我们发现,当数组数据被访问时我们轻而易举可以知道,但是被修改时我们却很难知道,为了解决这一问题,我们创建了数组方法拦截器,从而成功的将数组数据变的可观测。接着我们对数组的依赖收集及数据变化如何通知依赖进行了深入分析;最后我们发现Vue不但对数组自身进行了变化侦测,还对数组中的每一个元素以及新增的元素都进行了变化侦测,我们也分析了其实现原理。
2024-09-25 15:33:24
961
原创 根据源码解析Vue2中对于对象的变化侦测
通过方法实现了对object数据的可观测,并且封装了Observer类,让我们能够方便的把object数据中的所有属性(包括子属性)都转换成的形式来侦测变化。接着,知道了在getter中收集依赖,在setter中通知依赖更新,以及封装了依赖管理器Dep,用于存储收集到的依赖。最后,我们为每一个依赖都创建了一个Wtcher实例,当数据发生变化时,通知Watcher实例,由Watcher实例去做真实的更新操作。Data通过observer转换成了的形式来追踪变化。当外界通过Watcher。
2024-09-25 13:36:05
1188
原创 JS手写Promise以及promise.all方法
Promise是处理异步的一种方式,解决了回调地狱的问题。Promise有三种状态:1.pending(待定):初始状态。2.fulfilled(已兑现):表示异步操作成功,返回一个返回值。3.rejected(已拒绝):表示异步操作失败,返回一个错误原因。
2024-09-24 19:54:43
1093
原创 JS手写call,apply,bind方法
this传null或者undefined时,将是window,(node环境是global)这样效果便和上面一样了,但是白白给test加了一个属性这是不行的,所以最后需要删除它。这三个方法的作用说白了就是改变this指向,非常简单,但是手写需要搞清楚原理。手写模拟这种效果,怎么将bar的this指向test呢?使用arguments属性和slice方法可以截取数组。就是最终版本,其他两个也和这个思路大差不差,就省略了。call改变了this指向,指向了test。1.将函数设为对象的属性。
2024-09-20 09:49:07
284
原创 Vue双向数据绑定原理以及Javascript实现
通过数据劫持和发布订阅者模式来实现,同时利用Object.defineProperty()来劫持各个属性的setter和getter,在数据发生改变的时候发布消息给订阅者,触发对应的监听回调来渲染视图,数据和视图是同步的,数据发生改变,视图发生改变反之也是一样的。第二步:compile模版解析指令,把模版中的变量替换成数据,然后初始化渲染视图,同时把每个指令对应的节点绑定上更新函数,添加订阅者,如果数据变化,收到消息,更新视图。1.在自身实例化的时候往订阅器内添加自己。
2024-09-19 18:58:30
286
原创 new操作符具体做了什么?如何自己实现
4.根据构建函数返回的类型判断,如果是值类型,则返回对象,如果是引用类型,则返回这个引用类型。3.把构造函数的this绑定到新的空对象身上。2.把空对象和构造函数通过原型链进行连接。1.先创建一个空对象。
2024-09-18 18:18:45
176
原创 React中的函数组件使用useState
一般操作state,因为涉及到 state 的状态合并,react 认为当你在事件绑定中操作 state 是非常频繁的,所以为了节约性能 react 会把多次 setState 进行合并为一次,最后在一次性的更新 state,而定时器里面操作 state 是不会把多次合并为一次更新的。一个是通过一个新的state值进行更新,另一个是通过函数式更新返回新的state,现在这两种写法没有区别,但是在异步更新时,区别就显现出来了。一个组件的显示形态可以由数据状态和外部参数所决定,而数据就是state。
2024-05-20 19:16:41
445
1
原创 React中的Redux状态管理使用
通常集中状态管理的部分都会单独创建一个'store'目录,而应用通常会有很多个子模块,所以创建一个'modules'目录,在内部编写业务分类的子store,store入口文件index.js的作用是组合modules中所有的子模块,并导出store;简单来说,通过redux将整个状态存储到store中,组件可以派发dispatch行为action给store,其他组件可以通过订阅store中的状态state来更新自身的视图。state.counter中的counter来自于组件中的name;
2024-05-07 18:12:24
1569
5
原创 React中对函数组件和类组件的理解
在使用hooks情况下,一般如果函数调用state,则需要创建一个类组件或者state提升到你的父组件中,然后通过props对象传递到子组件中。在hooks出来之前,函数组件就是无状态组件,不能保管组件的状态,不像类组件中调用setState。函数组件就是通过函数编写的形式去实现一个React组件,是React中定义组件最简单的方式。两者最明显的区别在于编写形式的不同,同一种功能的实现可以分别对应类组件和函数组件的编写形式。如果是一个类组件,则需要将组件进行实例化,然后调用实例对象的render()方法。
2024-05-06 15:43:41
271
原创 React中的state和props以及之间的区别
在子组件中,props在内部不可变,如果想要改变他,只能通过外部组件传入新的props来重新渲染子组件,否则子组件的props和展示形式不会改变。react中的组件从概念上看就是一个函数,可以接受一个参数作为输入值,这个参数就是props,所以可以将其理解为从外部传入组件内的数据。一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state,一般在construct中初始化。1.props是外部传递给组件的,而state是在组件内被组件自己管理的,一般在constructor中初始化。
2024-04-28 16:52:05
445
2
原创 Javascript中关于new操作符
new通过构造函数Person创建出来的实例可以访问到构造函数原型链中的属性(即实例与构造函数通过原型链连接了起来)4.根据构建函数返回类型做判断,如果是原始值则被忽略,如果是返回对象,需要正常处理。从上面可以发现,构造函数如果返回值为一个对象,那么这个返回值会被正常使用。在Javascript中,new操作符用于创建一个给定构造函数的实例对象。如果在构造函数中显示加上返回值,而且这个返回值是一个原始类型。可以发现,构造函数中返回一个原始值,然而这个返回值并没有作用。下面在构造函数中返回一个对象。
2024-04-27 13:22:31
736
4
原创 Javascript中关于防抖与节流
函数防抖:在一段连续操作结束后,处理回调,利用clearTimeout和setTimeout实现,函数节流,在一段连续操作中,霉一段时间只执行一次,频率较高的事件中使用来提高性能。例如:浏览器的resize、scorll、keypress、mousemove等事件在触发时,会不断调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数,节流每隔500ms就执行一次,防抖不管调用多少次方法在2S后只会执行一次。
2024-04-26 13:44:10
462
3
原创 Javascript关于类型转换
在Javascript中有六种简单数据类型:undefined、null、boolean、string、number、symbol,以及引用类型:Object。虽然变量的数据类型是不确定的,但是对各种运算符对数据类型是有要求的,如果运算的类型与预期不符合,就会触发类型转换机制。从上面可以看到,Number转换的时候是很严格的,只要有一个字符无法转换成数值,整个字符串就会被转为NaN。相比于Number,就没那么严格 了,parseInt函数逐个解析字符,遇到不能转换的字符就停下来。1.比较运算(==、!
2024-04-24 12:57:50
389
4
原创 Javascript中对闭包的理解以及使用场景
一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量生命周期的目的。是维护他们各自的独立性的,每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境,不会影响另一个闭包中的变量。中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部链接起来的一座桥梁。例如计数器,延迟调用,回调等闭包的应用,其核心思想还是创建私有变量和延长变量的生命周期。
2024-04-23 08:49:39
372
1
原创 Javascript原型,原型链,以及特点
__proto___作为不同对象之间的桥梁,用来指向创建它的构造函数的原型对象每个对象的___proto___都是指向它的构造函数的原型对象prototype的构造函数是一个函数对象,是通过Function构造器产生的原型对象本身是一个普通对象,而普通对象的构造函数都是Object所有构造器都是函数对象,函数对象都是Function构造产生的Object的原型对象也有___proto___属性指向Null,Null是原型链的顶端。
2024-04-22 20:11:23
1612
1
原创 Javascript中关于this的理解
函数的关键字在中的表现略有不同,在绝大多数情况下,函数的调用方式决定了this的值(运行时绑定)关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用他的对象举个例子:// 当前调用栈是baz// 因此,当前调用位置是全局作用域bar();// bar// 因此,当前调用位置在baz中foo();// bar --> foo。
2024-04-22 16:33:10
366
2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人