前端面试题总结
(描述后期补充)
1- vue2与vue3双向绑定数据的原理不同
vue2双向数据绑定采用了es5中Object.defineProperty() 对数据进行了劫持,结合发布订阅模式实现
vue3 采用了es6中的proxy代理对象的方式进行数据交互,相较vue2来说大大的提高了效率
2- vue3支持碎片(Fragments)
支持多个根节点
3- Composition API
Vue2 与vue3 最大的区别是vue2使用选项式api,对比vue3组合式api。旧得选项型api在代码里分割了不同得属性:data,computed,methods等;新得组合式api能让我们使用方法来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁
4-建立数据data
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法
备注:此方法在组件初始化构造得时候触发。使用一下三个步骤来建立反应性数据:
1. 从vue引入reactive;
2. 使用reactive() 方法来声明数据为响应性数据;
3. 使用setup()方法来返回我们得响应性数据,从而template可以获取这些响应性数据。
5- 生命周期
vue2 --------------- vue3
beforeCreate -> setup()
Created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroyed -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
--------------------------------------------------------------------
beforeCreate 和 created 已经合并成一个新的函数 setup。
deactivated 和 activated 已经被废弃,取而代之的是 beforeMount 和 beforeUpdate。因为在Vue3中,keep-alive组件被完全重写了,其默认行为现在与没有keep-alive一样。
6- 父子传参不同
父传子,用props,子传父用事件 Emitting Events。
在vue2中,会调用this$emit然后传入事件名和对象;
在vue3中得setup()中得第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。
7- 新增setup()函数特性
响应式原理就是指的是MVVM的设计模式的核心,即数据驱动页面,一旦数据改变,视图也会跟着改动。
vue2的响应式原理是由Object.defineProperty()实现的 (数据劫持)
vue3的响应式原理是由es6中的Proxy所实现的 (数据代理)
1、computed擅长处理的场景:一个数据受多个数据影响;watch擅长处理的场景:一个数据影响多个数据。
2、功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
3、是否调用缓存:computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作。
4、是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
5、computed不支持异步 ,当computed内有异步操作时无效,无法监听数据的变化;而watch支持异步。
6、computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
setup是什么,作用
1、新的选项,所有的组合api函数都在此使用,只在初始化时执行一次
2、函数如果返回对象,对象中的属性与方法,在模板中可以直接使用
执行时机:
1、在beforeCreate之前执行一次,此时组件对象还没有创建
2、This的值为undefined,不能通过this操作 data、computed、methods、props
3、所有的composition api 都不能使用this
返回值:
1、一般都返回一个对象,用于向模板返回数据,返回的数据模板可以直接使用
2、返回的对象的属性与data返回的数据 在组件对象中属性合并
3、返回的对象的方法与methods返回的数据 在组件对象中方法合并
4、切记:
(1)如遇相同名字 setup优先
(2)Methods可以访问setup中属性与方法,setup不可以访问data与methods ,此方式不推荐使用
(3)Setup不能是一个异步函数,如果设置为异步函数返回的是一个promise,模板不能获取到return返回的对象
参数:
setup(props, context) / setup(props, {attrs, slots, emit})
props:接收组件的属性,
context:上下文对象,包括 slots,attrs,emit,expose
(1)attrs: 包含没有在props配置中声明的属性的对象, 相当于 this. a t t r s ( 2 ) s l o t s : 包含所有传入的插槽内容的对象 , 相当于 t h i s . attrs (2)slots: 包含所有传入的插槽内容的对象, 相当于 this. attrs(2)slots:包含所有传入的插槽内容的对象,相当于this.slots
(3)emit: 用来分发自定义事件的函数, 相当于 this.$emit
在逻辑组织和逻辑复用方面,Composition API是优于Options API
因为Composition API几乎是函数,会有更好的类型推断。
Composition API对 tree-shaking 友好,代码也更容易压缩
Composition API中见不到this的使用,减少了this指向不明的情况
如果是小型组件,可以继续使用Options API,也是十分友好的
定义数据角度:
ref用来定义:基本类型数据。
reactive用来定义:对象(或数组)类型数据。
备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象。
原理角度:
ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。
reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
使用角度:
ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
reactive定义的数据:操作数据与读取数据:均不需要.value。
- 父传子 通过在父组件自定义属性,在子组件通过props接收
- 子改父或者子传父 在父组件中通过自定义事件传递方法,在子组件中通过 e m i t 接收自定义事件 < c h i l d r e n @ e v e n t C h a n g e = ” c h a n g e ” > < / c h i l d r e n > t h i s . emit接收自定义事件 <children @ eventChange=”change”></children> this. emit接收自定义事件<children@eventChange=”change”></children>this.emit(‘eventChange’,100)
- 兄弟之间通信 通过一个事件总线(eventBus 其实是一个空实例),在A组件中通过 o n 绑定自定义事件在 B 组件中通过 on绑定自定义事件 在B组件中通过 on绑定自定义事件在B组件中通过emit接收组件
4.通过 p a r e n t / parent / parent/children/$refs $parent指的是父组件实例 c h i l d r e n / children/ children/refs是子组件实例- $attrs & $listeners
a t t r s 获取父组件中不被 p r o p s 接收的自定义属性并且可以通过 v − b i n d = " attrs获取父组件中不被props接收的自定义属性 并且可以通过 v-bind=" attrs获取父组件中不被props接收的自定义属性并且可以通过v−bind="attrs" 传入内部组件
$listeners获取父组件中的自定义事件
6 跨代传参 依赖provide传输数据 通过 inject将数据注入到对应的组件中
7 vuex 、 pinia 可以在任意组件中实现数据共享
8 pubsub-js
PubSub.subscribe()订阅消息
PubSub.publish() 发布消息
1.hash模式带#号比较丑,history模式比较优雅;
2.pushState设置的新的URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL;
3.pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中;
4.pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串;
5.pushState可额外设置title属性供后续使用;
6.hash兼容IE8以上,history兼容IE10以上;
7.history模式需要后端配合将所有访问都指向index.html,否则用户刷新页面,会导致404错误。
全局前置守卫:beforeEach
全局解析守卫:beforeResolve
全局后置钩子:afterEach
路由独享守卫:beforeEnter
组件内—进入:beforeRouteEnter
组件内—更新:beforeRouteUpdate
组件内—离开:beforeRouteLeave
里面的三个参数:
to : 即将要进入的目标 路由对象
from : 当前导航正要离开的路由
next() 通过调用next方法 才会进入到目标路由对象
Next()默认参数为:
True:允许跳转,
False: 拒绝跳转,
路由路径: 跳转到该路径
函数:在跳转前进行逻辑处理,从而决定是否跳转。
函数内的参数可以获取到组件的实例;
与 watchEffect() 相比,watch() 使我们可以:懒执行副作用:watch是懒侦听执行的;watchEffect是首次就会执行
触发侦听器的来源:watch是明确知道由哪个依赖引起的侦听,watchEffect不明确
可以访问所侦听状态的前一个值和当前值:watch可以,watchEffect不可以。
跨域是如何形成的?
当我们请求一个url的 协议、域名、端口三者之间任意一个与当前页面url的协议、域名、端口 不同这种现象我们把它称之为跨域
(了解)跨域会导致:
1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
2、无法接触非同源网页的 DOM
3、无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)
解决方案:
1.jsonp 只能解决get跨域
2.服务器代理 通过配置vue.Config.js文件实现
方式1:使用this.$set() 或者 Vue.set()
– 给对象赋值
//Object:目标对象 key 属性名称 value 值
this.$set(Object,key,value)
– 给数组赋值
//Array:目标数组 index元素索引 value 值
this.$set(Array,index,value)
方式2:使用Object.assign()
1- 操作 v-if:向DOM树添加或者删除DOM元素 v-show:控制css中display属性 进行元素的显示与隐藏 2- 编译过程 v-if:局部编译卸载的过程:在切换过程中,销毁或者重建 组件中的事件与子组件 v-show:执行css的切换 3- 编译条件 v-if:惰性,只有条件为true的时候才会编译解析组件 v-show:任何情况下都会自动加载,然后控制元素的显示与隐藏 4- 性能消耗 v-if:切换消耗高 v-show:只有初始渲染消耗 5- 使用场景 v-if:改变频率不频繁 v-show:频繁切换
1.pinia没有mutations,只有state,getters,actions
2.pinia分模块不需要modules (之前vuex分模块需要modules)
3.pinia体积更小(性能更好)
4.pinia可以直接修改state数据
如果data是对象的话,由于对象是引用类型,组件被复用的话,就会创建多个实例。本质上,这些实例用的都是同一个构造函数。这样就会影响到所有的实例,所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。
1、主要是为了高效的更新虛拟DOM,其原理是vue在patch(补丁)过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
2、 另外,若不设置key还可能在列表更新时引发一些隐蔽的bug。如某行数据不该更新的却更新了。
3、vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果
-或者--------------------------------------------------------------------------------------
1- 唯一标识
2.因为虚拟 dom 有一个 diff 算法,key 是唯一的,不会让数据产生混乱,可以高效更新的虚拟
dom
不建议使用索引作为 key,可以使用唯一 id 作为 key
原因:如果在一个数组中插入某一个值,vue 识别后会从新分配后续索引,速度变慢, 当
删除一条数据时,他的索引也会发生变化,会让数据产生混乱
Keep-alive 是 Vue.js 内置的一个抽象组件,用于缓存有状态组件,可以在组件切换时保留组件的状态避免重新渲染。它有以下两个作用:
1- 缓存有状态的组件,避免组件在切换时被重新渲染;
2- 在缓存的组件被激活时触发 activated 钩子函数,在缓存的组件被停用时触发 deactivated 钩子函数。
目的:使用 Keep-alive 可以提高组件的性能,尤其是在组件状态比较复杂或需要较长时间计算的情况下,通过缓存组件避免重复渲染,提高应用的性能。
属性:
① include:字符串或正则,只有名称匹配的组件会被缓存。
② exclude:字符串或正则,任何名称匹配的组件都不会被缓存。
③ max:数字,最多可以缓存多少组件实例。
pinia是Vue3中的状态管理库,具有以下核心属性:
$state:一个ref对象,用于存储状态数据。
$getters:一个包含所有状态的getter函数的对象。
$actions:一个包含所有操作状态的action函数的对象。
在组件中使用pinia,需要通过useStore方法来获取一个与组件相关联的状态管理对象。
query
1.是拼接在url后面的参数。
2.参数在?后面,且参数之间用&符分隔
3.query相当于get请求,可以在地址栏看到参数
params
1.是路由的一部分。以对象的形式传递参数
2.使用params传参只能由name引入路由,如果写成path页面会显示警告,说参数会被忽略
3.params相当于post请求,参数不会再地址栏中显示
或者
1、query 传参配置的是 path,而 params 传参配置的是 name,在 params 中配置 path 无效
2、query 在路由配置不需要设置参数,而 params 必须设置
3、query 传递的参数会显示在地址栏中
4、params 传参刷新会无效,但是 query 会保存传递过来的值,刷新不变 ;
5、接收参数使用 this.$router 后面就是搭配路由的名称就能获取到参数的值
$route:获取路由信息 指当前路由实例跳转到的路由对象
包括:
$route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如/home/ews
$route.name 当前路由的名字,如果没有使用具体路径,则名字为空
$route.router 路由规则所属的路由器
$route.matchd 数组,包含当前匹配的路径中所包含的所有片段所对象的配置参数对
象
$route.query 对象,包含路由中查询参数的键值对。会拼接到路由 url 后面
$route.params 对象,含路有种的动态片段和全匹配片段的键值对,不会拼接到路由
的 url 后面
r o u t e r :获取路由整个实例指整个路由实例,可操控整个路由通过‘ router:获取路由整个实例 指整个路由实例,可操控整个路由 通过‘ router:获取路由整个实例指整个路由实例,可操控整个路由通过‘router.push’往其中添加任意的路由对象 钩子函数等
1.性能的提升
打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
2.源码的升级
使用Proxy代替defineProperty实现响应式
重写虚拟DOM的实现
3.Vue3可以更好的支持TypeScript
新的特性-Composition API(组合API)
作用:实现祖与后代组件间通信
套路:父组件有一个 provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据
具体写法:
祖组件中:
setup(){
......
let car = reactive({name:'奔驰',price:'40万'})
provide('car',car)
......
}
-----------------------------------------------------
后代组件中:
setup(props,context){
......
const car = inject('car')
return {car}
......
}
MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。
View层是视图层,也就是用户界面。前端主要由HTML和CSS来构建;
Model层 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,对于前端来说就是后端的提供的API接口;
ViewModel层是视图数据层,一个同步View和Model的对象。
在MVVM架构下,View和Model之间并没有直接的联系,而是通过ViewModel进行交互,Model和ViewModel之间的交互是双向的,因此View数据的变化会同步到Model中,而Model数据的变化也会立即反应到View上。
ViewModel通过双向数据绑定把View层和Model层连接了起来,而View和Model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需要关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来统一管理。
概念:
虚拟DOM其实就是用一个原生的JS对象去描述一个DOM节点,实际上它只是对真实 DOM 的一层抽象。最终可以通过一系列操作使这棵树映射到真实环境上。
相当于在js与DOM之间做了一个缓存,利用patch(diff算法)对比新旧虚拟DOM记录到一个对象中按需更新, 最后创建真实的DOM
虚拟dom原理流程:
模板 ==> 渲染函数 ==> 虚拟DOM树 ==> 真实DOM
vuejs通过编译将模板(template)转成渲染函数(render),执行渲染函数可以得到一个虚拟节点树
在对 Model 进行操作的时候,会触发对应 Dep 中的 Watcher 对象。Watcher 对象会调用对应的 update 来修改视图。
虚拟 DOM 的实现原理主要包括以下 3 部分:
用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
diff 算法 — 比较两棵虚拟 DOM 树的差异;
pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
-- hook本质是一个函数,把setup函数中使用的Composition API进行了封装。类似于vue2.x中的mixin。
-- 自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
语法:const name = toRef(person,‘name’)
应用: 要将响应式对象中的某个属性单独提供给外部使用时。
扩展:toRefs 与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
readonly: 让一个响应式数据变为只读的(深只读)。
shallowReadonly:让一个响应式数据变为只读的(浅只读)。
应用场景: 不希望数据被修改时。
**在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。 **
使用场景:
1- 如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.nextTick()
2- 在created生命周期中进行DOM操作
【以下内容了解】
1 - nextTick 是 Vue 提供的一个全局 API,由于 Vue 的异步更新策略,导致我们对数据修改后不会直接体现在 DOM 上,此时如果想要立即获取更新后的 DOM 状态,就需要借助该方法。
2- Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue 将开启一个异步更新队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入队列一次。
3- 这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。nextTick方法会在队列中加入一个回调函数,确保该函数在前面的 DOM 操作完成后才调用。
Vue 2 中,v-for的优先级比v-if高,这意味着v-if将分别重复运行于每一个v-for循环中。如果要遍历的数组很大,而真正要展示的数据很少时,将造成很大的性能浪费。
Vue 3 中,则完全相反,v-if的优先级高于v-for,所以v-if执行时,它调用的变量还不存在,会导致异常。
很多时候,我们需要将给定匹配模式的路由映射到同一个组件,这种情况就需要定义动态路由。
例如,我们有一个 User组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用动态路径参数(dynamic segment)来达到这个效果:{path: ‘/user/:id’, compenent: User},其中:id就是动态路径参数。
1- 路由懒加载。有效拆分应用大小,访问时才异步加载。
2- keep-alive缓存页面。避免重复创建组件实例,且能保留缓存组件状态。
3- v-for遍历避免同时使用v-if。实际上在 Vue 3 中已经是一个错误用法了。
4- 长列表性能优化,可采用虚拟列表。
5- v-once。不再变化的数据使用v-once。
6- 事件销毁。组件销毁后把全局变量和定时器销毁。
7- 图片懒加载。
8- 第三方插件按需引入。
9- 子组件分割。较重的状态组件适合拆分。
10- 服务端渲染。
Vue.js是一种构建用户界面的现代JavaScript框架。它旨在轻松开发可维护和可重用的应用程序。Vue框架具有简洁的API,并且易于集成到现有项目中。
Vue.js的优点包括:
1- 非常轻量级, 在网页上加载速度很快
2- 可以使用模板或者单文件组件结构构建Realtime数据绑定
3- 组件化和模块化开发
4- 流畅的API,包括生命周期钩子
5- 易于学习和使用
1- 自身需要依赖另一个值得改变而使当前所在DOM更新
2- 计算属性不可以与data中的数据重名
3- 计算属性的方法不需要加括号调用,方法需要单独加括号调用 因为 计算属性 不属于方法 属于属性
4- 计算属性具有缓存机制
当计算属性第一次获取到响应式数据时,会缓存,在后期渲染视图时,会观察响应式数据是否改变,如果改变会调用计算属性,如果没有改变会读取存储的数据,方法只用更新就会重新调用
5- 当获取计算属性时会触发getter ,当设置修改计算机属性是会触发setter
注意:计算属性不可以使用箭头函数,否则this不会指向这个组件的实例
1- 当检测的值发生改变时,那么对应的方法会自动执行
2- deep 开启深度监视
发现对象内部值得变化,可以在选项参数中指定deep:true 作为深度监视,但是监听数组的变更则不需要使用
3- immediate
在选项参数中指定immediate:true将立即以表达式的当前值触发回调
1、在我们的vue项⽬中,难免会因为引⽤第三⽅库⽽需要操作DOM标签,vue为我们提供了ref属性。 ref 被⽤来给元素或⼦组件注册引⽤信息。
引⽤信息将会注册在⽗组件的 $refs 对象上。如果在普通的 DOM 元素上使⽤,引⽤指向的就是 DOM 元素;如果⽤在⼦组件上,引⽤就指向组件实例
2.通过event事件对象
3.通过自定义指令:directive(el)的参数el
通过一个对象代理另一个对象中属性的操作(读get、写set)
vue中的数据代理:
通过 vm 来代理 data对象中属性的操作
为什么使用数据代理:
更加方便的操作data中的数据
数据代理的工作原理:
Object.defineproperty()把data对象中所有属性添加到vm上,为每添加的每一个属性都制定了getter和setter,
可以通过getter和setter对data对象中属性执行读与写的操作
Vue 是一套构建用户界面的渐进式的自底向上增量开发的 MVVM 框架,
核心是关注视图层,vue 的核心是为了解决数据的绑定问题,为了开发大
型单页面应用和组件化,所以 vue 的核心思想是数据驱动和组件化,这
里也说一下 MVVM 思想,MVVM 思想是 模型 视图 vm 是 v 和 m 连
接的桥梁,当模型层数据修改时,VM 层会检测到,并通知视图层进行相
应修改
单页面 spa
优点:前后端分离 用户体验好 一个字 快 内容改变不需要重新加载整
个页面
缺点:不利于 seo, 初次加载时耗长(浏览器一开始就要加载 html css
js ,所有的页面内容都包含在主页面中) ,页面复杂度提高了,导航不
可用
Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
通俗讲,Promise是一个许诺、承诺,是对未来事情的承诺,承诺不一定能完成,但是无论是否能完成都会有一个结果。
Pending 正在做。。。
Resolved 完成这个承诺
Rejected 这个承诺没有完成,失败了
Promise 用来预定一个不一定能完成的任务,要么成功,要么失败
在具体的程序中具体的体现,通常用来封装一个异步任务,提供承诺结果
Promise 是异步编程的一种解决方案,主要用来解决回调地狱的问题,可以有效的减少回调嵌套。真正解决需要配合async/await
方法一:使用JSON.stringify和JSON.parse
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
该方法首先使用JSON.stringify将对象转为JSON字符串,然后再使用JSON.parse将JSON字符串转为对象。该方法的缺点是不能拷贝函数和Symbol等特殊类型的属性。
方法二:递归实现
function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
result[key] = deepClone(obj[key]);
}
return result;
}
该方法通过递归的方式实现深拷贝,能够拷贝对象中的所有属性,包括函数和Symbol等特殊类型的属性。但是如果对象嵌套层数过多,可能会导致栈溢出的问题。
箭头函数是匿名函数,不能作为构造函数,不能使用 new
箭头函数不能绑定 arguments,要用 rest 参数解决
箭头函数没有原型属性
箭头函数的 this 永远指向其上下文的 this,
箭头函数不能绑定 this,会捕获其所在的上下文的 this 值,作为自己的
this
原型
JS声明构造函数(用来实例化对象的函数)时,会在内存中创建一个对应的对象,这个对象就是原函数的原型。构造函数默认有一个prototype属性,prototype的值指向函数的原型。同时原型中也有一个constructor属性,constructor的值指向函数对象。
通过构造函数实例化出来的对象,并不具有prototype属性,其默认有一个__proto__属性,__proto__的值指向构造函数的原型。在原型对象上添加或修改的属性,在所有实例化出的对象上都可共享。
原型的作用:
1.数据共享 节约内存内存空间
2.实现继承
原型链
当在实例化的对象中访问一个属性时,首先会在该对象内部(自身属性)寻找,如找不到,则会向其__proto__指向的原型中寻找,如仍找不到,则继续向原型中__proto__指向的上级原型中寻找,直至找到或Object.prototype.__proto__为止(值为null),这种链状过程即为原型链。如下图所示好理解(根据代码参考下图)
原型链的作用:
查找对象的属性(方法)
(了解)
Object.prototype.constructor.proto === Function.prototype // true
Function.prototype.proto === Object.prototype // true
Object.prototype.proto === null // true
三者的异同
1.特性
Cookie 临时存储
localStorage 永久存储
sessionStorage 临时存储
2. 数据的生命期
Cookie:一般由服务器生成,可设置失效时间。如果在浏览器端生成 Cookie,默认是关闭浏览器后失效
localStorage,sessionStorage:除非被清除,否则永久保存仅在当前会话下有效,关闭页面或浏览器后被清除
3.存放数据大小
Cookie:4K 左右
localStorage,sessionStorage:一般为 5MB
4.与服务器端通信
Cookie:每次都会携带在 HTTP 头中,如果使用 cookie 保存过多数据会带来性能问题
localStorage,sessionStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信
5.易用性
Cookie:需要程序员自己封装,源生的 Cookie 接口不友好
localStorage,sessionStorage:源生接口可以接受,亦可再次封装来对 Object 和 Array 有更好的支持
1、filter()和indexOf()实现去重
let arr= [1, 2, 3, 4, 1, 2, 3, 4]
let newArr= arr.filter((item, index, array) => {
return arr.indexOf(item) === index
})
// newArr=== [1, 2, 3, 4]
2、reduce()和includes()实现去重
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = originalArray.reduce((unique, item) => {
unique.includes(item) ? unique : [...unique, item]
}, [])
// uniqueArray === [1, 2, 3, 4]
3、Set实现去重
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = array => [...new Set(array)]
// or
let uniqueArray = Array.from(new Set(originalArray))
// uniqueArray = [1, 2, 3, 4]
JS基本数据类型有:Number, String, Boolean, Null, Undefined,object ,Symbol。
判断方法:
- typeof操作符
- Object.prototype.toString.call()方法
- instanceof操作符
- constructor属性
区别:
- 强制类型转换是人为地将一种数据类型转换为另一种数据类型,比如使用Number()将字符串转换为数字。
- 隐式类型转换是JS引擎自动进行的类型转换,比如在字符串和数字相加时,JS会将数字隐式地转换为字符串。
作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合。作用域决定了代码区块中变量和其他资源的可见性。一般可分为:全局作用域、局部作用域(函数作用域)、块级作用域。
全局作用域任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。
局部作用域也叫做函数作用域,如果一个变量是在函数内部声明的,它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。
块级作用域凡是代码块就可以划分变量的作用域,这种作用域的规则就叫做块级作用域。
作用域链当在 JS 中使用一个变量时,JS 引擎会尝试在当前作用域下寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推,直至找到该变量或是查找至全局作用域,如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错。
闭包就是能够读取其他函数内部变量的函数。主要作用是解决变量污染问题,也可以用来延长局部变量的生命周期。
优点:延长局部变量的生命周期
缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏
- 首先创建了一个新的空对象
- 设置原型,将对象的原型设置为函数的prototype对象。
- 让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
- 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象
function myNew(context) {
const obj = new Object();
obj.__proto__ = context.prototype;
const res = context.apply(obj, [...arguments].slice(1));
return typeof res === "object" ? res : obj;
}
**浅拷贝:**如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。常用的方法有:object.assgin,扩展运算符等等
**深拷贝:**开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
var a = { count: 1, deep: { count: 2 } }; var b = Object.assign({}, a); // 或者 var c = {...a}; // 实现一个浅拷贝 function shallowClone(obj) { const newObj = {}; for (let prop in obj) { if (obj.hasOwnProperty(prop)) { newObj[prop] = obj[prop]; } } return newObj }
#### 【深拷贝代码说明】
```javascript
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
* @param {Map} map 用于存储循环引用对象的地址
*/
function deepClone(obj = {}, map = new Map()) {
if (obj === null) return obj // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== 'object') return obj
if (map.get(obj)) {
return map.get(obj);
}
let result = {}; // 初始化返回结果
if (
obj instanceof Array ||
// 加 || 的原因是为了防止 Array 的 prototype 被重写,Array.isArray 也是如此
Object.prototype.toString(obj) === "[object Array]"
) {
result = [];
}
// 防止循环引用
map.set(obj, result);
for (const key in obj) {
// 保证 key 不是原型属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key], map);
}
}
return result;
}
1.外层元素padding代替
2.内层元素透明边框 border:1px solid transparent;
3.内层元素绝对定位 postion:absolute:
4.外层元素 overflow:hidden;
5.内层元素 加float:left;或display:inline-block;
6.内层元素padding:1px;
flex 布局的原理 以及属性介绍
flex布局原理:
就是通过给父盒子添加flex属性,来控制子盒子的位置和排列方式。
flex 属性定义子项目分配剩余空间,用flex来表示占多少份数。
.align-self 控制子项自己在侧轴上的排列方式
order 属性定义项目的排列顺序
所谓移动端适配,就是WebApp在不同尺寸的屏幕上等比显示
第一种方法:viewport适配
原理:通过设置 initial-scale , 将所有设备布局视口的宽度调整为设计图的宽度.
第二种方法:借助media实现rem适配
rem:CSS的长度单位, 根元素字体大小的倍数,只有根元素字体大小有关; html 中的根元素即 html 元素。
大部分浏览器的默认字体大小都是16px,所以1rem = 16px;
rem适配原理:
长度单位都是用 rem 设置
当屏幕尺寸改变时,只需要修改 html 元素的 font-size 即可实现等比适配
我们在制作页面的时候,只考虑跟设计稿相同的屏幕尺寸即可,其他尺寸屏幕自动适配
第三种方法:JS配合修改配合rem适配
第四种方法:JS动态修改配合CSS预处理器(less)
第五种方法:JS动态修改配合rem适配
组件化
每个组件都符合开放-封闭原则,封闭是针对渲染工作流来说的,指的是组件内部的状态都由自身维护,只处理内部的渲染逻辑。开放是针对组件通信来说的,指的是不同组件可以通过props(单项数据流)进行数据交互
数据驱动视图
UI=f(data)
通过上面这个公式得出,如果要渲染界面,不应该直接操作DOM,而是通过修改数据(state或prop),数据驱动视图更新
虚拟DOM
由浏览器的渲染流水线可知,DOM操作是一个昂贵的操作,很耗性能,因此产生了虚拟DOM。虚拟DOM是对真实DOM的映射,React通过新旧虚拟DOM对比,得到需要更新的部分,实现数据的增量更新
JSX是react的语法糖,它允许在html中写JS,它不能被浏览器直接识别,需要通过webpack、babel之类的编译工具转换为JS执行
JSX与JS的区别:
JS可以被打包工具直接编译,不需要额外转换,jsx需要通过babel编译,它是React.createElement的语法糖,使用jsx等价于React.createElement
jsx是js的语法扩展,允许在html中写JS;JS是原生写法,需要通过script标签引入
生命周期指的是组件实例从创建到销毁的流程,函数组件没有生命周期,只有类组件才有,因为只有class组件会创建组件实例
组件的生命周期可以分为挂载、更新、卸载阶段
挂载
constructor 可以进行state和props的初始化
static getDerivedStateFromProps
render
componentDidMount 第一次渲染后调用,可以访问DOM,进行异步请求和定时器、消息订阅
更新 当组件的props或state变化会触发更新
static getDerivedStateFromProps
shouldComponentUpdate 返回一个布尔值,默认返回true,可以通过这个生命周期钩子进行性能优化,确认不需要更新组件时调用
render
getSnapShotBeforeUpdate
componentDidUpdate 在组件完成更新后调用
卸载
componentWillUnmount 组件从DOM中被移除的时候调用
错误捕获
static getDerivedStateFromError 在errorBoundary中使用
componentDidCatch
render是class组件中唯一必须实现的方法
react组件会被编译为React.createElement,在createElement中,它的this丢失了,并不是由组件实例调用的,因此需要手动绑定this
??? 为什么不能通过return false阻止事件的默认行为
因为React基于浏览器的事件机制实现了一套自己的事件机制,和原生DOM事件不同,它采用了事件委托的思想,通过dispatch统一分发事件处理函数
1- 类组件可以使用其他特性,如状态和生命周期钩子,并且他有this
2- 函数组件只能接收props渲染到页面,无状态组件,没有this,不能使用生命周期钩子
3- 函数组件性能要高于类组件,因为类组件使用要实例化,而函数组件直接执行取返回结果即可,为了提高性能,尽量使用函数组件
优点:
- 提高了应用性能和开发效率
- 使用JSX,代码可读性好
- react的componentWillUnmount生命周期,能够清除相关所有事件,避免内存泄露
- 并不直接对DOM进行操作,引入了一个虚拟DOM的概念,安插在js和真实DOM中间,性能好,速度快
缺点:
每次 state 更改,render 函数都要生成完整的虚拟 DOM. 哪怕 state 改动很小,render函数也会完整计算一遍。如果 render 函数很复杂,这个过程就白白浪费了很多计算资源
相似之处:
用于创建UI的js库
使用起来轻快便捷
都用了虚拟DOM
都是基于组件的架构
不同点 :
vue使用的html模板;react使用的是js
vue有双向绑定语法
vue增加了语法糖computed和watch等,react需要自己写逻辑来实现
react用了jsx语法
react整体思路是编程式,推荐组件化,数据不变,单向数据流;vue数据可变,双向绑定,声明式的写法
React会创建一个虚拟的DOM。当一个组件的状态改变时,React首先会通过“diffing"算法来标记虚拟DOM中的改变,第二步是调节,会用diff的结果来更新DOM.
e.preventDefault(),e是第三方提供的一个合成事件(注意:不能用return)
作用:用来计算VirtualDOM中被改变部分,针对该部分进行原生DOM操作,不用重新渲染整个页面
state是数据结构,只能使用setState来改变
props是组件的属性,由父组件传递给子组件,props是不可以改变的
state是局部的,除了它所在的这个组件其它组件都无法访问
函数组件:首字母大写,需要return出react元素
类组件:首字母大写,需要使用render方法,return出react元素
区别:
函数组件是无状态组件的思想
函数组件中不能用State,不能用组件的生命周期方法,这就决定了函数组件都是展开性组件,接收props,渲染DOM,而不关注其它逻辑
函数组件中没有this
函数组件更容易理解。当你看到一个函数组件时,你就知道它的功能只是接收属性,渲染页面,它不执行与UI无关的逻辑处理,它只是一个纯函数
组件的生命周期可分成三个状态:
Mounting:已载入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
setState会进行状态更新
将传入的参数对象与组件当前状态合并,然后触发所谓的调和过程,经过调和过程,根据新的state,React元素会重新构建虚拟DOM,进行diff算法对比新旧虚拟DOM树的区别,进行视图更新,而不是全部渲染
setState 采用的任务队列机制,不会马上执行,而是加入队列,在下次事件循环是一次性执行
(在构造函数中)调用 super(props) 的目的是什么
在super() 被调用之前,子类是不能使用 this 的,在 ES5 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props
为什么浏览器无法读取JSX?
浏览器只能处理JS对象,而不能读取常规的JSX。为了使浏览器能够读取JSX,首先,需要像Babel这样的JSX转换器将JSX转换为JS对象,然后再传给浏览器
只读组件,必须保持纯函数,即不可变。它们总是再整个应用中从父组件传递到子组件。子组件永远不能将prop送回到父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据
是React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props不同,它们是可变的,并创建动态和交互式组件。可以通过this.state()访问它们。
围绕浏览器原生事件充当跨浏览器对象。将不同浏览器的行为合并为一个 API。这样做是为了确保事件在不同浏览器中显示一致的属性
受控组件:通过setState的形式控制输入的值及更新
非受控组件:通过dom的形式更新值,获取值通过ref的形式去获取
不可以,会导致无限循环报错
在react中直接修改state,render函数不会重新执行渲染,应使用setState方法进行修改
通过onChange事件监听input的value值,在通过this.setState改变显示出来
函数组件是一个返回react元素的函数,体现的是无状态组件思想,函数组件中没有this,没有state,没有生命周期,决定了函数组件都是展示性组件,接收props,渲染dom
函数组件不需要考虑组件状态和组件生命周期方法,有很大的性能提升空间
即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
一、setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同:
● 在 React 钩子函数及合成事件中,它表现为异步;
● 同步:
○ DOM 原生事件中(绕过React通过addEventListener直接添加的事件处理函数)
○ 通过setTimeout/setInterval产生的异步调用
类组件可以使用其他特性,如状态和生命周期钩子,并且他有this
函数组件只能接收props渲染到页面,无状态组件,没有this,不能使用生命周期钩子
函数组件性能要高于类组件,因为类组件使用要实例化,而函数组件直接执行取返回结果即可,为了提高性能,尽量使用函数组件
refs是提供一种访问在render方法中创建DOM节点或者React元素的方法,在典型的数据流中,props是父子组件交互的唯一方式,想要修改子组件,需要使用新的props重新渲染它,某些情况下,在典型的数据流外,强制修改子代,这个时候可以使用refs
我们可以在组件添加一个ref属性来使用,该属性是一个回调函数,接收作为其第一个参数的底层DOM元素或组件挂载实例
input元素有一个ref属性,他的值是一个函数,该函数接收输入的实际DOM元素,然后将其放在实例上,这样就可以在 handleSubmit 函数内部访问它
经常被误解的只有在类组件中才能使用 refs,但是refs也可以通过利用 JS 中的闭包与函数组件一起使用
相同点:都是普通的js对象,他们包含着影响渲染输出的信息
不同点:state是组件自己管理数据,控制自己的状态,可变
props是外部传入的数据参数,不可变
没有state的叫做无状态组件,有state的叫有状态组件
多用props,少用state
63.在构造函数调用super并将props作为参数传入的作用是啥?
在调用 super() 方法之前,子类构造函数无法使用this引用,ES6 子类也是如此。将 props 参数传递给 super() 调用的主要原因是在子构造函数中能够通过this.props来获取传入的 props。
props 的行为只有在构造函数中是不同的,在构造函数之外也是一样的
在第一发布react时,还引入了一种新的js方言jsx,将原始 HTML 模板嵌入到 JS 代码中。JSX 代码本身不能被浏览器读取,必须使用Babel和webpack等工具将其转换为传统的JS。很多开发人员就能无意识使用 JSX,因为它已经与 React 结合在一起了
React 路由是一个构建在 React 之上的强大的路由库,它有助于向应用程序添加新的屏幕和流。这使 URL 与网页上显示的数据保持同步。它负责维护标准化的结构和行为,并用于开发单页 Web 应用。 React 路由有一个简单的API
React的主要功能如下:
它使用虚拟DOM 而不是真正的DOM。
它可以进行服务器端渲染。
它遵循单向数据流或数据绑定。
它提高了应用的性能
可以方便地在客户端和服务器端使用
由于 JSX,代码的可读性很好
React 很容易与 Meteor,Angular 等其他框架集成
使用React,编写UI测试用例变得非常容易
虚拟 DOM 渲染:当render方法被调用时,它返回一个新的组件的虚拟 DOM 结构。当调用setState()时,render会被再次调用,因为默认情况下shouldComponentUpdate总是返回true,所以默认情况下 React 是没有优化的。
原生 DOM 渲染:React 只会在虚拟DOM中修改真实DOM节点,而且修改的次数非常少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。
React 中最常见的问题之一是组件不必要地重新渲染。React 提供了两个方法,在这些情况下非常有用:
React.memo():这可以防止不必要地重新渲染函数组件
PureComponent:这可以防止不必要地重新渲染类组件
这两种方法都依赖于对传递给组件的props的浅比较,如果 props 没有改变,那么组件将不会重新渲染。虽然这两种工具都非常有用,但是浅比较会带来额外的性能损失,因此如果使用不当,这两种方法都会对性能产生负面影响。
通过使用 React Profiler,可以在使用这些方法前后对性能进行测量,从而确保通过进行给定的更改来实际改进性能。
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state() 访问它们
key 用于识别唯一的 Virtual DOM 元素及其驱动 UI 的相应数据。它们通过回收 DOM 中当前所有的元素来帮助 React 优化渲染。这些 key 必须是唯一的数字或字符串,React 只是重新排序元素而不是重新渲染它们。这可以提高应用程序的性能
模块
理解:向外提供特定功能的js程序, 一般就是一个js文件
为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
作用:复用js, 简化js的编写, 提高js运行效率
组件
理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
为什么要用组件: 一个界面的功能更复杂
作用:复用编码, 简化项目编码, 提高运行效率
模块化:当应用的js都以模块来编写的, 这个应用就是一个模块化的应用
组件化:当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
React 中的 Action 必须具有 type 属性,该属性指示正在执行的 ACTION 的类型。必须将它们定义为字符串常量,并且还可以向其添加更多的属性。在 Redux 中,action 被名为 Action Creators 的函数所创建
Redux 的优点如下:
结果的可预测性 - 由于总是存在一个真实来源,即 store ,因此不存在如何将当前状态与动作和应用的其他部分同步的问题。
可维护性 - 代码变得更容易维护,具有可预测的结果和严格的结构。
服务器端渲染 - 你只需将服务器上创建的 store 传到客户端即可。这对初始渲染非常有用,并且可以优化应用性能,从而提供更好的用户体验。
开发人员工具 - 从操作到状态更改,开发人员可以实时跟踪应用中发生的所有事情。
社区和生态系统 - Redux 背后有一个巨大的社区,这使得它更加迷人。一个由才华横溢的人组成的大型社区为库的改进做出了贡献,并开发了各种应用。
易于测试 - Redux 的代码主要是小巧、纯粹和独立的功能。这使代码可测试且独立。
组织 - Redux 准确地说明了代码的组织方式,这使得代码在团队使用时更加一致和简单
可以直接写一个字符串,不过它只适用于类组件
createRef和useRef来定义ref变量,ref.current获取数据
可以使用箭头函数的方式,提前定义一个变量,箭头函数的形参就是当前对象
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>、<group>、<p> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果
Store 是一个 JavaScript 对象,它可以保存程序的状态,并提供一些方法来访问状态、调度操作和注册侦听器。应用程序的整个状态/对象树保存在单一存储中。因此,Redux 非常简单且是可预测的。我们可以将中间件传递到 store 来处理数据,并记录改变存储状态的各种操作。所有操作都通过 reducer 返回一个新状态。
浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX。所以为了使浏览器能够读取 JSX,首先,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器
单一事实来源:整个应用的状态存储在单个 store 中的对象/状态树里。单一状态树可以更容易地跟踪随时间的变化,并调试或检查应用程序。
状态是只读的:改变状态的唯一方法是去触发一个动作。动作是描述变化的普通 JS 对象。就像 state 是数据的最小表示一样,该操作是对数据更改的最小表示。
使用纯函数进行更改:为了指定状态树如何通过操作进行转换,你需要纯函数。纯函数是那些返回值仅取决于其参数值的函数。
Reducers 是纯函数,它规定应用程序的状态怎样因响应 ACTION 而改变。Reducers 通过接受先前的状态和 action 来工作,然后它返回一个新的状态。它根据操作的类型确定需要执行哪种更新,然后返回新的值。如果不需要完成任务,它会返回原来的状态
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类
文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景 最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。 在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记
?作者主页:静Yu?简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者?社区地址:前端知识交流社区?博主的个人博客:静Yu的个人博客?博主的个人笔记本:前端面试题个人笔记本只记录前端领域的面试题目,项目总结,面试技巧等等。接下来会更新蓝桥杯官方系统基础练习的VIP试题,依然包括解题思路,源代码等等。问题描述:给定当前的时间,请用英文的读法将它读出来。时间用时h和分m表示,在英文的读法中,读一个时间的方法是: 如果m为0,则将时读出来,然后加上“o’clock”,如3:00读作“threeo’clock”。 如果m不为0,则将时读出来,然后将分读出来,如5
【动态规划】一、背包问题1.背包问题总结1)动规四部曲:2)递推公式总结:3)遍历顺序总结:2.01背包1)二维dp数组代码实现2)一维dp数组代码实现3.完全背包代码实现4.多重背包代码实现一、背包问题1.背包问题总结暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化!背包问题是动态规划(DynamicPlanning)里的非常重要的一部分,关于几种常见的背包,其关系如下:在解决背包问题的时候,我们通常都是按照如下五部来逐步分析,把这五部都搞透了,算是对动规来理解深入了。1)动规四部曲:(1)确定dp数组及其下标的含义(2)确定递推公式(3)dp数组的初始化(4)确定遍历顺
最近更新的博客华为OD机试-卡片组成的最大数字(Python)|机试题算法思路华为OD机试-网上商城优惠活动(一)(Python)|机试题算法思路华为OD机试-统计匹配的二元组个数(Python)|机试题算法思路华为OD机试-找到它(Python)|机试题算法思路华为OD机试-九宫格按键输入(Python)|机试算法备考思路华为OD机试-身高排序(Python)|备考思路使用说明参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。华为OD清单查看地址:blog.csdn.net/hihell/catego
1,Camera基本工作原理答案:光线通过镜头Lens进入摄像头内部,然后经过IRFilter过滤红外光,最后到达sensor(传感器),senor分为按照材质可以分为CMOS和CCD两种,可以将光学信号转换为电信号,再通过内部的ADC电路转换为数字信号,然后传输给DSP(如果有的话,如果没有则以DVP的方式传送数据到基带芯片baseband,此时的数据格式RawData,后面有讲进行加工)加工处理,转换成RGB、YUV等格式输出。数据流是如何从sensor到APP的?上述描述结束后,在ISP处理后面的阶段,数据会进行分流,分为capture,preview,video等以供后续动作使用。例如
前言介绍了网络安全岗位常见的面试题,仅供参考!一、常识部分1.Linux服务器种用户关键信息存储在那个文件中?启动、停止、重启、开机自启mysql服务命令?如何查找/etc/test.txt文件中"password"关键字信息?如何精确查找80端口?/etc/passwdsystemctlstartmysqld或systemmysqldstart 启动systemctlstopmysqld或systemmysqldstop 停止systemctlrestartmysqld或systemmysqldrestart 重启systemctlenablemysqld或systemmysqldenabl
我在之前的面试中遇到了这个问题,但做不到,知道吗?这是做什么的:`$=`;$_=\%!;($_)=/(.)/;$==++$|;($.,$/,$,,$\,$",$;,$^,$#,$~,$*,$:,@%)=($!=~/(.)(.).(.)(.)(.)(.)..(.)(.)(.)..(.)......(.)/,$"),$=++;$.++;$.++;$_++;$_++;($_,$\,$,)=($~.$"."$;$/$%[$?]$_$\$,$:$%[$?]",$"&$~,$#,);$,++;$,++;$^|=$";`$_$\$,$/$:$;$~$*$%[$?]$.$~$*${#}$%[$?]$;
最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理已参加机试人员的实战技巧本篇题解:贪心的商人or最大利润题目描述商人经营一家店铺,有number种商品,由于仓库限制每件商品的最大持有数量是item[index],每种商品的价格在每天是item_price[item_index][day],通过对商品的买进和卖出获取利润,请给出商人在days天内能获取到的最大的利润;注:同一件商品可以反复买进和卖出;输入描述3//输入商品的数量nu