关于javascript:热点面试题什么是粘包半包问题该如何解决

前言极度投入,深度沉迷,边界清晰 前端小菜鸡一枚,分享的文章纯属个人见解,若有不正确或可待探讨点可随便评论,与各位同学一起学习~ 欢送关注 『前端进阶圈』 公众号 ,一起摸索学习前端技术...... 公众号回复 加群 或 扫码, 即可退出前端交流学习群,长期交流学习...... 公众号回复 加好友,即可添加为好友 什么是粘包/半包问题,该如何解决?什么是粘包?粘包问题:在数据传输时,在一条音讯中读取到了另一条音讯的局部数据,这种景象叫做粘包。比方发送了两条音讯,别离为“ABC”和“DEF”,那么失常状况下接收端也应该收到两条音讯“ABC”和“DEF”,但接收端却收到的是“ABCD”,像这种状况就叫做粘包,如下图所示: 什么是半包?半包问题:指接收端只收到了局部数据,而非残缺的数据的状况就叫做半包。比方发送了一条音讯是“ABC”,而接收端却收到的是“AB”和“C”两条信息,这种状况就叫做半包,如下图所示: 为什么会呈现粘包问题?Q: 为什么会呈现粘包问题? R: 粘包问题产生在 TCP/IP 协定中,因为 TCP 是面向连贯的传输协定,它是以 流 stream 的模式传输数据的,而 流 数据是没有明确数据的开始和结尾边界的,所以就会呈现粘包问题。 如何解决粘包/半包问题?Q: 如何解决粘包/半包问题? 固定数据大小:发送放和接管方固定发送数据的大小,当字符串长度不够时用空字符补救。有了固定大小之后就晓得每条音讯的具体边界了,这样就没了粘包问题。 毛病:当数据量小的时候应用空字符来填充,会额定减少网络传输的累赘。封装自定义数据协定层:在 TCP 协定的根底上封装一层自定义数据协定,在自定义数据协定中,蕴含数据头(贮存数据的大小) 和数据的具体内容,这样服务端失去数据后,通过解析数据头就能够晓得数据的具体长度,也就没有粘包的问题了。 毛病:此计划尽管能够解决粘包问题,但音讯的设计和代码的实现复杂度比拟高,所有也不是现实的解决方案以非凡的字符结尾: 比方 \n 结尾,这样咱们就晓得数据的具体边界了从而防止了粘包的问题。 毛病:长处是实现起来简略,但存在肯定的局限性,比方一条音讯两头如果呈现了结束符就会造成半包的问题,所以如果是简单的字符串要对内容进行编码和解码解决,这样能力保障结束符的正确性。包头 + 包体格局:这种格局的包个别分为两局部,即包头和包体,包头是固定大小的,且包头中必须含有一个字段来阐明接下来的包体有多大。文章特殊字符形容:问题标注 Q(question)答案标注 R(result)注意事项规范:A:(attention matters)详情形容标注:D:(detail info)总结标注:S:(summary)剖析标注:Ana:(analysis)提醒标注:T:(tips)往期回顾:热点面试题:过程系列问题?热点面试题:Node.js 中的垃圾回收机制?热点面试题:简述 http3.0~http1.0 别离有什么改良?JavaScript中的AMD和CMD标准Vue数据监听Object.definedProperty()办法的实现最初:欢送关注 『前端进阶圈』 公众号 ,一起摸索学习前端技术......公众号回复 加群 或 扫码, 即可退出前端交流学习群,长期交流学习......公众号回复 加好友,即可添加为好友

January 19, 2023 · 1 min · jiezi

关于javascript:什么是纯函数

什么是纯函数?纯函数顾名思义首先是一个函数,然而它须要恪守肯定规定 至多接管一个参数须要有返回值返回后果只依赖输出参数不产生副作用(不容许批改传入的参数,不容许批改全局变量)为什么要用纯函数? 便于进行单元测试 纯函数不会批改全局变量,不会批改任何货色,返回的后果只和传入的参数相干,具备可预测性。测试时不依赖任何环境和数据。具备可复用性 纯函数的返回后果只依赖于传入的参数,所以该函数耦合性小,因而能够很不便地复用。

January 19, 2023 · 1 min · jiezi

关于javascript:立即执行函数IIFE和闭包

IIFEIIFE: immediately-invoked function expression,立刻调用函数表达式,函数在定义的时候,立刻执行,是一种语法。 前置常识理解函数申明和函数表达式的区别 以 function 结尾的就是函数申明痛过赋值给变量的就是函数表达式例子: function a() {} // 函数申明var a = function () {}; // 函数表达式模式(function () {})(); // 模式1(function () {}()); // 模式2+function () {}(); // 模式3-function () {}(); // 模式4!function () {}(); // 模式5~function () {}(); // 模式6申明一个函数,个别是匿名函数,因为立刻执行函数是不须要名字的将函数申明转换成函数表达式,能够应用上面四个一元运算符(只用一个操作数):+ - ! ~(按位取反运算符),或者用小括号包裹起来让表达式执行,在表达式前面增加小括号让函数立刻执行作用不须要为函数命名,防止净化全局变量创立一个独立作用域,这个作用域外面的变量外界拜访不到,防止净化全局变量应用场景页面加载完后,须要立刻执行一些初始化设置,例如事件处理,创建对象等在利用中只执行一次的代码闭包这个知识点来来回回总结了好屡次,次要本人没有一个太明确的概念,而且再工作中用的场景也很好,前面遇到再好好补充。 闭包:在函数内部拜访函数外部的变量的函数,就是闭包,失常状况下在函数内部是拜访不到函数外部变量的。 举个例子 function a() { let i = 0;}console.log(i); // ReferenceError: i is not defined在内部拜访会报错,对吧,因为依据作用域链的规定,只能是函数外部能拜访内部的变量,那我当初有一个需要,我就想拜访外部的变量,怎么办,这个时候就能够应用闭包了。既然外部能够拜访内部的变量,那我就在外部定义一个函数,去拜访这个变量,而后我再把这个函数给返回进来不久能够了。 function a() { let i = 0; return function b() { console.log(i); }}let c = a();c(); // 0这个革新一下,这个就是闭包了 ...

January 19, 2023 · 1 min · jiezi

关于javascript:如何通过闭包对象管理程序中状态的变化学习笔记-day3

值的不可变原始类型不可能扭转一个原始类型的值对象类型值是可变的React.js中的props 和stateprops通常是作为一个内部参数,传入到函数里。作为动态元素输入在UI中渲染。state是一个外部变量。作为动静元素输入在UI中渲染。 props和state 都是用对象来存储状态的。构造值不可变props和state是不是必须的?props是必须的,state不是如果利用和用户之间有交互,就须要治理值的状态,和围绕值设计一些列行为。这个过程中,咱们须要思考的就是一个值的构造不可变的问题闭包和对象这两者都能够对一个状态值进行封装和创立因为。闭包最大特点是能够冲破生命周期和作用域的限度当一个内部函数内嵌一个外部函数时,如果内嵌函数援用了内部函数的变量,这个变量就会冲破生命周期的限度,在函数完结执行后,依然存在。冲破作用域的限度是指,咱们能够把一个外部函数返回成一个办法在内部调用。单纯从值的状态治理和围绕它的一系列行为的角度来看,咱们能够说闭包和对象是同状态的(isomorphic)。差别:在隐衷、状态拷贝、性能。在结构性的解决值的问题,具备不同的优劣势属性的查改闭包:除非通过接口,也就在内部函数中返回外部函数的办法,不然外部是不对外的对象:不须要非凡的形式,就能够获取对象中的属性和从新赋值;Object.freeze()-将对象设置为只读>writable: false状态的拷贝如何解决拷贝性能问题?

January 18, 2023 · 1 min · jiezi

关于javascript:一个-gosqldriver-的离奇-bug

文|郝洪范 京东技术专家 Seata-go 我的项目独特发起人 微服务底层技术的摸索与钻研。 本文 3482 字 浏览 7 分钟 对于 Go CURD Boy 来说,置信 github.com/go-sql-driver/mysql 这个库都不会生疏。基本上 Go 的 CURD 都离不开这个特地重要的库。咱们在开发 Seata-go 时也应用了这个库。不过最近在应用 go-sql-driver/mysql 查问 MySQL 的时候,就呈现一个很有意思的 bug, 感觉有必要分享进去,以避免后来者再次踩坑。PART. 1 问题详述为了阐明问题,这里不详述 Seata-go 的相干代码,用一个独自的 demo 把问题详细描述分明。 1.1 环境筹备在一个 MySQL 实例上筹备如下环境: CREATE TABLE `Test1` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATECURRENT_TIMESTAMP, -PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;从这个 SQL 语句中能够看进去, create_time 是 timestamp 类型,这里要特地注意 timestamp 这个类型。 ...

January 18, 2023 · 3 min · jiezi

关于javascript:总结一些书写-CSS-的时候经常犯的错误

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。当咱们十分专一写代码时候,咱们往往会有意识的写出一些有效CSS代码。 我把这种称为 “潜意识谬误”。 导致这种谬误后,咱们常常会反诘本人:“为什么我写出这样低级谬误?” 不过,这些谬误都比拟好解决,不须要花很多工夫,只有纠正一下就行了。 跟着本文看看,我会常常写哪些乏味的 CSS 谬误。 Font Size? 我在font-size和font-weight之间常常犯错误,如下所示: .title { font-size: bold;}Opacity我也不晓得啥起因,但有时我会遗记写百分比 ?: .title { opacity: 50;}对于 opacity 我还常常犯上面谬误: .title { /* 现这一点并不容易,你们看出谬误在哪里吗? ?*/ opaciy: 0.5;Font Weight是 light 还是 lighter ?? .title { font-weight: light;}Padding当你认为属性是padding,而实际上用的是padding-top时,就会产生这种状况?: .section { padding-top: 10px 20px;}人才,优良 ?。 CSS Grid对于 CSS Grid 有时我会潜意识的写 grid-column 而不是 grid-template-columns ?: .section { grid-columns: 1fr 1fr 1fr;}CSS 变量对于 CSS 变量的应用,我也常常遗记写 var ?: ...

January 18, 2023 · 1 min · jiezi

关于javascript:源码库在调用-createApp-时Vue-为我们做了那些工作

在应用Vue3时,咱们须要应用createApp来创立一个利用实例,而后应用mount办法将利用挂载到某个DOM节点上。 那么在调用createApp时,Vue再背地做了些什么事件呢?明天就来扒一扒Vue3的源码,看看调用createApp产生了些什么。 大家好,这里是田八的【源码&库】系列,Vue3的源码浏览打算,Vue3的源码浏览打算不出意外每周一更,欢送大家关注。 首发在掘金,如果想一起交换的话,能够点击这里一起独特交换成长 系列章节:【源码&库】跟着 Vue3 学习前端模块化寻找入口在上一章中,咱们咱们曾经将Vue3的源码下载下来了,并且曾经晓得如何编译源码了,先看一下Vue3的源码目录: packages目录下的包就是Vue3的所有源码了,编译之后会在每个工程包上面生成一个dist目录,外面就是编译后的文件。 这里我框出了vue包,这个大家都相熟,关上vue包下的package.json文件,能够看到unpkg字段指向了dist/vue.global.js文件,这个文件就是Vue3的全局版本,咱们能够间接在浏览器中引入这个文件来应用Vue3。 代码逻辑基本上都是雷同的,用打包后的文件来剖析源码,能够更加直观的看到源码的逻辑,因为Vue在设计的时候会思考其余平台,如果间接通过源码来查看会有额定的心智累赘。 具体如何应用每个打包后的文件,能够查看vue包下的README.md文件,如果只是想剖析源码,且不想那么麻烦,能够间接应用dist/vue.global.js文件。 如果想理解Vue3的目录构造和模块划分能够应用vue.esm-bundler.js文件,这个文件是Vue3的ESM版本,会通过import来引入其余模块,这样就能够间接看到Vue3的模块划分。 本系列就会通过vue.esm-bundler.js文件来剖析Vue3的源码,并且会通过边剖析边入手的形式来学习Vue3的源码。 应用咱们先来看一下Vue3的应用形式: import {createApp} from 'vue'import App from './App.vue'const app = createApp(App)app.mount('#app')在Vue3中,咱们须要应用createApp来创立一个利用实例,而后应用mount办法将利用挂载到某个DOM节点上。 createApp是从vue包中导出的一个办法,它接管一个组件作为参数,而后返回一个利用实例。 入口 createApp从vue的package.json能够看到,module字段指向了dist/vue.esm-bundler.js文件,这个文件是Vue3的ESM版本,咱们能够间接应用import来引入Vue3。 而createApp办法并不在这个包中,而是在runtime-dom包中,这个文件是间接全副导出runtime-dom包中的内容: export * from '@vue/runtime-dom';不必狐疑@vue/runtime-dom指向的就是runtime-dom包,应用esm版本就间接找xxx.esm-bundler.js文件,应用cjs版本就间接找xxx.cjs.js文件,前面不会再提到这个问题。 关上runtime-dom.esm-bundler.js文件,能够看到createApp办法: import { } from '@vue/runtime-core';export * from '@vue/runtime-core';import { } from '@vue/shared';// ... 省略n多代码function createApp(...args) { // ...}export {createApp};能够看到runtime-dom包中还援用了runtime-core包和shared包,当初找到入口文件了,在剖析间接能够先搭建一个简略的代码剖析和测试的环境,这样不便本人验证并且能够间接看到代码的执行后果。 demo环境能够间接在本地搭建,也能够应用codesandbox、stackblitz等在线环境,这里应用codesandbox,后续demo的代码都会放在codesandbox上,文末会有链接。 当然大家也能够间接在本地搭建一个demo环境,这里就不再赘述了。 源码剖析下面的环境都筹备好了之后就能够间接开始剖析Vue3的源码了,咱们先来看一下createApp办法的实现; createAppconst createApp = (...args) => { const app = ensureRenderer().createApp(...args); const {mount} = app; app.mount = (containerOrSelector) => { // ... }; return app;}createApp办法接管一个组件作为参数,而后调用ensureRenderer办法; ...

January 17, 2023 · 7 min · jiezi

关于javascript:吃透JS设计模式-工厂模式

工厂模式概念工厂模式不裸露创建对象的具体逻辑,而是将逻辑封装在一个函数中,创立大量类似对象,那么这个函数就能够被视为一个工厂。工厂模式依据形象水平的不同能够分为:简略工厂,工厂办法和形象工厂 长处通过工厂模式,咱们能够疾速创立大量类似对象,没有反复代码。 毛病工厂模式创立的对象属于Object,无奈辨别对象类型,这也是工厂模式没有宽泛应用的起因。 代码实现简略工厂模式(动态): // 例:将王者英雄进行按需分类,在一个公共的工厂中产出const personList = [ { person: ['妲己', '小乔', '周瑜', '王昭君'] }, { person: ['李白', '阿珂', '兰陵王', '韩跳跳'] }, { person: ['曹阿瞒', '凯爹', '宫本'] } ]let wangzhe = function (personType) { function Fashi() { this.person = personList[0].person } function Cike() { this.person = personList[1].person } function Zhanshi() { this.person = personList[2].person } switch (personType) { case 'fashi': return new Fashi(); break; case 'cike': return new Cike(); break; case 'zhanshi': return new Zhanshi(); break; default: throw new Error('参数谬误, 可选参数:fashi、cike、zhanshi'); } } //调用 let fashi = wangzhe('fashi'); let cike = wangzhe('cike'); let zhanshi = wangzhe('zhanshi'); fashi.peson // ['妲己', '小乔', '周瑜', '王昭君'] // es6写法: class Wangzhe { constructor(opt) { this.person = opt.person; } static getPersonList(personType) { switch (personType) { case 'fashi': return new Wangzhe(personList[0]); break; case 'cike': return new Wangzhe(personList[1]); break; case 'zhanshi': return new Wangzhe(personList[2]); break; default: throw new Error('参数谬误, 可选参数:fashi、cike、zhanshi'); }}}//调用Wangzhe.getPersonList('fashi').person // ['妲己', '小乔', '周瑜', '王昭君']

January 17, 2023 · 1 min · jiezi

关于javascript:使用管控平台管理redis集群

1 增加redis集群在数据库资源中增加redis集群,配置参数并将URL中cluster调整为true。 2 验证配置资源是否失常 3 操作redis数据库中的数据能够通过应用图形化界面或者命令窗口进行Redis数据库的CRUD 3.1 图形化界面操作操作Redis字符串列表 3.1.1 新增右键数据类型,抉择新增,设置名称及value,保留即可。 3.1.2 读取右键对应key,抉择设计,便可查看/批改对应key的value值如果呈现某个key对应value值过多的状况,能够应用搜寻文本框对value数据进行检索。例如搜寻dbkey中的value值中蕴含or字段的 3.1.3 批改右键key,抉择设计,便可查看/批改对应key的value值若要批改对应key的名称,在对应key上右键抉择重命名。 3.1.4 删除删除redis字符串列表中某个value,抉择所选行删除即可。 3.2 命令窗口操作3.2.1 新增 Redis> LPUSH hhdbkey redis(integer) 1Redis> LPUSH hhdbkey mongodb(integer) 2Redis> LPUSH hhdbkey mysql(integer) 33.2.2 读取 Redis> LRANGE hhdbkey 0 101) "mysql"2) "mongodb"3) "redis" 3.2.3 批改lset [lset key index value] :设置列表指定索引的值,如果指定索引不存在则报错 Redis> LRANGE hhdbkey 0 101) "mysql"2) "mongodb"3) "redis"Redis> lset hhdbkey 0 testOKRedis> lrange hhdbkey 0 101) "test"2) "mongodb"3) "redis" 3.2.4 删除lrem [lrem key count value] :移除等于value的元素,当count>0时,从表头开始查找,移除count个;当count=0时,从表头开始查找,移除所有等于value的;当count<0时,从表尾开始查找,移除|count| 个。 ...

January 17, 2023 · 1 min · jiezi

关于javascript:浏览器原理学习笔记Day1

宏观视角下的浏览器Chrome 架构 过程与线程多线程单过程浏览器 问题1:不稳固问题2:不晦涩问题3:不平安多过程浏览器 最新chrome版本架构 浏览器过程渲染过程(n+)GPU过程网络过程插件过程(n+)问题: 更高的资源占用更简单的体系架构将来面向服务的架构(SOA)TCP协定:如何保障页面文件能被残缺送达浏览器?FP(First Paint):是指从页面加载到首次开始绘制的时长。网络加载速度间接影响FP指标。IP:计算机的地址,拜访任何网站实际上只是你的计算机向另外一台计算机申请信息。 传输过程: 下层将含有“极客工夫”的数据包交给网络层;网络层再将IP头附加到数据包上,组成新的IP数据包,并交给底层;底层通过物理网络将数据包传输给主机B;数据包被传输到主机B的网络层,在这里主机B拆开数据包的IP头信息,并将拆开来的数据局部交给下层;UDP:用户数据包协定(User Datagram Protocol),把数据包送达应用程序 传输过程: 下层将含有“极客工夫”的数据包交给传输层;传输层会在数据包前边附加上UDP头,组成新的UDP数据包,再将新的UDP数据包交给网络层;网络层再将IP头附加到数据包上,组成新的IP数据包,并交给底层;数据包被传输到主机B的网络层,在这里主机B拆开IP头信息,并将拆开来的数据局部交给传输层;在传输层,数据包中的UDP头会被拆开,并依据UDP中所提供的端口号,把数据局部交给下层应用程序;UDP传输不能保证数据的可靠性,对于谬误的数据包,UDP并不提供重发机制,只是抛弃以后包;然而传输速度却十分快。IP通过IP地址信息把数据包发送给制订的电脑,而UDP通过端口号把数据包分发给正确的程序。TCP:传输控制协议(Transmission Control Protocol),把数据残缺的送达应用程序 TCP是一种面向连贯的、牢靠的、基于字节流的传输层通信协议。特点: 对于数据包失落的状况,TCP提供重传机制;TCP引入了数据包排序机制,用来保障把乱序的数据包组合成一个残缺的文件。传输过程: 首先,建设连贯阶段。这个阶段是通过“三次握手”来建设客户端和服务器之间的连贯。TCP提供面向连贯的通信传输。面向连贯是指在数据通讯之前先做好两端之间的筹备工作。所谓三次握手,是指建设一个TCP连贯时,客户端和服务器总共要发送三个三个数据包以确认连贯的建设。其次,传输数据阶段。在该阶段,接管方须要对每个数据包进行确认操作。也就是接收端在接管到数据包之后,须要发送确认数据包给发送端。所以当发送端发送一个数据包之后,在规定的工夫内没有收到接收端反馈的确认音讯,则判断为数据失落,并触发发送端的重发机制。同样,一个大的文件在传输过程中会被拆分为很多小的数据包,这些数据包送达到接收端后,接收端会依照TCP头中的序号为其排序,从而保障组成残缺饿数据。最初,断开连接阶段。数据传输结束后,就要停止连贯了,波及到最初一个阶段“四次挥手”来保障单方都能断开连接。总结 互联网中的数据是通过数据包来传输的,数据包在传输过程中容易失落和出错。IP负责把数据包送达目标主机。UDP负责把数据包送达具体利用。而TCP保障了数据残缺地传输,它的连贯分为三个阶段:建设连贯、传输数据和断开连接。

January 16, 2023 · 1 min · jiezi

关于javascript:关于-Angular-开发时对主流浏览器支持的话题

现实状况下,一个 Angular 利用将在客户应用的任何浏览器中对立出现。 然而,Web 浏览器并不都反对雷同的 Web 规范,它们也不以雷同的形式解决这些规范。 例如,有不同的形式来解释规范的标准,进行设计决策。这些不同的设计决策形式,会导致不同的后果,以及呈现一些只有在某种浏览器上能力重现的谬误。 对于受反对的每个浏览器,都会产生包含 QA、架构决策和技术决策在内的施行工作。 总之,Angular 开发人员必须在提供杰出的 Web 页面体验和尽可能多地反对现有的不同 Web 浏览器之间获得均衡。 Spartacus 旨在利用最新的网络平台规范,同时还容许您在尽可能多的不同网络浏览器中运行您的 Spartacus 店面。 然而,一些较旧的浏览器不反对最新规范,因而,Spartacus 不反对这些浏览器。 Spartacus 积极支持 常青浏览器(evergreen browsers),这意味着对常青浏览器进行了端到端测试和手动 QA. Evergreen 浏览器是主动降级到将来版本的 Web 浏览器,而不是通过散发新版本(例如,在操作系统更新中)进行更新。 Spartacus 只反对常绿浏览器,因为 Spartacus 遵循规范的 Angular,Spartacus 库通过无意防止库代码中的 browser quirks 来放弃尽可能洁净,并且没有打算投资于十分旧的浏览器的自动化测试。 只管 Spartacus 可能不反对较旧的浏览器,但有一些罕用技术能够反对这些浏览器。 以下是您能够采取的一些步骤,让旧版浏览器与 Spartacus 一起工作: 配置 TypeScript 编译器以转换为适当版本的 JavaScript。增加 JavaScript polyfill 以提供一些旧浏览器中不蕴含的 Web 性能。利用 PostCSS(主动)在浏览器未蕴含 CSS 规范语法的中央增加供应商前缀款式规定。

January 16, 2023 · 1 min · jiezi

关于javascript:APP内软键盘遮挡输入框解决方案

APP内软键盘遮挡输入框解决方案:1、IOS无奈弹起体现偶发,整体成果可承受;2、Android上分X5内核和原生内核别离解决,但在收起键盘时未开展,体现为键盘弹起状态,故须要从新设置款式;3、X5内核监听resize事件,从新设置款式触发页面绘制;4、原生内核只触发了一次resize办法(猜想是webview团队对其进行了拦挡),故须要依附端提供的计划 addListentNewHeightCallback 进行款式设置; /** * 监听输入框的软键盘弹起和收起事件,并执行页面款式和滚动操作 */export const keyboardDeal = () => { // 软键盘解决 let timer1: number | undefined let timer2: number | undefined let keyboardHeight = 0 const originHeight = window.screen.availHeight function listenKeyboard () { if (isIOS()) { // IOS 键盘:通过判断获取焦点的元素是否为输入框,得悉键盘弹出状态(键盘收起时,同时失去焦点) // TODO: 因为IOS webview大小未修改,故批改款式也无成果 // window.addEventListener('focusin', (e) => { // // @ts-ignore 须要思考元素属性 contenteditable disabled等 // if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { // keyboardPopup(e.target) // } else { // keyboardStowed(e.target) // } // }, { passive: false }) } else { // Andriod 键盘:Andriod 键盘弹起或收起页面高度会发生变化,以此为根据获知键盘收起 window.addEventListener('resize', function () { const resizeHeight = window.innerHeight if (resizeHeight < originHeight) { keyboardPopup(document.activeElement) } else { keyboardStowed(document.activeElement) } }, false) } } listenKeyboard() // 键盘弹出 function keyboardPopup (ele: any) { timer1 = setInterval(() => { const newKeyboardHeight = originHeight - window.innerHeight if (keyboardHeight !== newKeyboardHeight) { keyboardHeight = newKeyboardHeight return } if (keyboardHeight > 0) { clearInterval(timer1) document.documentElement.style.height = window.innerHeight + 'px' ele.scrollIntoViewIfNeeded(true) } }, 100) } // 键盘收起 function keyboardStowed (ele: any) { timer2 = setInterval(() => { keyboardHeight = originHeight - window.innerHeight if (keyboardHeight === 0) { clearInterval(timer2) document.documentElement.style.height = '100%' document.documentElement.scrollTo(0, window.innerHeight) // ele.scrollIntoViewIfNeeded(true) } }, 100) } // 原生回调监听键盘开展收起(该办法仅在Android手APP内且下载x5内核失败的状况下调用) window.addListentNewHeightCallback = (height: number) => { // 适配逻辑 const inputEle = document.activeElement if (window.innerHeight > height) { document.documentElement.style.height = height + 'px' inputEle && inputEle.scrollIntoView() } else { document.documentElement.style.height = '100%' } }}

January 16, 2023 · 2 min · jiezi

关于javascript:YonBuilder-应用构建教程之移动端扩展

YonBuilder 挪动端扩大在上一篇文章中,咱们通过对员工信息实体的挪动端页面构建来对 YonBuilder 挪动端配置的根底流程进行了简略的介绍,本篇文章则通过之前搭建的出入库实体来进行扩大,次要介绍如何在挪动端中增加跳转页面的性能以及通过函数实现自定义配置的办法。一、页面构建创立挪动端页面有两种形式:一种是在创立 PC 端页面时勾选同时生成挪动端,而另一种则是如下图操作在有需要时选中具体页面增加挪动端。因为此前搭建的出入库利用中不须要应用挪动端页面,因而本次通过增加挪动端的形式为之前的页面增补对应的挪动端。 通过增加挪动端的形式,咱们领有了每个独自页面对应的挪动端页面,但此时每一个独自的挪动端页面内的所有跳转是只包含一个列表以及它对应的详情页信息的。如果想要将这些页面都汇总在一个页面上,则须要新建一个挪动端页面,汇聚所有的出库、入库、库存等信息的跳转入口。与 PC 端页面创立统一,想要新建挪动端页面同样须要先创立一个配套的实体。这里咱们新增一个名为主页面的实体,因为咱们须要的是一个空页面,因而字段这里能够不进行配置。在页面建模中,选中单据中的空页面模板来进行创立,并勾选生成挪动端。最终,会失去如图所示的一个空白挪动端页面。 二、跳转性能新建页面之后进入页面进行编辑,能够看到此时是一个空白的页面,接下来通过从左侧拖拽组件到画布上来实现页面的疾速编辑。因为这里想要做的是一个能够跳转到各页面的汇总页,因而拖拽几个按钮在画布上用于减少跳转页面性能,将按钮拖拽至画布上后,能够通过右侧的属性与款式面板来对其进行批改。在对按钮的属性及款式进行批改之后,能够通过右侧的动作面板对其跳转属性进行配置。选中按钮之后,在右侧的面板中抉择单击事件,执行前端动作中的跳转页面接口。   其中,在最初一步须要填写的想要跳转的页面的单据类型以及单据号,这些信息能够在跳转页面的属性栏中获取。这里要留神的是此处咱们跳转的是其余单据对应的挪动端页面,如果想要跳转本单据中的子页面,则在前端接口处抉择调用显示子页面接口即可。三、自定义配置在动作面板中咱们能够对组件触发的事件进行自定义的扩大,设置对应的脚本或者命令等。入选中一个组件后,咱们能够在右侧的动作面板中查看该组件反对的事件,例如选中日期抉择组件后会对应显示 6 个罕用事件。同时,选中页面也会呈现对应的事件,包含页面初始化、加载实现等。   对于任意一个罕用事件都能够进行 4 种操作形式,刚刚在前文的跳转性能中应用的是前端动作,除此之外,还包含前端函数、后端函数以及执行命令三局部。如果选中执行命令,则与前端动作相似,执行零碎预置的命令;而选中前端函数或后端函数,则须要编辑相应的脚本。进入脚本编辑器能够看到左侧预置了局部挪动端罕用的脚本,其余的配置形式皆与 PC 端保持一致。 除了做为根底的 PC 端配套利用,YonBuilder 挪动端通过自定义扩大的形式能够实现多种延展的性能,包含 OCR 辨认、一键打卡、蓝牙打印等等。更多挪动端案例能够返回官网教程如果有任何疑难,欢送在评论区交换探讨哦! 

January 16, 2023 · 1 min · jiezi

关于javascript:组件注册与画布渲染

接着可视化搭建的实践形象,咱们开始勾画一个具体的 React 可视化搭建器。 精读如果咱们将可视化搭建整体定义为 <Designer>,那么 API 可能是这样的: <Designer componentMetas={[]} componentTree={} />componentMetas: 定义组件元信息的数组。componentTree: 定义组件树结构。只有注册了组件元信息与组件树,可视化搭建的画布就能够渲染进去了,这很好了解。 咱们先看组件树如何定义: 组件树组件树里有各组件的实例,那么最好的设计是,组件树与组件实例构造是同构的,称为 ComponentInstance - 组件实例: { "componentName": "container", "children": [ { "componentName": "text", "props": { "name": "我是一个文本组件" } } ]}下面的构造既能够当做单个组件的 组件实例信息,也能够认为是一个 组件树,也就是组件树的任何组件节点都能够拎进去成为一个新组件树,这就是同构的含意。 咱们定义了最最根底的组件树结构,当前所有性能都基于这三个因素来拓展: componentName: 组件名,形容组件类型,比方是个文本、图片还是表格。props: 该组件实例的所有配置信息,透传给组件 props。children: 子组件,类型为 ComponentInstance[]。每一个概念都不可或缺,让咱们从概念必要性再剖析一下这三个属性: componentName: 必须领有的属性,否则怎么渲染该节点都无从谈起。所以相应的,咱们须要组件元信息来定义每个组件名应该如何渲染。props: 即使是雷同组件名的不同实例,也可能领有不同配置,这些配置放在 props 里足够了,没必要开额定的其余属性存储各种各样的业务配置。children: 实践上能够合并到 props.children,但因为子组件概念太常见,倡议 children 与 props.children 这两种地位同时反对,同时定义时,前者优先级更高。除此之外,还有一个可选属性 componentId,即组件惟一 ID。咱们从可选性与必要性两个角度剖析一下这个属性: componentId 的可选性:组件实例在 组件树的门路 就是人造的组件惟一 ID,比方下面的文本组件的组件惟一 ID 能够认为是 children.0。componentId 的必要性:用组件树门路代替组件惟一 ID 的害处是,组件在组件树上挪动后其唯一性就会隐没,此时就要用上 componentId 了。一个好的可视化搭建实现是反对 componentId 的可选性。 ...

January 16, 2023 · 3 min · jiezi

关于javascript:20个你可能不知道的Git命令

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。如果你已经浏览过git手册(或运行man git),那么你会留神到git的内容比咱们大多数人日常应用的多得多。这些命令中有很多是十分弱小的,能够让你的生存变得更轻松(其余的则有点小众,但还是要晓得的)。 这篇文章概述了我最喜爱的20个不罕用的git性能,你能够应用它们来晋升你的开发过程,给共事留下深刻印象,帮忙你答复git面试问题,最重要的是 - 让你有乐趣!Git Web运行 git instaweb 能够立刻在 gitweb 中浏览你的工作存储库。Git有一个内置的web-based visualiser的可视化工具,用于浏览本地仓库,让你通过浏览器的GUI来查看和治理你的仓库。它有很多有用的性能,包含。 浏览和浏览修订版,查看差别、文件内容和元数据直观地查看提交日志、分支、目录、文件历史和附件数据生成提交和版本库流动日志的RSS或Atom feeds搜寻提交、文件、更改和差别要关上它,只需在你的版本库中运行git instaweb。你的浏览器应该弹出,并加载http://localhost:1234。如果你没有装置Lighttpd,你能够用-d标记指定一个代替的网络服务器。其余选项能够通过标记(比方-p示意端口,-b示意浏览器关上,等等),或者在你的git config中的[instaweb]块下配置。 还有git gui命令,它能够关上一个基于GUI的git利用 Git Notes应用git notes为提交增加额定信息有时您须要为一个 git 提交附加额定的数据(不仅仅是更改、音讯、日期工夫和作者信息)。 这些正文存储在 .git/refs/notes 中,因为它与提交对象数据离开,您能够随时批改与提交相干的正文,而不会扭转 SHA-1 哈希值。 你能够用git log、大多数git GUI应用程序或git notes show命令来查看正文。一些git主机也在提交视图中显示正文(只管GH不再显示正文)。 Git Bisect应用git bisect,您能够通过二进制搜寻找到引入谬误的提交。 这是最弱小但又最容易应用的git命令之一--当波及到调试时,bisect相对是个救星。启动bisect后,它为你查看提交,你通知它该提交是好的(没有bug),还是坏的(引入了bug),这能够让你放大呈现bug的最早的提交。 要开始工作,先运行git bisect start,而后用git bisect good <commit-hash>传递一个已知的好的提交,用git bisect bad <optional-hash>传递一个已知的坏的提交(默认为以后)。而后它将查看好的和坏的提交之间的提交,而后你用git bisect good或git bisect bad来指定谬误是否存在。而后它将反复这个过程,在坏和好的两头查看出一个提交,始终到你找到引入该谬误的确切提交。用git bisect reset随时勾销。 bisect命令还有很多内容,包含重放、查看提交、跳过,所以下次调试的时候值得看看文档。 Git Grep》 应用git grep来搜寻代码、文件、提交或其余任何货色,逾越你的 repo 有没有发现自己须要在git我的项目的任何中央搜寻一个字符串?应用git grep,您能够轻松地在整个我的项目中搜寻任何字符串或RegEx,也能够跨分支搜寻(就像一个更弱小的Ctrl + F!)。 git grep <regexp><ref></p><p>它包含很多选项来放大搜寻范畴,或指定后果格局。例如,应用 -l 只返回文件名,-c 指定每个文件的匹配数量,-e 排除符合条件的后果,--and 指定多个条件,-n 用行号搜寻。 ...

January 16, 2023 · 2 min · jiezi

关于javascript:热点面试题-consolelog-同异步问题

前言极度投入,深度沉迷,边界清晰 前端小菜鸡一枚,分享的文章纯属个人见解,若有不正确或可待探讨点可随便评论,与各位同学一起学习~ 欢送关注 『前端进阶圈』 公众号 ,一起摸索学习前端技术...... 公众号回复 加群 或 扫码, 即可退出前端交流学习群,长期交流学习...... 公众号回复 加好友,即可添加为好友 热点面试题:console.log()同异步问题?eg: var a = {index: 1,};// 而后console.log(a);// 再而后a.index++;以上代码在 开发者工具控制台 和 浏览器控制台 的输入状况: 开发者工具控制台浏览器控制台 开展前:开展后Q: 为什么会呈现这个异样输入呢?R:集体认为,在开发者工具控制台 和 浏览器控制台输入后果是不同的,次要起因是在类型上。 在 js 中对象是援用类型,每次应用对象时,都只是应用了对象在堆内存的援用。前述代码,在批改 a.index++后,a 在堆内存中 index 值其余变成了 2,当不开展看的时候,console.log() 打印的是对象过后的快照,所以咱们看到的 index 值是批改之前的 1,当开展对象时,它实际上是从新去堆内存中读取对象的属性值了,因而当开展对象后看到的 index 值为 2。 在 《你不晓得的javascript中卷》 书中,第二局部 异步和性能 -> 第一章 异步:当初与未来 -> 异步控制台 有说起:并没有什么标准或一组需要指定`console.*办法族`如何工作——它们并不是JavaScript正式的一部分,而是由宿主环境(请参考本书的“类型和语法”局部)增加到JavaScript中的。因而,不同的浏览器和JavaScript环境能够依照本人的志愿来实现,有时候这会引起混同尤其要提出的是,在某些条件下,某些浏览器的`console.log(..)`并不会把传入的内容立刻输入。呈现这种状况的次要起因是,在许多程序(不只是JavaScript)中,I/O是十分低速的阻塞局部。所以,(从页面/UI的角度来说)浏览器在后盾异步解决控制台I/O可能进步性能,这时用户甚至可能基本意识不到其产生。上面这种情景不是很常见,但也可能产生,从中(不是从代码自身而是从内部)能够察看到这种状况:var a = {index: 1,};// 而后console.log(a);console.log(a.index);// 再而后a.index+=1;咱们通常认为恰好在执行到 console.log(..) 语句的时候会看到a对象的快照,打印出相似于 { index: 1} 这样的内容,而后在下一条语句 a.index++ 执行时将其批改,这句的执行会严格在a的输入之后。少数状况下,前述代码在 开发者工具的控制台 中输入的对象示意与冀望是统一的。然而,这段代码运行的时候,浏览器可能会认为须要把控制台I/O提早到后盾,在这种状况下,等到 浏览器控制台 输入对象内容时,a.index++可能曾经执行,因而会显示{ index: 2 }。到底什么时候控制台I/O会提早,甚至是否可能被察看到,这都是游移不定的。如果在调试的过程中遇到对象在 console.log(..) 语句之后被批改,可你却看到了意料之外的后果,要意识到这可能是这种I/O的异步化造成的。书中倡议:如果遇到这种少见的状况,最好的抉择是在JavaScript调试器中应用断点,而不要依赖控制台输入。次优的计划是把对象序列化到一个字符串中,以强制执行一次“快照”,比方通过 JSON.stringify(..)。 ...

January 15, 2023 · 1 min · jiezi

关于javascript:用JS重构了一个K线图小组件支持桌面移动端全平台适配

dsxkline纯JS(ES5)语言进行开发,简直完满适配所有浏览器平台(ie678除外),挪动端桌面端混合开发媲美原生体验! dsxkline 反对基本功能,滚动缩放滑动分页实时刷新,反对MA,BOLL、VOL、KDJ、MACD、RSI、WR、CCI、BIAS、PSY等指标 反对支流开发平台 android,ios,flutter,web,h5,c#等 目前已开源SDK JS:dsxkline/dsxkline_js iOS:dsxkline/dsxkline_iphone Android: dsxkline/dsxkline_android C#: dsxkline/dsxkline_net Flutter: dsxkline/dsxkline_flutter python: dsxkline_python 预览 开始<script src="http://www.dsxkline.com/dsx.kline.js></script>创立K线图<div id="kline"></div>var c=document.getElementById("kline"); var kline = new dsxKline({ element:c, onLoading:function(o){ // 开始申请加载数据 }, nextPage:function(data,index){ // 开始申请加载下一页数据 }, onCrossing:function(data,index){ // 十字线挪动数据 }, updateComplate:function(){ // 实现K线一次更新 }});更新K线图kline.update({ chartType:dsxConfig.chartType.timeSharing, //theme:"dark", candleType:dsxConfig.candleType.hollow, zoomLockType:dsxConfig.zoomLockType.right, isShowKlineTipPannel:false, sides:kline.chartType<=1?["VOL"]:["VOL","MACD"], datas:data,});kline.finishLoading();刷新最新数据// 周期 cycle=t,d,w,m,y,m1,t5 别离代表 分时,日K,周K,年K,1分钟,五日// data为最初一根K线数据,数据结构 分时图=[日期,工夫,价格,成交量,成交额] K线图=[日期,开,高,低,收,成交量,成交额] 分钟K线=[日期,工夫,开,高,低,收,成交量,成交额]kline.refreshLastOneData(data,cycle);属性属性名称类型必须默认值备注theme主题string否whitewhite,darkchartType图标类型int否0分时图=0,五日=1,k线图=2market交易所string否shsh,sz,bj,hk,uscandleType蜡烛图类型int否0空心=0 实心=1dpr屏幕dprfloat否2主动适配element画布对象dom是 width宽度float否画布宽度默认跟element适配height高度float否画布高度默认跟element适配paddingTop顶部间距float否20 paddingMiddle主副图间距float否20 paddingBottom底部间距float否1 autoSize主动大小boolean否false为true依据element主动适应datas数据int否null查看数据标准lastClose昨收int否null以后股票昨日收盘价mobileCross十字线挪动端接管boolean否false须要挪动端实现十字线时启用onCrossing滑动十字线回调function否0返回十字线以后数据zoomstep缩放步长float否0.5每次缩放多少像素zoomMin放大最小值float否3 zoomMax放大最大值float否50 zoomLockType缩放类型int否21=左,2=中,3=右,4=追随鼠标mobileZoom缩放手势挪动端接管boolean否false挪动端实现缩放时启用sides副图指标array否["MA"]反对指标 MA,BOLLmain主图指标array否["VOL"]反对指标 VOL,MACD,KDJ,RSIsideHeight副图高度float否height*20%默认为高度的20%mainHeight主图高度float否 debugdebug模式boolean否false nextPage加载下一页function否0滚动到最右边的时候加载下一页数据rightEmptyKlineAmount左边空数据int否0默认图表左边空出多少根K线onLoading开始加载回调function否0初始化加载数据,首次申请数据须要定义在此updateComplate更新实现回调function否0图表实现一次更新完结timePeriod交易时间段string否9:30-11:30,13:00-15:00为空启用零碎内置isShowKlineTipPannel显示内置K线提醒面板boolean否true自主实现K线数据提醒请敞开page页码int否1加载下一页数据时须要传入页码theend滚动到止境boolean否false下一页没有数据须要标记为true配置 dsxConfigk线图表类型// k线图表类型dsxConfig.chartType = { timeSharing:0, // 分时图 timeSharing5:1, // 五日分时图 candle:2, // K线图}蜡烛图空心实心// 蜡烛图实心空心dsxConfig.candleType = { hollow:0, // 空心 solid:1 // 实心}缩放K线锁定类型// 缩放K线锁定类型dsxConfig.zoomLockType = { left:1, // 锁定右边进行缩放 middle:2, // 锁定两头进行缩放 right:3, // 锁定左边进行缩放 follow:4, // 追随鼠标地位进行缩放,web版成果比拟好}交易所类型及其交易工夫// 交易所类型及其交易工夫dsxConfig.market = { sh:"9:30-11:30,13:00-15:00", // 上海 sz:"9:30-11:30,13:00-15:00", // 深圳 bj:"9:30-11:30,13:00-15:00", // 北京 hk:"9:30-12:00,13:00-16:00", // 港股 us:"9:30-12:00,12:00-16:00", // 美股 fu:"9:30-12:00,12:00-16:00", // 期货 sp:"9:30-12:00,12:00-16:00", // 现货 wh:"9:30-12:00,12:00-16:00", // 外汇}指标配置// 指标配置dsxConfig.index = { VOL:{ // 显示名称 title:"成交量", // 参数配置值 value:{VOL:0,MA5:5,MA10:10}, // 画线配置 draw:{VOL:{model:"column",color:"CLOSE",hiddenTitle:true},MA5:{model:"line",color:"#FFA500"},MA10:{model:"line",color:"#87CEFA"}}, // 反对的图形 chartType:[dsxConfig.chartType.timeSharing,dsxConfig.chartType.timeSharing5,dsxConfig.chartType.candle], // 反对的图表地位 主图 main,副图 sides location:['sides'] }, TMA:{ title:"", value:{"均价":1}, draw:{ "均价":{model:"line",color:"#FFA500"},"新值":{model:"text",color:"",colorValue:0}}, chartType:[dsxConfig.chartType.timeSharing,dsxConfig.chartType.timeSharing5], location:['main'] }, MA:{ title:"均线", value:{ MA5:5, MA10:10, MA30:30,MA60:60}, draw:{ MA5:{model:"line",color:"#FFA500"}, MA10:{model:"line",color:"#87CEFA"}, MA30:{model:"line",color:"#BA55D3"},MA60:{model:"line",color:"#808000"},}, chartType:[dsxConfig.chartType.timeSharing,dsxConfig.chartType.timeSharing5,dsxConfig.chartType.candle], location:['main'] }, MACD:{ title:"MACD(26,9,12)", value:{DIFF:0,DEA:0,MACD:0,long:26,d:9,short:12}, draw:{DIFF:{model:"line",color:"#FFA500"},DEA:{model:"line",color:"#87CEFA"}, MACD:{model:"column",color:"#BA55D3"}}, chartType:[dsxConfig.chartType.timeSharing,dsxConfig.chartType.timeSharing5,dsxConfig.chartType.candle], location:['sides'] }, KDJ:{ title:"KDJ(9,3,3)", value:{K:9,D:3,J:3}, draw:{K:{model:"line",color:"#FFA500"},D:{model:"line",color:"#87CEFA"},J:{model:"line",color:"#BA55D3"}}, chartType:[dsxConfig.chartType.candle], location:['sides'] }, BOLL:{ title:"BOLL(20,2)", value:{UP:0,MID:0,LOW:0,N:20,M:2}, draw:{UP:{model:"line",color:"#FFA500"},MID:{model:"line",color:"#87CEFA"}, LOW:{model:"line",color:"#BA55D3"}}, chartType:[dsxConfig.chartType.candle], location:['main'] }, RSI:{ title:"RSI(6,12,24)", value:{RSI6:6,RSI12:12,RSI24:24}, draw:{RSI6:{model:"line",color:"#FFA500"},RSI12:{model:"line",color:"#87CEFA"}, RSI24:{model:"line",color:"#BA55D3"}}, chartType:[dsxConfig.chartType.timeSharing,dsxConfig.chartType.timeSharing5,dsxConfig.chartType.candle], location:['sides'] }, WR:{ title:"WR(6,10)", value:{WR6:6,WR10:10}, draw:{WR6:{model:"line",color:"#FFA500"},WR10:{model:"line",color:"#87CEFA"}}, chartType:[dsxConfig.chartType.candle], location:['sides'] }, BIAS:{ title:"BIAS(6,12,24)", value:{BIAS6:6,BIAS12:12,BIAS24:24}, draw:{BIAS6:{model:"line",color:"#FFA500"},BIAS12:{model:"line",color:"#87CEFA"}, BIAS24:{model:"line",color:"#BA55D3"}}, chartType:[dsxConfig.chartType.candle], location:['sides'] }, CCI:{ title:"CCI(14)", value:{CCI14:14}, draw:{CCI14:{model:"line",color:"#FFA500"}}, chartType:[dsxConfig.chartType.candle], location:['sides'] }, PSY:{ title:"PSY(12,6)", value:{PSY:12,PSYMA:6}, draw:{PSY:{model:"line",color:"#FFA500"},PSYMA:{model:"line",color:"#87CEFA"}}, chartType:[dsxConfig.chartType.candle], location:['sides'] },}主题配置// 主题配置dsxConfig.theme = { white:{ backgroundColor:"#ffffff", // 背景色彩 color:"#333333",// 字体色彩 fontSize:window.devicePixelRatio<=1?12:10,// 字体大小 redColor:"#F44336",// 蜡烛图红色 greenColor:"#4CAF50",// 蜡烛图绿色 crossLineColor:"#2196F3",// 十字线色彩 crossLineWidth:1.0,// 十字线宽度 fontBgColor:"#2196F3", // 文字背景色彩 十字线提醒的文字背景色彩 gridLineColor:"#eeeeee",// 网格线色彩 gridLineCount:3,// 网格线数量 gridLineWidth:1.0,// 网格线的宽度 lineWidth:1.0, // 线条的大小 指标线条的大小 klineWidth:10,// 一根k线的默认宽度 klinePadding:1,// k线之间的距离 timeSharingLineColor:"#2196F3",// 分时图价格线的色彩 timeSharingLineFillColor:"rgba(65,105,225,0.1)", // 分时图价格线区域填充色彩 }, dark:{ backgroundColor:"rgba(19, 23, 34, 1)", // 背景色彩 color:"#c5cbce",// 字体色彩 fontSize:window.devicePixelRatio<=1?12:10,// 字体大小 redColor:"#F44336",// 蜡烛图红色 greenColor:"#4CAF50",// 蜡烛图绿色 crossLineColor:"#2196F3",// 十字线色彩 crossLineWidth:1.0,// 十字线宽度 fontBgColor:"#2196F3", // 文字背景色彩 gridLineColor:"#191b28",// 网格线色彩 gridLineCount:3,// 网格线数量 gridLineWidth:1.0,// 网格线的宽度 lineWidth:1.0, // 线条的大小 指标线条的大小 klineWidth:10,// 一根k线的默认宽度 klinePadding:1,// k线之间的距离 timeSharingLineColor:"#2196F3",// 分时图价格线的色彩 timeSharingLineFillColor:"rgba(65,105,225,0.1)", // 分时图价格线区域填充色彩 }}图表数据格式分时图数组 ["日期,工夫,报价,成交量,成交额"]["20220301,0930,3001.23,453999595,233944858","20220301,0931,3001.23,453999595,233944858","20220301,0932,3001.23,453999595,233944858",]五日分时图数组 ["日期,工夫,报价,成交量,成交额"],相当于间断五天的分时图数据["20220301,0930,3001.23,453999595,233944858","20220301,0931,3001.23,453999595,233944858","20220301,0932,3001.23,453999595,233944858",..."20220302,0930,3001.23,453999595,233944858","20220302,0931,3001.23,453999595,233944858","20220302,0932,3001.23,453999595,233944858",..."20220303,0930,3001.23,453999595,233944858","20220303,0931,3001.23,453999595,233944858","20220303,0932,3001.23,453999595,233944858",..."20220304,0930,3001.23,453999595,233944858","20220304,0931,3001.23,453999595,233944858","20220304,0932,3001.23,453999595,233944858",..."20220305,0930,3001.23,453999595,233944858","20220305,0931,3001.23,453999595,233944858","20220305,0932,3001.23,453999595,233944858",]K线图数组 ["日期,开盘价,最高价,最低价,收盘价,成交量,成交额"]["20220301,3001.23,3030.21,2989.3,3002.4,453999595,233944858","20220302,3001.23,3030.21,2989.3,3002.4,453999595,233944858","20220303,3001.23,3030.21,2989.3,3002.4,453999595,233944858",]分钟K线图数组 ["日期,工夫,开盘价,最高价,最低价,收盘价,成交量,成交额"]["20220301,0930,3001.23,3030.21,2989.3,3002.4,453999595,233944858","20220302,0931,3001.23,3030.21,2989.3,3002.4,453999595,233944858","20220303,0932,3001.23,3030.21,2989.3,3002.4,453999595,233944858",]

January 14, 2023 · 2 min · jiezi

关于javascript:Js高级API

Decorator装璜器针对属性 / 办法的装璜器 // decorator 内部能够包装一个函数,函数能够带参数 function Decorator (type) { /** * 这里是真正的decorator * @description: 装璜的对象的形容对象 * @target:装璜的属性所述类的原型,不是实例后的类。如果装璜的是Animal的某个属性,这个target就是Animal.prototype * @name 装璜的属性的key */ return function (target, name, desciptor) { // 因为babel的缘故 通过value并不能获取值,以此能够获取实例化的时候此属性的默认值 let v = desciptor.initializer && desciptor.initializer.call(this) // 返回一个新的形容对象,或者间接批改desciptor也能够 return { enumerable: true, //能够遍历 configurable: true, //能够删除 get: function () { return v }, set: function (c) { v = c } } } } // 下面的不能和业界商用的Decorator混用 function Check (type) { return function (target, name, desciptor) { let v = desciptor.initializer && desciptor.initializer.call(this) // 将属性名字以及须要的类型的对应关系记录到类的原型上 if (!target.constructor._checkers_) { // 将这个暗藏属性定义成no enumerable,遍历的时候是取不到的 Object.defineProperty(target.constructor, '_checkers_', { value: {}, enumerable: false, writable: true, configurable: true }) } target.constructor._checkers_[name] = { type: type } return desciptor } } // 装璜函数的第一个参数 target 是包装属性所属的类的原型(prototype) // 也就是把对应关系挂载到了开发定义的子类上。vue中应用Decoratorts开发肯定对vue-property-decorator不会感到生疏,这个插件提供了许多装璜器在methods外面的办法下面应用装璜器,这时候装璜器的target对应的是methods。能够在生命周期钩子函数下面应用装璜器,这时候target对应的是整个组件对象。 import {log,confirmation} from "./test" methods: { @log() name() { console.log("获取数据"); }, @confirmation('此操作将永恒删除文件,是否持续?') deleteFile(data){ //删除文件操作 } }, mounted () { this.name() }test.js ...

January 13, 2023 · 3 min · jiezi

关于javascript:JavaScript-中-find-和-filter-方法的区别

JavaScript 在 ES6 上有很多数组办法,每种办法都有独特的用处和益处。 在开发应用程序时,大多应用数组办法来获取特定的值列表并获取单个或多个匹配项。 在列出这两种办法的区别之前,咱们先来一一理解这些办法。 JavaScript find() 办法ES6 find() 办法返回通过测试函数的第一个元素的值。如果没有值满足测试函数,则返回 undefined。 语法以下语法中应用的箭头函数。 find((element) => { /* ... */ } )find((element, index) => { /* ... */ } )find((element, index, array) => { /* ... */ } )咱们有一个蕴含名称 age 和 id 属性的用户对象列表,如下所 let users = [{ id:1, name: 'John', age: 22}, { id:2, name: 'Tom', age: 22}, { id:3, name: 'Balaji', age: 24}];以下代码应用 find() 办法查找年龄大于 23 的第一个用户。 console.log(users.find(user => user.age > 23));//console//{ id: 3, name: 'Balaji', age:24}当初咱们要找到第一个年龄为 22 的用户 ...

January 13, 2023 · 1 min · jiezi

关于javascript:JS字符串表达式解析常用方法

简介比方咱们有一段字符串: var code = "obj['count'].value+10"而已知obj内容如下: var obj={ count:{ value:7 }}当然,表达式code可能是参数,下面的例子只是一种可能,如何求解code运算后的值?借助这里的办法就非常容易实现了。 当然,除了表达式的解析,还包含对象属性值的设置与获取。 本工具自身是平台无关的,能够在所有反对JS和TS的环境中应用,包含H5、各种小程序、uni-app等。 舒适提醒:应用中如果遇到任何问题,都能够点击此处给咱们提Issue。 引入你须要执行上面的装置命令: npm install --save jsdoor而后在须要应用中央引入: import { evalExpress, getValue, setValue } from 'jsdoor/value/index.js';应用evalExpress在指定对象target上求解表达式express的值: 语法var value=evalExpress(target, express, scope = {});舒适提醒:一个可选参数scope示意,如果scope有值,会拦挡target,下同。例子当初有个json: var json = { "a": { "b": [1, 2, 3] }}那么执行上面的语句: evalExpress(json, 'a.b[0]-10')后果就是: -9。 getValue获取对象上字符串表达式对应的值: 语法var value=getValue(target, express, scope = {});例子当初有个json: var json = { "a": { "b": [1, { "d": "value" }, 3, 4] }}那么执行上面的语句: getValue(json, '["a"].b')后果就是: [1, { "d": "value" }, 3, 4]。 ...

January 12, 2023 · 1 min · jiezi

关于javascript:Es6中双箭头函数的含义柯里化

const isType =(type: string) => (value: any) => typeof(value) === type;what?在理解双箭头函数之前能够先理解一下函数式编程中的一个概念: 柯里化:把一个多参数函数转化成一个嵌套的一元函数(只有一个参数的函数)的过程。可见双箭头函数就是一个多参数函数的柯里化版本。 转化成JavaScript后: const isType = function (type){ return function (value) { return typeof(value) === type; } }(这样看就有点闭包的意思了,也能够了解为把其中的每一步骤进行封装,保留每一步的后果,作为下一步开始的条件)你也能够写成没有柯里化的函数也是能够的: const isType = function (type,value){ return typeof(value) === type; }它的调用办法: isType (“string”) //返回一个函数:function (value) {return typeOf(value) === type;}isType (“string”)(“abc”) //返回:trueconst type = isType("string"); type("abc"); //返回:true Why?那问题来了,为什么要柯里化呢?它有什么用? 可读性: isType (“string”)(“abc”)可复用性 :重复使用const type = isType(“string”); 用来做其余判断type (“def”);可维护性 : const fn = (a,b) => a * b; //可批改成a+bconst isType =(fn)=> (type) => (value) =>fn(type,value);console.log(isType (fn)(2)); //返回函数 console.log(isType (fn)(2)(3)); //6const type = isType(fn)(2); console.log(type(4)); //8How?应用场景 ...

January 12, 2023 · 1 min · jiezi

关于javascript:验证码逆向专栏某验二代滑块验证码逆向分析

申明本文章中所有内容仅供学习交换,抓包内容、敏感网址、数据接口均已做脱敏解决,严禁用于商业用途和非法用处,否则由此产生的所有结果均与作者无关,若有侵权,请分割我立刻删除! 本文章未经许可禁止转载,禁止任何批改后二次流传,擅自应用本文解说的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】分割作者立刻删除! 逆向指标指标:某验二代滑块验证码逆向剖析主页:aHR0cDovL3d3dy5qc2dzai5nb3YuY246NTg4ODgvbWluaS9uZXR3ZWIvU01MaWJyYXJ5LmpzcA==阐明:大多数逻辑其实和三四代都一样,雷同的就简写了,有纳闷的中央能够看以前的文章【验证码逆向专栏】某验三代滑块验证码逆向剖析【验证码逆向专栏】某验四代滑块验证码逆向剖析抓包状况主页点击搜寻就会跳出二代的验证码,netWebServlet.json 的申请,会返回 challenge 和 gt。 有个 get.php 的申请,返回了一个新的 challenge,这个申请之后的操作,都要用这个新的 challenge,不然是验证不胜利的,其余的还有验证码背景图片、乱序图片地址、c、s 等值,之前写过三代的文章,都是相似的,这里就不一一剖析了。 而后是 ajax.php 验证是否通过,通过之后返回一个 validate,申请里同样是须要咱们逆向的 w 参数: 而后同样还是 netWebServlet.json 接口,带上 get.php 申请返回的 challenge 以及 ajax.php 返回的 validate,申请拿到一个 name 的字段。 后续的搜寻数据,带上这个 name 就行了: 逆向剖析搞过三、四代的都晓得咱们能够间接搜寻 w 的 Unicode 值 \u0077 即可定位,然而二代则不是 Unicode,而是16进制的编码,搜寻 \x77 即可定位,当然依照失常流程,跟栈也能很容易找到加密的地位。 获取 H7z 值从上图中能够晓得 w 的值为 r7z + H7z,先看 H7z。 跟进这个办法,来到一大串控制流,这里还是举荐用 AST 还原一下,后续可能有一些循环啥的,硬跟的话容易出错,当然间接全副扣一把梭也是能够的,H7z 的外围其实就是 RSA 加密随机字符串,三代四代都有,这里就不细讲了。 ...

January 12, 2023 · 5 min · jiezi

关于javascript:JS-函数式概念-管道-和-组合

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。函数管道和组合是函数式编程中的概念,当然也能够在JavaScript中实现--因为它是一种多范式的编程语言,让咱们疾速深刻理解这个概念。 这个概念就是依照肯定的程序执行多个函数,并将一个函数的后果传递给下一个函数。 你能够像这样做得很难看: function1(function2(function3(initialArg)))或者应用函数组合: compose(function3, function2, function1)(initialArg);或性能管道: pipe(function1, function2, function3)(initialArg);简而言之,组合和管道简直是一样的,惟一的区别是执行程序;如果函数从左到右执行,就是管道,另一方面,如果函数从右到左执行,就叫组合。 一个更精确的定义是。"在函数式编程中,compose是将较小的单元(咱们的函数)组合成更简单的货色(你猜对了,是另一个函数)的机制"。 上面是一个管道函数的例子。 const pipe = (...functions) => (value) => { return functions.reduce((currentValue, currentFunction) => { return currentFunction(currentValue); }, value); };让咱们来补充一些这方面的见解。 基础知识 咱们须要收集N多的函数同时抉择一个参数以链式形式执行它们,将收到的参数传递给将被执行的第一个函数调用下一个函数,退出第一个函数的后果作为参数。持续对数组中的每个函数做同样的操作。/* destructuring to unpack our array of functions into functions */const pipe = (...functions) => /* value is the received argument */ (value) => { /* reduce helps by doing the iteration over all functions stacking the result */ return functions.reduce((currentValue, currentFunction) => { /* we return the current function, sending the current value to it */ return currentFunction(currentValue); }, value); };咱们曾经晓得,箭头函数如果只返回一条语句,就不须要括号,也不须要返回标签,所以咱们能够通过这样写来缩小键盘的点击次数。 ...

January 12, 2023 · 2 min · jiezi

关于javascript:threejs入门-掉落的甜甜圈实战-大帅老猿threejs特训

随着webGL的热度越来越高,作为一个老前端也想去理解一下,我抉择入门three.js理解一下。 webGL & Three.js 简介WebGL 是一项在浏览器体现 3D 画面的技术。是一种3D绘图规范,容许把JavaScript和OpenGL ES 2.0联合在一起,通过减少OpenGL ES 2.0的一个JavaScript绑定,WebGL能够为HTML5 Canvas提供硬件3D减速渲染(局部计算GPU),这样Web开发人员就能够借助零碎显卡来在浏览器里更流畅地展现3D场景和模型了,还能创立简单的导航和数据视觉化。Three.js(Javascript 3D library),应用JavaScript语言对WebGL进行了封装,让前端开发人员在不须要把握很多数学知识和绘图常识的状况下,也可能轻松进行web 3D开发。 相干文档three.js中文文档收费3D模型下载网站、模型下载blender下载,Blender是一款收费的三维全功能软件.Vite中文文档素材源码下载解决模型在理论我的项目咱们是须要和美术单干的,当然如果你或者你对象懂3d建模就再好不过了。关上资源网站,搜寻模型,关上详情,点击download按钮。应用blender导入模型。应用blender导出glb模型文件。应用vite搭建我的项目。Vite 能帮咱们疾速搭建我的项目。 npm create vite@latestthree.js 基本概念三维的物体要渲染在二维的屏幕上。首先要创立一个场景来搁置物体,那么最终怎么显示三维的内容,就应该找一个相机,将相机放在场景的某个地位,而后想要显示就要把相机拍的内容渲染进去。所以就引出三个基本概念:场景、相机、渲染器。 创立场景const scene = new THREE.Scene();创立相机three.js 中相机分为立方体相机、正交相机、近景相机。这里咱们应用的是近景相机。 构造函数 PerspectiveCamera( fov, aspect, near, far ) fov — 相机视锥体垂直视角aspect — 相机视锥体宽高比near — 相机视锥体近裁剪面far — 相机视锥体远裁剪面。const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10);渲染器three.js 中渲染器分为Canvas渲染器(CanvasRenderer)、WebGL渲染器(WebGLRenderer)这里我应用WebGL渲染器。构造函数 WebGLRenderer( parameters )parameters 是一个可选对象,蕴含用来定义渲染器行为的属性。当没有设置该参数时,将应用默认值。 canvas — 一个用来绘制输入的 Canvas 对象。context — 所用的 渲染上下文(RenderingContext) 对象。precision — 着色器的精度。能够是"highp", "mediump" 或 "lowp". 默认为"highp",如果设施反对的话。alpha — Boolean, 默认为 false.premultipliedAlpha — Boolean, 默认为 true.antialias — Boolean, 默认为 false.stencil — Boolean, 默认为 true.preserveDrawingBuffer — Boolean, 默认为 false.depth — Boolean, 默认为 true.logarithmicDepthBuffer — Boolean, 默认为 false.// 创立渲染器const renderer = new THREE.WebGLRenderer({ antialias: true });// 设置渲染的尺寸大小renderer.setSize(window.innerWidth, window.innerHeight);// 将webgl渲染的canvas内容增加到body中document.body.appendChild(renderer.domElement);光照three.js中光照有以下几种:环境光源(AmbientLight)、点光源(PointLight)、聚光光源(SpotLight)、平行光源(DirectionalLight)、半球光源(HemisphereLight)其中反对暗影的光照有:点光源,聚光灯,平行光源。这里我应用的是半球光源 DirectionalLight( hex, intensity ) ...

January 11, 2023 · 1 min · jiezi

关于javascript:mouseover-和-mouseenter-的区别

mouseover 和 mouseenter 是两种不同的 JavaScript 事件。 mouseover 事件在鼠标指针挪动到元素上方或其子元素上方时触发。 mouseenter 事件则是在鼠标指针进入元素时触发,但不会在其子元素上触发。 举个例子,如果你有一个 div 元素,其中蕴含一个 p 元素,并且为这两个元素都增加了 mouseover 和 mouseenter 事件监听器,当鼠标指针挪动到 p 元素上方时,mouseover 事件会在 div 和 p 元素上同时触发,而 mouseenter 事件只会在 div 元素上触发。 还有一点须要留神的是,mouseover 和 mouseenter 事件有一个重要的区别,就是当鼠标指针从子元素挪动到父元素时,mouseover 事件会在父元素上再次触发,而 mouseenter 事件不会。 例如,如果你有一个 div 元素,其中蕴含一个 p 元素,并且为这两个元素都增加了 mouseover 和 mouseenter 事件监听器,当鼠标指针从 p 元素挪动到 div 元素时,mouseover 事件会在 div 元素上再次触发,而 mouseenter 事件不会。 总的来说,mouseover 事件会在鼠标指针挪动到元素或其子元素上方时触发,并且在鼠标指针从子元素挪动到父元素时会再次触发。而 mouseenter 事件只在鼠标指针进入元素时触发,不会在其子元素上触发,也不会在鼠标指针从子元素挪动到父元素时再次触发。

January 11, 2023 · 1 min · jiezi

关于javascript:Nerdctl-原生支持-Nydus-加速镜像

文|李楠(GitHub ID : @loheagn) 北京航空航天大学 21 级研究生 云原生底层零碎的开发和摸索工作。 本文 6369 字 浏览 16 分钟 OSPP 开源之夏是由中科院软件研究所“开源软件供应链点亮打算”发动并长期反对的一项暑期开源流动。旨在激励在校学生积极参与开源软件的开发保护、促成优良开源软件社区的蓬勃发展、造就和挖掘更多优良的开发者。 这是去年(2022)的开源流动中,李楠同学加入 Nydus 容器开源生态集成课题的相干工作。 | 作者有话说 | 大家好!我是来自北京航空航天大学的 2021 级研究生李楠,对云原生技术很感兴趣,GitHub ID 是 @loheagn。在往年上半年,我加入了 Linux 基金会的秋季实习,实现了 CNCF - Kubevela: Management of Terraform state 我的项目的工作,并因而造就了对开源工作的趣味。在开源之夏 2022 凋谢题目后,我理解到了 Nydus 我的项目,感觉这是一个很酷的我的项目,因为我之前对容器和镜像的底层技术并不是很相熟,感觉这是个很不错的学习机会。于是便尝试投递了简历申请,最终很幸运地通过了筛选,并在严松老师的帮忙下顺利完成了题目。PART. 1 我的项目背景NerdctlNerdctl 是一个对标 Docker CLI 和 Docker Compose 的、用于与 Containerd (当下最风行的容器运行时,Docker 的后端也是调用的 Containerd,通常作为守护过程呈现) 交互的命令行工具。 用户能够像应用 Docker CLI 一样应用 Nerdctl 与 Containerd 进行交互,比方应用 nerdctl pull <image_name> 来拉取镜像、应用 nerdctl run <image_name> 来运行容器等等。 相比于 Containerd 自身提供的 CTR 工具,Nerdctl 默认提供了更敌对的用户体验,并尽量放弃其应用形式与 Docker 统一。对于从 Docker 迁徙到 Containerd 的用户,往往只须要 alias docker=nerdctl 就能够与之前取得统一的应用体验。 ...

January 11, 2023 · 4 min · jiezi

关于javascript:提升代码可读性减少ifelse的几个小技巧

前言置信大家或多或少都接触过领有宏大 if else 的我的项目代码吧,多重嵌套的 if else 在保护的时候真的让人很恼火,有时候一个 bug 排查下来,重大感觉身材被掏空。 本文并未有毁灭或歧视 if else的意思,if else 的好用都晓得,这里只是在某些特定场景为大家额定提供一种思路,减少咱们代码的可读性。 短路运算Javascript 的逻辑或 || 的短路运算有时候能够用来代替一些比较简单的 if else 逻辑或 || 的短路运算:若右边能转成true,返回右边式子的值,反之返回左边式子的值。 上面用一个简略的案例来表述 let cif(a){ c = a} else { c = b}大家看着下面的代码会好受嘛(自己有一丢丢的强迫症),明明就是一个很简略的判断却须要写好几行代码能力实现。这个时候咱们就能够用短路运算去简化咱们的代码啦。 let c = a || b这样看起来是不是就简洁了很多。 三元运算符三元运算符我感觉大家应该都很相熟吧,很多时候简略的一些判断咱们都能够应用三元运算符去代替 if else,这里只举荐 一层 三元运算符,因为多层嵌套的三元运算符也不具备良好的可读性。 例子:条件为 true 时返回1,反之返回0: const fn = (nBoolean) { if (nBoolean) { return 1 } else { return 0 } }// 应用三元运算符const fn = (nBoolean) { return nBoolean ? 1 : 0}三元运算符应用的中央也比拟多,比方:条件赋值,递归... ...

January 10, 2023 · 1 min · jiezi

关于javascript:猎豹浏览器原生js出现各种各样方法未定义的错误解决办法

想不到2023年了还有人会要求兼容猎豹浏览器。 我用原生js写的一个程序,按理来说不该当有兼容性问题,后果页面上报各种办法未定义的谬误 前面忽然想到会不会是因为上一次更新中应用了可选链操作符?.导致的呢 把所有用到?.的中央间接删掉当前,页面体现就失常了

January 10, 2023 · 1 min · jiezi

关于javascript:链表与数组相互转换

最近闲来刷了一些力扣的题,遇到很多链表题,前端切图仔示意一脸懵逼 明明长的和数组一样,数组的所有办法却不能用,遇到链表题的解题思路都是想着转换成数组再解决,毕竟黑猫白猫,抓住老鼠的就是好猫 链表转数组 function listToArray(head) { let arr = [] while (head) { arr.push(head.val) head = head.next } return arr}数组转链表 function arrayToList(arr) { let head = new ListNode(arr[0]) let node = head for (let i = 1; i < arr.length; i++) { node.next = new ListNode(arr[i]) node = node.next } return head}而后回到正题,这里有个ListNode [1,2,3,4],前端儿怎么了解这个[1,2,3,4]? 对应到前端能够用object模仿链表: a={val:1,next:b}b={val:2,next:c}c={val:3,next:d}d={val:4,next:null}能够看进去,其实就是前端的tree型数据,javascript自身并没有链表这个概念,不过能够理解一下,毕竟解题思路根本和咱们解决tree数据的思路是一样的,面试种还是很罕用的,

January 10, 2023 · 1 min · jiezi

关于javascript:评价打分组件SVG-半颗星的解决方案

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。对于一个内容服务的网站来说评估打分也是很重要的一部分,它有利于剖析用户对咱们的内容的爱好程序。最近,咱们团须要为一个我的项目实现一个星级评估的组件,需要如下: 性能(不能用图片)可调整的大小可拜访性小数位打分(如:3.5或3.2)应用 css 就能够间接管制款式要达到下面的要求,常常调研,最终抉择了 SVG 计划。 工作下图是咱们最终想要的成果: 咱们次要的工作就是让星星能够扭转其色彩,描边,大小,还能够显示半颗星星。 实现在实现之前,咱们须要有一个根底 SVG 构造,如下所示: <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <path d="..."/></svg>增加 aria-label增加 aria-label 能够应用读屏器用户可能拜访这一信息。 <p aria-label="Rating is 4.5 out of 5"> <svg width="32" height="32" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <path d="..."/> </svg></p>aria-label属性用来给以后元素加上的标签形容,承受字符串作为参数。是用不可视的形式给元素加label(如果被形容元素存在实在的形容元素,可应用 aria-labelledby 属性作为来绑定形容元素和被形容元素来代替)。如何重用SVG咱们能够把下面的SVG 标签复制五次,或者提取path数据并保留在某个中央,而后在不反复代码的状况下从新应用它。咱们抉择后者。 首先,咱们须要创立一个宽度和高度为零的SVG,这样它就不会保留空间。 <svg width="0" height="0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Content --></svg>在该SVG中,咱们须要在<symbol>元素中蕴含path数据。依据MDN: symbol 元素用于定义图形模板对象,能够通过<use>元素来实例化。<symbol>外面的内容与图标的内容雷同。另外,增加一个 id 也很重要,这样咱们当前就能够援用这个 symbol 。 <svg width="0" height="0" xmlns="http://www.w3.org/2000/svg"> <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="star"> <path d="..."/> </symbol></svg>有了这个设置,咱们当初能够用<use>元素来重用这个symbol。做法就是应用id作为href属性的值。 <p class="c-rate"> <svg class="c-icon" width="32" height="32"> <use href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use href="#star"></use> </svg> <svg class="c-icon" width="32" height="32"> <use href="#star"></use> </svg></p>星星的款式有了下面的星星构造,咱们当初来增加款式: ...

January 10, 2023 · 3 min · jiezi

关于javascript:高级前端常考手写面试题合集

解析 URL Params 为对象let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';parseParam(url)/* 后果{ user: 'anonymous', id: [ 123, 456 ], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型 city: '北京', // 中文需解码 enabled: true, // 未指定值得 key 约定为 true}*/function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来 const paramsArr = paramsStr.split('&'); // 将字符串以 & 宰割后存到数组中 let paramsObj = {}; // 将 params 存到对象中 paramsArr.forEach(param => { if (/=/.test(param)) { // 解决有 value 的参数 let [key, val] = param.split('='); // 宰割 key 和 value val = decodeURIComponent(val); // 解码 val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字 if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则增加一个值 paramsObj[key] = [].concat(paramsObj[key], val); } else { // 如果对象没有这个 key,创立 key 并设置值 paramsObj[key] = val; } } else { // 解决没有 value 的参数 paramsObj[param] = true; } }) return paramsObj;}实现forEach办法Array.prototype.myForEach = function(callback, context=window) { // this=>arr let self = this, i = 0, len = self.length; for(;i<len;i++) { typeof callback == 'function' && callback.call(context,self[i], i) }}设计一个办法提取对象中所有value大于2的键值对并返回最新的对象实现: ...

January 9, 2023 · 17 min · jiezi

关于javascript:从零开始实现一个Promise

1.Promise产生背景及标准家喻户晓,Promise是ES6引入的新个性,旨在解决回调天堂。上面是一个简略的例子:管制接口调用程序: apiA-->apiB-->apiC。简单的业务,开发人员会裂开。后生在此向老前辈致敬。 // 回调天堂apiA({ handleSuccess(resA){ apiB({ handleSuccess(resB){ apiC({ handleSuccess(resC){ } }) } }) }})因而Promise/A+标准应运而生,ES6的Promise就是遵循标准开发进去的。 2. 同步Promise浏览标准可得上面几点根本要求: Promise存在三个状态:pending(期待态)、fulfilled(胜利态)、rejected(失败态)pending为初始态,并能够转化为fulfilled和rejected胜利时,不可转为其余状态,且必须有一个不可扭转的值(value)失败时,不可转为其余状态,且必须有一个不可扭转的起因(reason)new Promise(executor=(resolve,reject)=>{resolve(value)}),resolve(value)将状态置为 fulfillednew Promise(executor=(resolve,reject)=>{reject(reson)}),reject(reson)将状态置为 rejected若是executor运行异样执行reject()thenable:then(onFulfilled, onRejected) onFulfilled:status为fulfilled,执行onFulfilled,传入valueonRejected:status为rejected,执行onRejected,传入reason// 1.Promise存在三个状态:pending(期待态)、fulfilled(胜利态)、rejected(失败态)const STATUS_PENDING = 'pending'const STATUS_FULFILLED = 'fulfilled'const STATUS_REJECTED = 'rejected'class myPromise { constructor(executor) { // pending为初始态,并能够转化为fulfilled和rejected this.status = STATUS_PENDING this.value = '' // 3 this.reason = '' // 4 let resolve = value => { // 5. if (this.status === STATUS_PENDING) { this.status = STATUS_FULFILLED this.value = value } } let reject = reason => { //6. if (this.status === STATUS_PENDING) { this.status = STATUS_REJECTED this.reason = reason } } // 7. try { executor(resolve, reject); } catch (err) { reject(err); } } // 8. then(onFulfilled = () => {}, onRejected = () => {}) { // 8.1 if (this.status === STATUS_FULFILLED) { onFulfilled(this.value) } // 8.2 if (this.status === STATUS_REJECTED) { onRejected(this.reason) } }}new myPromise(resolve => { console.log('before resolve') resolve(1)}).then(res => { console.log(res)})new myPromise((resolve, reject) => { console.log('before reject') reject('reject error')}).then(res => { console.log(res)}, error => { console.log(error)})3. 异步Promisenew myPromise(resolve => { console.log('before resolve') setTimeout(()=>{ resolve(1) },1000)}).then(res => { console.log(res)})promise的状态只能在resolve或者reject的时候扭转,同步代码执行到then回调的时候promise的状态还是pending,明细不合乎咱们的冀望。 ...

January 9, 2023 · 5 min · jiezi

关于javascript:前端必会手写面试题合集

实现Event(event bus)event bus既是node中各个模块的基石,又是前端组件通信的依赖伎俩之一,同时波及了订阅-公布设计模式,是十分重要的根底。 简略版: class EventEmeitter { constructor() { this._events = this._events || new Map(); // 贮存事件/回调键值对 this._maxListeners = this._maxListeners || 10; // 设立监听下限 }}// 触发名为type的事件EventEmeitter.prototype.emit = function(type, ...args) { let handler; // 从贮存事件键值对的this._events中获取对应事件回调函数 handler = this._events.get(type); if (args.length > 0) { handler.apply(this, args); } else { handler.call(this); } return true;};// 监听名为type的事件EventEmeitter.prototype.addListener = function(type, fn) { // 将type事件以及对应的fn函数放入this._events中贮存 if (!this._events.get(type)) { this._events.set(type, fn); }};面试版: class EventEmeitter { constructor() { this._events = this._events || new Map(); // 贮存事件/回调键值对 this._maxListeners = this._maxListeners || 10; // 设立监听下限 }}// 触发名为type的事件EventEmeitter.prototype.emit = function(type, ...args) { let handler; // 从贮存事件键值对的this._events中获取对应事件回调函数 handler = this._events.get(type); if (args.length > 0) { handler.apply(this, args); } else { handler.call(this); } return true;};// 监听名为type的事件EventEmeitter.prototype.addListener = function(type, fn) { // 将type事件以及对应的fn函数放入this._events中贮存 if (!this._events.get(type)) { this._events.set(type, fn); }};// 触发名为type的事件EventEmeitter.prototype.emit = function(type, ...args) { let handler; handler = this._events.get(type); if (Array.isArray(handler)) { // 如果是一个数组阐明有多个监听者,须要顺次此触发外面的函数 for (let i = 0; i < handler.length; i++) { if (args.length > 0) { handler[i].apply(this, args); } else { handler[i].call(this); } } } else { // 单个函数的状况咱们间接触发即可 if (args.length > 0) { handler.apply(this, args); } else { handler.call(this); } } return true;};// 监听名为type的事件EventEmeitter.prototype.addListener = function(type, fn) { const handler = this._events.get(type); // 获取对应事件名称的函数清单 if (!handler) { this._events.set(type, fn); } else if (handler && typeof handler === "function") { // 如果handler是函数阐明只有一个监听者 this._events.set(type, [handler, fn]); // 多个监听者咱们须要用数组贮存 } else { handler.push(fn); // 曾经有多个监听者,那么间接往数组里push函数即可 }};EventEmeitter.prototype.removeListener = function(type, fn) { const handler = this._events.get(type); // 获取对应事件名称的函数清单 // 如果是函数,阐明只被监听了一次 if (handler && typeof handler === "function") { this._events.delete(type, fn); } else { let postion; // 如果handler是数组,阐明被监听屡次要找到对应的函数 for (let i = 0; i < handler.length; i++) { if (handler[i] === fn) { postion = i; } else { postion = -1; } } // 如果找到匹配的函数,从数组中革除 if (postion !== -1) { // 找到数组对应的地位,间接革除此回调 handler.splice(postion, 1); // 如果革除后只有一个函数,那么勾销数组,以函数模式保留 if (handler.length === 1) { this._events.set(type, handler[0]); } } else { return this; } }};实现具体过程和思路见实现eventArray.prototype.map()Array.prototype.map = function(callback, thisArg) { if (this == undefined) { throw new TypeError('this is null or not defined'); } if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } const res = []; // 同理 const O = Object(this); const len = O.length >>> 0; for (let i = 0; i < len; i++) { if (i in O) { // 调用回调函数并传入新数组 res[i] = callback.call(thisArg, O[i], i, this); } } return res;}二叉树深度遍历// 二叉树深度遍历class Node { constructor(element, parent) { this.parent = parent // 父节点 this.element = element // 以后存储内容 this.left = null // 左子树 this.right = null // 右子树 }}class BST { constructor(compare) { this.root = null // 树根 this.size = 0 // 树中的节点个数 this.compare = compare || this.compare } compare(a,b) { return a - b } add(element) { if(this.root === null) { this.root = new Node(element, null) this.size++ return } // 获取根节点 用以后增加的进行判断 放右边还是放左边 let currentNode = this.root let compare let parent = null while (currentNode) { compare = this.compare(element, currentNode.element) parent = currentNode // 先将父亲保存起来 // currentNode要不停的变动 if(compare > 0) { currentNode = currentNode.right } else if(compare < 0) { currentNode = currentNode.left } else { currentNode.element = element // 相等时 先笼罩后续解决 } } let newNode = new Node(element, parent) if(compare > 0) { parent.right = newNode } else if(compare < 0) { parent.left = newNode } this.size++ } // 前序遍历 preorderTraversal(visitor) { const traversal = node=>{ if(node === null) return visitor.visit(node.element) traversal(node.left) traversal(node.right) } traversal(this.root) } // 中序遍历 inorderTraversal(visitor) { const traversal = node=>{ if(node === null) return traversal(node.left) visitor.visit(node.element) traversal(node.right) } traversal(this.root) } // 后序遍历 posterorderTraversal(visitor) { const traversal = node=>{ if(node === null) return traversal(node.left) traversal(node.right) visitor.visit(node.element) } traversal(this.root) } // 反转二叉树:无论先序、中序、后序、层级都能够反转 invertTree() { const traversal = node=>{ if(node === null) return let temp = node.left node.left = node.right node.right = temp traversal(node.left) traversal(node.right) } traversal(this.root) return this.root }}先序遍历 ...

January 9, 2023 · 12 min · jiezi

关于javascript:从零手写reactrouter

蛮多同学可能会感觉react-router很简单, 说用都还没用明确, 还从0实现一个react-router, 其实router并不简单哈, 甚至说你看了这篇博客当前, 你都会感觉router的外围原理也就那么回事至于react-router帮忙咱们实现了什么货色我就不过多论述了, 这个间接移步官网文档, 咱们上面间接聊实现 另外: react-router源码有依赖两个库path-to-regexp和history, 所以我这里也就间接引入这两个库了,尽管上面我都会讲到根本应用, 然而同学有工夫的话还是能够浏览以下官网文档 还有一个须要留神的点是: 上面我书写的router原理都是应用hooks + 函数组件来书写的, 而官网是应用类组件书写的, 所以如果你对hooks还不是很明确的话, 得去补一下这方面的常识, 为什么要抉择hooks, 因为当初绝大多数大厂在react上根本都在鼎力举荐应用hook, 所以咱们得跟上时代不是, 而且我着重和大家聊的也是原理, 而不是跟官网截然不同的源码, 如果要1比1的复刻源码不带本人的了解的话, 那你去看官网的源码就行了, 何必看这篇博文了 在本栏博客中, 咱们会聊聊以下内容: 封装本人的生成match对象办法history库的应用Router和BrowserRouter的实现Route组件的实现Switch和Redirect的实现withRouter的实现Link和NavLink实现聚合api封装本人的生成match对象办法在封装之前, 我想跟大家先分享path-to-regexp这个库 为什么要先聊这个库哈, 次要起因是因为react-router中用到了这个库, 我看了一下其实咱们也没必要本人再去实现一个这个库(为什么没必要呢,倒并不是因为react-router没有实现咱们就不实现, 而是因为这个库实现的性能非常简单, 然而细节十分繁琐, 有十分多的因素须要去思考到我感觉没必要), 这个库做的事件非常简单: 将一个字符串变成一个正则表达式咱们晓得, react-router的大抵原理就是依据门路的不同从而渲染不同的页面, 那么这个过程其实也就是门路A匹配页面B的过程, 所以咱们之前会写这样的代码 <Route path="/news/:id" component={News} /> // 如果门路匹配上了/news/:id这样的门路, 则渲染News组件那么react-router他是怎么去判断浏览器地址栏的门路和这个Route组件中的path属性匹配上的? path填写的如果是/news/:id这样的门路, 那么/news/123 /news/321这种都可能被react-router匹配上 咱们可能想到的办法是不是大略能够如下: 将所有的path属性全副转换为正则表达式(比方/news/:id转换为/^\/news(?:\/([^\/#\?]+?))[\/#\?]?$/i), 而后将地址栏的path值取出来跟该正则表达式进行匹配, 匹配上了就要渲染相应的路由, 匹配不上就渲染其余的逻辑path-to-regexp就是做这个事件的, 他把咱们给他的门路字符串转换为正则表达式, 供咱们匹配 装置: yarn add path-to-regexp -S// 咱们能够来轻易试试这个库import { pathToRegexp } from "path-to-regexp";const keys = [];// pathToRegexp(path, keys?, options?)// path: 就是咱们要匹配的门路规定// keys: 如果你传递了, 当他匹配上当前, 会把绝对应的参数key传递到keys数组中// options: 给path门路规定的一些附加规定, 比方sensitive大小写敏感之类的const result = pathToRegexp("/news/:id", keys);console.log("result", result);console.log(result.exec("/news/123")); // 输入 ["/news/123", "123", index: 0, input: "/news/123", groups: undefined]console.log(result.exec("/news/details/123")); // 输入nullconsole.log(keys); // 输入一个数组, 数组的有一个对象{modifier: " name: "id", pattern: "[^\/#\?]+?", prefix: "/", suffix: ""}当然, 这个库还有很多玩法, 他也不是专门为react-router实现的, 只是刚好被react-router拿过去用了, 对这个库有趣味的同学能够去看看他的文档 ...

January 9, 2023 · 8 min · jiezi

关于javascript:大厂前端面试考什么

基于 Localstorage 设计一个 1M 的缓存零碎,须要实现缓存淘汰机制设计思路如下: 存储的每个对象须要增加两个属性:别离是过期工夫和存储工夫。利用一个属性保留零碎中目前所占空间大小,每次存储都减少该属性。当该属性值大于 1M 时,须要依照工夫排序零碎中的数据,删除一定量的数据保障可能存储下目前须要存储的数据。每次取数据时,须要判断该缓存数据是否过期,如果过期就删除。以下是代码实现,实现了思路,然而可能会存在 Bug,然而这种设计题个别是给出设计思路和局部代码,不会须要写出一个无问题的代码 class Store { constructor() { let store = localStorage.getItem('cache') if (!store) { store = { maxSize: 1024 * 1024, size: 0 } this.store = store } else { this.store = JSON.parse(store) } } set(key, value, expire) { this.store[key] = { date: Date.now(), expire, value } let size = this.sizeOf(JSON.stringify(this.store[key])) if (this.store.maxSize < size + this.store.size) { console.log('超了-----------'); var keys = Object.keys(this.store); // 工夫排序 keys = keys.sort((a, b) => { let item1 = this.store[a], item2 = this.store[b]; return item2.date - item1.date; }); while (size + this.store.size > this.store.maxSize) { let index = keys[keys.length - 1] this.store.size -= this.sizeOf(JSON.stringify(this.store[index])) delete this.store[index] } } this.store.size += size localStorage.setItem('cache', JSON.stringify(this.store)) } get(key) { let d = this.store[key] if (!d) { console.log('找不到该属性'); return } if (d.expire > Date.now) { console.log('过期删除'); delete this.store[key] localStorage.setItem('cache', JSON.stringify(this.store)) } else { return d.value } } sizeOf(str, charset) { var total = 0, charCode, i, len; charset = charset ? charset.toLowerCase() : ''; if (charset === 'utf-16' || charset === 'utf16') { for (i = 0, len = str.length; i < len; i++) { charCode = str.charCodeAt(i); if (charCode <= 0xffff) { total += 2; } else { total += 4; } } } else { for (i = 0, len = str.length; i < len; i++) { charCode = str.charCodeAt(i); if (charCode <= 0x007f) { total += 1; } else if (charCode <= 0x07ff) { total += 2; } else if (charCode <= 0xffff) { total += 3; } else { total += 4; } } } return total; }}画一条0.5px的线采纳transform: scale()的形式,该办法用来定义元素的2D 缩放转换:transform: scale(0.5,0.5);采纳meta viewport的形式<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>这样就能缩放到原来的0.5倍,如果是1px那么就会变成0.5px。viewport只针对于挪动端,只在挪动端上能力看到成果 ...

January 9, 2023 · 4 min · jiezi

关于javascript:面试官说说Event-Loop事件循环微任务宏任务

前言JS是一门单线程语言,单线程就意味着,所有的工作须要排队,前一个工作完结,才会执行下一个工作。这样所导致的问题是:如果JS执行的工夫过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的觉。为了解决这个问题,JS中呈现了同步和异步。他们的本质区别是:一条流水线上各个流程的执行程序不同。在讲JS工作执行机制前,先要理解一下什么是同步工作与异步工作。 同步工作:即主线程上的工作,依照程序由上⾄下顺次执⾏,以后⼀个工作执⾏结束后,能力执⾏下⼀个工作。 异步工作:不进⼊主线程,⽽是进⼊工作队列的工作,执行结束之后会产生一个回调函数,并且告诉主线程。当主线程上的工作执行完后,就会调取最早告诉本人的回调函数,使其进入主线程中执行。 1. 事件循环Event Loop概念介绍事件循环Event Loop又叫事件队列,两者是一个概念事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规定。事件循环不属于js代码自身的领域,而是属于js编译器的领域,在js中探讨事件循环是没有意义的。换句话说,js代码能够了解为是一个人在公司中具体做的事件, 而 事件循环 相当于是公司的一种规章制度。 两者不是一个层面的概念。 2. 微工作、宏工作概念介绍微工作与宏工作就属于js代码的领域js代码次要分为两大类: 同步代码、异步代码异步代码又分为:微工作与宏工作 3. 事件循环Event Loop执行机制1.进入到script标签,就进入到了第一次事件循环.2.遇到同步代码,立刻执行3.遇到宏工作,放入到宏工作队列里.4.遇到微工作,放入到微工作队列里.5.执行完所有同步代码6.执行微工作代码7.微工作代码执行结束,本次队列清空寻找下一个宏工作,反复步骤1 以此重复直到清空所以宏工作,这种一直反复的执行机制,就叫做事件循环画了一张图来形容事件循环 4.易错点(1). promise自身是一个同步的代码(只是容器),只有它前面调用的then()办法外面的回调才是微工作 (2). await左边的表达式还是会立刻执行,表达式之后的代码才是微工作, await微工作能够转换成等价的promise微任务分析 (3). script标签自身是一个宏工作, 当页面呈现多个script标签的时候,浏览器会把script标签作为宏工作来解析 看到这里,对事件循环应该有所理解了,给大家看几道面试题。 一. 1.先执行主线程上的log(1) 2.当有两个await时,只有第一个await左边的代码会立刻执行log(4),前面的几行代码都会放入微工作队列中。 3.执行主线程上的log(6) 4.执行第4行至第6行的微工作 二. 1.先执行主线程上的1,5,7 2.主线程的同步工作执行结束后,会先执行微工作。执行Promise的then办法里的代码,打印6 3.微工作执行结束后,最初执行定时器里的宏工作,打印2,3,4 三. 参考 前端进阶面试题具体解答 1.先执行主线程上的同步代码,打印1 2.执行第9行的函数,进⼊async1外部,async1其实是申明了⼀个promise,promise是同步代码,会程序执⾏打印async2函数里的4 ,只有.then⾥⾯的代码会加⼊微工作队列⾥,这⾥相当于执⾏了async2()之后,再将前面的代码加⼊⼀个微工作队列中。 3.回主线程中,遇到setTimeout(),加⼊到宏工作队列 4.主线程持续往后执⾏,前⾯说过,promise是同步代码,.then后⾯的回调会加⼊微工作队列,所以会打印13⾏的7 5.主线程执⾏实现,开始执⾏微工作队列内的工作,遵循先进先出的准则,打印第四⾏的2。而后接着执行第5行第二个awaite左边的代码,打印5。第6行这个时候就被退出微工作队列。 6.接着会执行第二个微工作,也就是16行代码,打印8。第17行的then这个时候也会退出微工作队列。再顺次执行第6行和第17行的两个微工作,打印3和9 7.微工作执⾏完结,开始执⾏宏工作setTimeout,打印11⾏的6. 总结所有同步工作都在主线程上执行,造成一个执行栈(call stack)。遇到异步工作, 进入异步解决模块并注册回调函数; 等到指定的事件实现(如ajax申请响应返回, setTimeout提早到指定工夫)时,异步解决模块会将这个回调函数移入异步工作队列。当栈中的代码执行结束,执行栈中的工作为空时,主线程会先查看微工作队列中是否有工作,如果有,就将微工作队列中的所有工作顺次执行,直到微工作队列为空; 之后再查看宏工作队列中是否有工作,如果有,则取出第一个宏工作退出到执行栈中,之后再清空执行栈,查看微工作,以此循环,直到全副的工作都执行实现。以上就是我对JS执行原理的一些整顿和了解,心愿能给读者带来一些帮忙。如果有了解谬误或表述不当的中央,请斧正。最初再给大家出一道题,能够把答案留在评论区

January 9, 2023 · 1 min · jiezi

关于javascript:2023前端二面常考面试题合集

说下对 JS 的理解吧是基于原型的动静语言,次要独特个性有 this、原型和原型链。 JS 严格意义上来说分为:语言规范局部(ECMAScript)+ 宿主环境局部 语言规范局部 2015 年公布 ES6,引入诸多新个性使得可能编写大型项目变成可能,规范自 2015 之后以年号代号,每年一更 宿主环境局部 在浏览器宿主环境包含 DOM + BOM 等在 Node,宿主环境包含一些文件、数据库、网络、与操作系统的交互等说一下SPA单页面有什么优缺点?长处:1.体验好,不刷新,缩小 申请 数据ajax异步获取 页面流程;2.前后端拆散3.加重服务端压力4.共用一套后端程序代码,适配多端毛病:1.首屏加载过慢;2.SEO 不利于搜索引擎抓取为什么有时候⽤translate来扭转地位⽽不是定位?translate 是 transform 属性的⼀个值。扭转transform或opacity不会触发浏览器从新布局(reflow)或重绘(repaint),只会触发复合(compositions)。⽽扭转相对定位会触发从新布局,进⽽触发重绘和复合。transform使浏览器为元素创立⼀个 GPU 图层,但扭转相对定位会使⽤到 CPU。 因而translate()更⾼效,能够缩短平滑动画的绘制工夫。 ⽽translate扭转地位时,元素仍然会占据其原始空间,相对定位就不会发⽣这种状况。 代码输入后果var a = 1;function printA(){ console.log(this.a);}var obj={ a:2, foo:printA, bar:function(){ printA(); }}obj.foo(); // 2obj.bar(); // 1var foo = obj.foo;foo(); // 1输入后果: 2 1 1 解析: obj.foo(),foo 的this指向obj对象,所以a会输入2;obj.bar(),printA在bar办法中执行,所以此时printA的this指向的是window,所以会输入1;foo(),foo是在全局对象中执行的,所以其this指向的是window,所以会输入1;代码输入后果const promise = Promise.resolve().then(() => { return promise;})promise.catch(console.err)输入后果如下: Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>这里其实是一个坑,.then 或 .catch 返回的值不能是 promise 自身,否则会造成死循环。 ...

January 9, 2023 · 4 min · jiezi

关于javascript:22道js输出顺序问题你能做出几道

前言最近在筹备面试题,console的输入程序之前始终迷迷糊糊。 必备常识JS是单线程的单线程是 JavaScript 外围特色之一。这意味着,在 JS 中所有工作都须要排队执行,前一个工作完结,才会执行后一个工作。所以这就造成了一个问题:如果前一个工作耗时很长,后一个工作就不得不始终等着后面的工作执行完能力执行。比方咱们向服务器申请一段数据,因为网络问题,可能须要期待 60 秒左右能力胜利返回数据,此时只能期待申请实现,JS 能力去解决前面的代码。 同步工作和异步工作为了解决JS单线程带来的问题,JavaScript 就将所有工作分成了同步工作和异步工作。 同步工作(Synchronous)同步工作指的是以后一个(如果有)工作执行结束,接下来能够立刻执行的工作。这些工作将在主线程上顺次排队执行。也就是说排排队 //for(){} 和 console.log() 将会顺次执行,最终输入 0 1 2 3 4 done。for (let i = 0; i < 5; i++) {console.log(i)}console.log('done')异步工作(Asynchronous)异步工作绝对于同步工作,指的是不须要进入主线程排队执行,而是进入超车道、并车道。也就是工作队列中,造成一系列的工作。这些工作只有当被告诉能够执行的时候,该工作才会从新进入主线程执行。 //上面的 then() 办法须要期待 Promise 被 resolve() 之后能力执行,它是一个异步工作。最终输入 1 3 2。console.log(1)Promise.resolve().then(() => { console.log(2)})console.log(3)具体来说就是,所有同步工作会在主线程上顺次排队执行,造成一个执行栈(Execution ContextStack)。主线程之外,还存在一个工作队列。当异步工作有了运行后果,会在工作队列之中搁置对应的事件。当执行栈中的所有同步工作执行结束,工作队列里的异步工作就会进入执行栈,而后持续顺次执行。 异步工作(工作队列)能够分为 macrotasks(taskQueue):宏工作 task,也是咱们常说的工作队列 macrotasks 的划分:(留神先后顺序!) (1)setTimeout(提早调用)(2)setInterval(间歇调用)(3)setImmediate(Node 的立刻调用)(4)requestAnimationFrame(高频的 RAF)(5)I/O(I/O 操作)(6)UI rendering(UI 渲染)(7) 包裹在一个 script 标签中的 js 代码也是一个 Macrotasks留神: (1)每一个 macrotask 的回调函数要放在下一车的结尾去执行! (2)只有 setImmediate 可能确保在下一轮事件循环立刻失去解决 microtasks:微工作(也称 job)调度在以后脚本执行完结后,立刻执行的工作,以防止付出额定一个 task 的费用。 ...

January 9, 2023 · 6 min · jiezi

关于javascript:让你更好使用-Typescript-的11个技巧

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。学习Typescript通常是一个从新发现的过程。最后印象可能很有欺骗性:这不就是一种正文Javascript 的形式吗,这样编译器就能帮忙我找到潜在的bug? 尽管这种说法总体上是正确的,但随着你的后退,会发现语言最不堪设想的力量在于组成、推断和操纵类型。 本文将总结几个技巧,帮忙你充分发挥语言的后劲。 将类型设想成汇合类型是程序员日常概念,但很难扼要地定义它。我发现用汇合作为概念模型很有帮忙。 例如,新的学习者发现Typescript组成类型的形式是反直觉的。举一个非常简单的例子: type Measure = { radius: number };type Style = { color: string };// typed { radius: number; color: string }type Circle = Measure & Style;如果你将 & 操作符解释为逻辑与,你的可能会认为 Circle 是一个哑巴类型,因为它是两个没有任何重叠字段的类型的联合。这不是 TypeScript 的工作形式。相同,将其设想成汇合会更容易推导出正确的行为: 每种类型都是值的汇合有些汇合是有限的,如 string、object;有些是无限的,如 boolean、undefined,...unknown 是通用汇合(包含所有值),而 never 是空集合(不包含任何值)Type Measure 是一个汇合,蕴含所有蕴含名为 radius 的 number 字段的对象。Style 也是如此。&运算符创立了交加:Measure & Style 示意蕴含 radius 和 color 字段的对象的汇合,这实际上是一个较小的汇合,但具备更多常用字段。同样,|运算符创立了并集:一个较大的汇合,但可能具备较少的常用字段(如果两个对象类型组合在一起)汇合也有助于了解可调配性:只有当值的类型是指标类型的子集时才容许赋值: type ShapeKind = 'rect' | 'circle';let foo: string = getSomeString();let shape: ShapeKind = 'rect';// 不容许,因为字符串不是 ShapeKind 的子集。shape = foo;// 容许,因为 ShapeKind 是字符串的子集。foo = shape;了解类型申明和类型收窄TypeScript 有一项十分弱小的性能是基于控制流的主动类型收窄。这意味着在代码地位的任何特定点,变量都具备两种类型:申明类型和类型收窄。 ...

January 9, 2023 · 5 min · jiezi

关于javascript:THREEjs设置背景图和播放动画学习-大帅老猿threejs特训

THREE.js设置背景图和播放动画学习 | 大帅老猿threejs特训本文能学到什么作者的three.js属于入门的,最近跟着大帅的训练营,学习了three.js如何设置全景图背景和播放动画,本文章应用的模型和图片都是当时提供好的,咱们只须要实现加载背景图、加载模型和播放动画即可 成果 具体实现初始化首先咱们依照惯例,生成scene、camera和renderer let scene, camera, rendererfunction init() { scene = new THREE.Scene() camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); camera.position.set(0.6, 0.6, 1); document.body.appendChild(renderer.domElement);}init()加载模型function loadModel() { const gltfLoader = new GLTFLoader() gltfLoader.load('../resources/models/donuts.glb', gltf => { scene.add(gltf.scene); });}loadmodel()初始化控制器function initControls() { controls = new OrbitControls(camera, renderer.domElement);}initControls()渲染function animate() { renderer.render(scene, camera) controls.update() requestAnimationFrame(animate)}模仿太阳光这时候整个场景事彩色的,咱们加个directionLight,模仿太阳光 function init() { ... const directionLight = new THREE.DirectionalLight(0xffffff, 0.4); scene.add(directionLight);}加载背景图function loadBackground() { const rgbeLoader = new RGBELoader() rgbeLoader.load('../resources/hdr/sky.hdr', function (texture) { scene.background = texture; });}loadModel()loadBackground()首先这里应用hdr,hdr比一般的jpg和png,在光洁很强或者很暗的中央,可能展现更多的细节,而一般的jpg、png就只能显示红色或者彩色咱们单纯的给scene设置背景,就是固定的背景,咱们心愿变成全景图的背景,须要设置几个值,这几个值的含意如下: ...

January 8, 2023 · 1 min · jiezi

关于javascript:客服系统即时通讯IM开发一基于WebSocket实现实时获取消息唯一客服网站在线客服系统

我在实现在客服零碎的时候,前端是基于WebSocket来实时收取服务端音讯的,具体的解释下 即时通讯一种罕用的办法是应用 WebSocket。WebSocket 是一种通信协议,它容许浏览器和服务器进行全双工通信,也就是说,单方都能够同时发送和接管音讯。 在前端应用 JavaScript 实现即时通讯的办法也有很多,能够应用 WebSocket 对象来与服务器通信。你能够在浏览器中关上 WebSocket 连贯,而后应用 send() 办法向服务器发送音讯,应用 onmessage 事件处理程序来接管服务器发送的音讯。 const ws = new WebSocket('ws://example.com/ws');ws.onopen = function () { console.log('WebSocket 连贯已关上'); ws.send('发送音讯');};ws.onmessage = function (event) { console.log(`收到服务器的音讯:${event.data}`);};ws.onclose = function () { console.log('WebSocket 连贯已敞开');};咱们还须要实现断线重连机制在前端应用 JavaScript 实现断线重连的办法有很多。上面是一种常见的实现形式: // 设置重连工夫距离(单位:毫秒)const RECONNECT_INTERVAL = 1000;// 设置最大重连次数const MAX_RECONNECT_TIMES = 3;let reconnectTimes = 0;let ws;// 尝试连贯 WebSocketfunction connect() { ws = new WebSocket('ws://example.com/ws'); ws.onopen = function () { console.log('WebSocket 连贯已关上'); reconnectTimes = 0; }; ws.onclose = function () { console.log('WebSocket 连贯已敞开'); // 尝试重连 reconnect(); };}// 尝试重连function reconnect() { if (reconnectTimes >= MAX_RECONNECT_TIMES) { console.log('重连失败'); return; } reconnectTimes++; console.log(`正在尝试重连(第 ${reconnectTimes} 次)`); setTimeout(function () { connect(); }, RECONNECT_INTERVAL);}connect();咱们还须要获取到后端的数据并进行解析在前端应用 JavaScript 接管音讯并解析的办法有很多。例如,你能够应用 WebSocket 的 onmessage 事件处理程序来接管服务器发送的音讯,而后依据音讯的格局来解析。上面是一个简略的例子,假如服务器发送的音讯格局为 { "type": "message", "data": "Hello, World!" }: ...

January 7, 2023 · 2 min · jiezi

关于javascript:Element-UI日期选择器eldatepicker设置默认的时刻踩坑

大家好,我是小梅,公众号:「小梅的前端之路」 原创作者。 作为在前端畛域一直摸索的一员,在此记录开发中遇到的问题,如果你也遇到了雷同的问题,心愿本文对你有帮忙。 踩坑经验应用日期选择器,抉择日期时,试图让selectTime能取到抉择日期的最初一刻的工夫戳。举例:2023-01-06 23:59:59的工夫戳1673020799999 <el-date-picker v-model="selectTime" type="date" value-format="timestamp" placeholder="抉择日期"></el-date-picker>查看文档看到一个default-time,希图间接设置default-time属性给日期抉择组件希图的实现,上面这样不能实现哦,因为这个字段基本不是用来设置该组件默认时刻的,该字段只对日期范畴类型的日期选择器无效;具体详情看官网对该字段的形容 <el-date-picker v-model="selectTime" default-time=“23:59:59” type="date" value-format="timestamp" placeholder="抉择日期"></el-date-picker>实现方法:因为我的需要是提交的时候,提交日期的最初一刻就行了,因而我能够间接把值转换一下就能够了,我的项目中用到了dayjs插件,因而此处间接用 const time = dayjs(this.selectTime).endOf('day').valueOf()如果没有引入dayjs的话,这里提供一种办法 const time = new Date(this.selectTime)const y = time.getFullYear()const m = time.getMonth()const d = time.getDate()// 失去日期的最初一刻的工夫戳const targetTime = new Date(y, m, d, 23, 59, 59).getTime()❤️欢送素质三连[点赞 + 珍藏 + 评论] 我是小梅,有趣味的话能够在微信搜一搜「小梅的前端之路」第一工夫接管文章更新告诉,一起沟通、学习成长呀。

January 7, 2023 · 1 min · jiezi

关于javascript:js函数this指向问题解析

this指向问题根底定义类的货色最好还是查看正规文档,网上文章有诸多谬误,容易误导人相干内容所在仓库地址:https://github.com/goblin-pitcher/steel-wheel-run/blob/master/%E6%98%93%E5%BF%98%E7%9F%A5%E8%AF%86%E7%82%B9%E6%B1%87%E6%80%BB/this%E6%8C%87%E5%90%91%E7%9B%B8%E5%85%B3.md this指向相干定义这里次要探讨function函数和箭头函数的this相干定义: function函数,参考mdn官网文档(this) 在绝大多数状况下,函数的调用形式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。箭头函数,参考mdn官网文档(箭头函数) 箭头函数不会创立本人的this,它只会从本人的作用域链的上一层继承 this如何了解箭头函数的this了解箭头函数的this,最好的形式是查看babel是如何对其进行本义的,示例如下: 原代码: const name = 'a'const obj = { name: 'b', f: ()=> { console.log(this.name) }, f0(){ return ()=>{ console.log(this.name) } }}本义为es5的代码: var _this = void 0;var name = 'a';var obj = { name: 'b', f: function f() { console.log(_this.name); }, f0: function f0() { var _this2 = this; return function () { console.log(_this2.name); }; }};能够发现,箭头函数的本义,即是在其所在下层作用域中定义_this对象,再将箭头函数外部this替换为_this。 联合箭头函数this的定义,箭头函数不会创立本人的this,它只会从本人的作用域链的上一层继承 this,咱们能够不把箭头函数中的this当作一个一般对象,例如将上述代码改成如下写法 const _context = void 0;const name = 'a';const obj = { name: 'b', f: function f() { console.log(_this.name); }, f0: function f0() { const _context = this; return function () { console.log(_context.name); }; }};obj.f0()() // 输入bobj.f0.call({name: 123})() // 输入123将箭头函数本义成上述es5写法,同样可正确实现其成果,这样箭头函数this指向问题就变成了一个闭包问题 ...

January 6, 2023 · 4 min · jiezi

关于javascript:客服系统切换中英文多语言-使用js更新URL参数来实现切换-唯一客服网站网页客服源码教程

我的客服聊天页面有多语言切换性能,是通过URL参数中的lang参数来进行辨别的 如果要切换中英文或者其余语言,就须要动静更新URL参数中的lang参数,所以实现上面这个函数 //批改url参数function changeURLPar(destiny, par, par_value) { var pattern = par.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '=([^&]*)'; var replaceText = par + '=' + par_value; if (destiny.match(new RegExp(pattern))) { return destiny.replace(new RegExp(pattern, 'g'), replaceText); } else { if (destiny.match('[\?]')) { return destiny + '&' + replaceText; } else { return destiny + '?' + replaceText; } }}应用办法如下: var url = 'http://example.com';var newUrl = changeURLPar(url, 'key', 'newValue');console.log(newUrl); // "http://example.com?key=newValue"这个函数接管三个参数:destiny,par,par_value。 destiny是一个字符串,示意要批改的URL。par是一个字符串,示意要批改的参数。par_value是一个字符串,示意参数的新值。首先,函数应用par构建一个正则表达式模式,该模式用于在URL中搜寻匹配的参数。 而后,函数应用这个模式测试destiny字符串。如果有匹配的参数,函数应用正则表达式和g标记来替换所有匹配的参数。 如果没有匹配的参数,函数应用另一个正则表达式测试destiny字符串以确定它是否蕴含问号。如果有,函数在URL开端增加新参数。如果没有,函数将在URL的结尾增加问号和新参数。 ...

January 6, 2023 · 1 min · jiezi

关于javascript:客服弹窗中使用layer库自定义展示的标题-网站网页在线客服源码教程

我在实现客服零碎的过程中,应用layer实现右下角弹窗成果,当初须要自定义layer弹窗的题目和减少自定义按钮 layer.open({ type: 2, title: 'My Window<button class="btn btn-primary" id="btn-reload">Reload</button>', // 在题目中退出按钮 shadeClose: true, shade: 0.8, move:false,//不容许拖动,很重要 area: ['380px', '90%'], offset: 'rb', // 右下角弹出 content: 'http://www.your-site.com/html/window.html', success: function(layero, index){ // 弹窗加载胜利时的回调 var iframe = layero.find('iframe'); // 获取到弹窗中的iframe元素 var btnReload = layero.find('#btn-reload'); // 获取到按钮 btnReload.click(function(){ iframe.attr('src', iframe.attr('src')); // 从新加载iframe的内容});在这个例子中,我在自定义题目外面减少了一个按钮,实现点击从新加载弹窗内容的成果咱们应用了jQuery的click()办法来解决按钮的点击事件。在按钮的回调函数中,咱们应用了iframe的attr()办法来从新设置src属性,从而从新加载iframe的内容。这个外面move:false很重要,不能允许拖动,否则点击事件不起作用 在惟一客服(http://gofly.v1kf.com)外面,我是在题目上减少了一个切换成英文的按钮,看成果 惟一在线客服零碎https://gofly.v1kf.com十年开发教训程序员,到职全心守业中,历时三年开发出的产品《惟一客服零碎》

January 6, 2023 · 1 min · jiezi

关于javascript:Javascript实现右下角在线客服弹窗效果代码-网站网页在线客服源码教程

如果你只想要实现右下角弹窗性能,你能够应用JavaScript库"layer"。 layer是一个开源的JavaScript库,能够帮忙你疾速地实现相似操作系统的弹出窗口成果。它提供了许多可定制的选项,能够帮忙你创立各种各样的弹出窗口,例如信息框、对话框、提示框、加载框等。要应用layer,你须要在你的HTML页面中引入layer layer.open({ type: 2, title: '在线客服征询', shadeClose: true, shade: 0.8, area: ['380px', '90%'], offset: 'rb', // 右下角弹出 content: 'http://www.your-site.com/html/window.html'});offset属性能够管制窗口弹出的地位,你能够应用"rb"来示意右下角。此外,你还能够应用layer的其余选项来自定义窗口的外观和行为,例如设置窗口的题目、设置是否能够拖动、设置背景遮罩层的透明度等。 惟一客服(http://gofly.v1kf.com) 就是通过下面的形式实现的右下角弹出聊天窗口,当然进行了一些批改,前面我还会持续介绍 惟一在线客服零碎 https://gofly.v1kf.com

January 6, 2023 · 1 min · jiezi

关于javascript:记录一次利用canvans解决数据可视化问题箱图转换为对应圆

先看最终效果图需要:箱图种每个箱子都有本人对应的圆心和半径,以及以后图上对应的y轴的取值范畴(可缩放),依据这三个值,画出一个圆心在同一条竖线上一一对应的圆 形象的画一下:,再给它想方法搬到规范直角坐标系上能够看到,所有的圆的圆心坐标都是(0,?),而此时的直角坐标系的y的最大值和最小值,咱们能够任意给,且是对称的,咱们给到600.-600,此时咱们只须要算进去实在的每个圆在右侧的坐标系里的圆心坐标,和半径长度,就能够利用canvas来画出圆。 难点在于坐标的转换,这里我是利用比例的关系进行的计算:1、首先是对于半径的计算,列出公式: 实在圆的半径 / 实在的范畴 = 坐标系圆的半径 / 坐标系y轴的范畴 实在圆的半径由后端发回,实在的范畴由左侧的箱图的y轴范畴也能够拿到 = y_end - y_start坐标系y轴的范畴 = 1200,(咱们设置的y轴范畴为600到-600)即可计算出坐标系上缩放后的圆的半径 2、坐标系上圆心的计算,同样,咱们能够利用圆心距竖直核心的间隔,来列出等比例的公式: (实在圆心坐标 - 实在范畴核心)/ 实在的范畴 = (坐标系圆心y坐标 - 坐标系范畴核心y坐标)/坐标系y轴的范畴 实在圆的半径由后端发回,实在的范畴 = y_end - y_start实在范畴核心 = (y_end - y_start)/2 + y_start坐标系范畴核心y坐标 = 0坐标系y轴的范畴 = 1200 即可失去坐标系上缩放后 圆心y的坐标 晓得这两个,咱们只须要在canvans上把圆画进去即可,咱们建设一个大小为1200的canvans画布,pencil?.clearRect(0, 0, 1200, 1200);而canvans自带的坐标系为这样子的 所以咱们的坐标系的原点对应的canvans画布的坐标为(600,600) 那圆心的坐标还是须要转化,,能够看到,原先圆心的y坐标为200,新的即为600-200=400,即canvans画布上 圆心的y坐标 = 600 - 缩放后缩放后 圆心y的坐标那么就能够利用canvas画圆的办法来把圆绘制进去 pencil.arc(600,canvans画布上圆心的y坐标,缩放后圆的半径,0,2 * Math.PI,); 所有的数学逻辑剖析与canvans的办法剖析结束。 间接上代码: type BoxPlotCircleData = { diameter: number; mean: number; parameterX: string; testItem: string;};type CirCleProps = { // colors: Color[]; range: [number, number]; boxPlotColorDic: { [key: string]: Color }; width: number; data: BoxPlotCircleData[];};// 计算缩放后直径值的函数,应用之前保障realRange为大于0 的数const computerDiameter = (realDiameter: number, realRange: number, computerRange: number) => { // 公式:computerDiameter/realDiameter = computerRange/realRange // if (!realRange) return; const computerDiameterRes: number = bignumberFc.multiply(bignumberFc.divide(computerRange, realRange), realDiameter); return computerDiameterRes;};// 计算缩放后圆心Y坐标的函数,应用之前保障realRange为大于0 的数const computerCircleCenter = ( realCircleCenter: number, realRange: number, realStartPoint: number, computerRange: number,) => { // 公式:中点坐标 = realRange/2 + range[0] // 公式:(realCircleCenter - 中点) /realRange = (computerCircleCenter - 0 ) /computerRange // if (!realRange) return; const realMiddle: number = bignumberFc.add(bignumberFc.divide(realRange, 2), realStartPoint); const computerCircleCenterRes = bignumberFc.multiply( bignumberFc.divide(bignumberFc.subtract(realCircleCenter, realMiddle), realRange), computerRange, ); return computerCircleCenterRes;};const AnovaCircle: React.FC<CirCleProps> = (props: CirCleProps) => { // console.log(props, 'props______-'); const { range, data, boxPlotColorDic } = props; const canvasDom = useRef<HTMLCanvasElement>(null); useEffect(() => { const pencil = canvasDom.current?.getContext('2d'); if (!pencil) return; pencil?.clearRect(0, 0, 1200, 1200); if (!range) return; const realRange = bignumberFc.subtract(range[1], range[0]); if (!(realRange > 0)) return; data.map((item) => { // console.log(computerCircleCenter(item.mean, realRange, range[0], 1200), '圆心坐标'); // console.log(bignumberFc.divide(computerDiameter(item.diameter, realRange, 1200), 2), '半径'); pencil.beginPath(); pencil.strokeStyle = boxPlotColorDic[item.parameterX] as string; pencil.lineWidth = 12; pencil.arc( 600, bignumberFc.subtract(600, computerCircleCenter(item.mean, realRange, range[0], 1200)), bignumberFc.divide(computerDiameter(item.diameter, realRange, 1200), 2), 0, 2 * Math.PI, ); pencil.stroke(); pencil.closePath(); }); }, [range, data]); return ( <div className={styles.container}> <canvas ref={canvasDom} width={1200} height={1200} style={{ height: 130, width: 130 }}> 您的浏览器不反对canvas标签,无奈看到图形 </canvas> </div> );};注:代码种的bigNumber.办法,可均替换成加减乘除bigNumber.add(a,b) 即为 a+bbigNumber.subtract(a,b) 即为 a-bbigNumber.multiply(a,b) 即为 a*bbigNumber.divide(a,b) 即为 a/b ...

January 6, 2023 · 2 min · jiezi

关于javascript:在js中使用Proxy来相对可靠地实现单例模式

先上实现: // singleton.jsexport default function singleton(className) { let ins return new Proxy(className,{ construct(target,argArray) { if (!ins) { ins = new target(...argArray) } return ins } })}这里利用了Proxy的construct配置属性拦挡构造函数的new操作应用 应用: Video.jsimport singleton from './singleton';class Video { constructor() { console.log('create'); }}const newVideo = new singleton(Video)export { newVideo as Video }// index.jsimport {Video} from './Video.js';const v1 = new Video()const v2 = new Video()console.log(v1 === v2); // true为什么要这么写呢?因为:咱们个别这么实现单例模式: // singleton.jsexport default function singleton(className) { let ins //这里返回了一个新类 return class { constuctor(...args){ if (!ins) { ins = new className(...args) } return ins } })}应用起来也跟下面应用Proxy实现差不多,然而有一个弊病,就是不能操作原来类的原型对象,新增或批改外面的属性: ...

January 6, 2023 · 1 min · jiezi

关于javascript:社招前端二面必会手写面试题总结

字符串查找请应用最根本的遍从来实现判断字符串 a 是否被蕴含在字符串 b 中,并返回第一次呈现的地位(找不到返回 -1)。a='34';b='1234567'; // 返回 2a='35';b='1234567'; // 返回 -1a='355';b='12354355'; // 返回 5isContain(a,b);function isContain(a, b) { for (let i in b) { if (a[0] === b[i]) { let tmp = true; for (let j in a) { if (a[j] !== b[~~i + ~~j]) { tmp = false; } } if (tmp) { return i; } } } return -1;}setTimeout与setInterval实现setTimeout 模仿实现 setInterval题目形容: setInterval 用来实现循环定时调用 可能会存在肯定的问题 能用 setTimeout 解决吗 ...

January 6, 2023 · 8 min · jiezi

关于javascript:一步步实现ReactHooks核心原理

React Hooks曾经推出一段时间,大家应该比拟相熟,或者多多少少在我的项目中用过。写这篇文章简略剖析一下Hooks的原理,并带大家实现一个简易版的Hooks。 这篇写的比拟细,相干的知识点都会解释,给大家刷新一下记忆。 HooksHooks是React 16.8推出的新性能。以这种更简略的形式进行逻辑复用。之前函数组件被认为是无状态的。然而通过Hooks,函数组件也能够有状态,以及类组件的生命周期办法。 useState用法示例: import React, { useState } from 'react';function Example() { // count是组件的状态 const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> );}闭包开始之前,咱们来简略回顾一下闭包的概念,因为Hooks的实现是高度依赖闭包的。 闭包(Closure),Kyle Simpson在《你不晓得的Javascript》中总结闭包是: Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.闭包就是,函数能够拜访到它所在的词法作用域,即便是在定义以外的地位调用。 闭包的一个重要利用就是,实现外部变量/公有数据。 var counter = 0;// 给计数器加1function add() { counter += 1;}// 调用 add() 3次add(); // 1add(); // 2counter = 1000;add(); // 1003这里因为counter不是外部变量,所以谁都能批改它的值。咱们不想让人随便批改counter怎么办?这时候就能够用闭包: ...

January 6, 2023 · 4 min · jiezi

关于javascript:前端一面必会手写面试题边面边更

实现 add(1)(2)(3)函数柯里化概念: 柯里化(Currying)是把承受多个参数的函数转变为承受一个繁多参数的函数,并且返回承受余下的参数且返回后果的新函数的技术。 1)粗犷版 function add (a) {return function (b) { return function (c) { return a + b + c; }}}console.log(add(1)(2)(3)); // 62)柯里化解决方案 参数长度固定var add = function (m) { var temp = function (n) { return add(m + n); } temp.toString = function () { return m; } return temp;};console.log(add(3)(4)(5)); // 12console.log(add(3)(6)(9)(25)); // 43对于add(3)(4)(5),其执行过程如下: 先执行add(3),此时m=3,并且返回temp函数;执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数因为前面没有传入参数,等于返回的temp函数不被执行而是打印,理解JS的敌人都晓得对象的toString是批改对象转换字符串的办法,因而代码中temp函数的toString函数return m值,而m值是最初一步执行函数时的值m=12,所以返回值是12。参数长度不固定function add (...args) { //求和 return args.reduce((a, b) => a + b)}function currying (fn) { let args = [] return function temp (...newArgs) { if (newArgs.length) { args = [ ...args, ...newArgs ] return temp } else { let val = fn.apply(this, args) args = [] //保障再次调用时清空 return val } }}let addCurry = currying(add)console.log(addCurry(1)(2)(3)(4, 5)()) //15console.log(addCurry(1)(2)(3, 4, 5)()) //15console.log(addCurry(1)(2, 3, 4, 5)()) //15查找字符串中呈现最多的字符和个数例: abbcccddddd -> 字符最多的是d,呈现了5次let str = "abcabcabcbbccccc";let num = 0;let char = ''; // 使其依照肯定的秩序排列str = str.split('').sort().join('');// "aaabbbbbcccccccc"// 定义正则表达式let re = /(\w)\1+/g;str.replace(re,($0,$1) => { if(num < $0.length){ num = $0.length; char = $1; }});console.log(`字符最多的是${char},呈现了${num}次`);转化为驼峰命名var s1 = "get-element-by-id"// 转化为 getElementByIdvar f = function(s) { return s.replace(/-\w/g, function(x) { return x.slice(1).toUpperCase(); })}Function.prototype.bindFunction.prototype.bind = function(context, ...args) { if (typeof this !== 'function') { throw new Error("Type Error"); } // 保留this的值 var self = this; return function F() { // 思考new的状况 if(this instanceof F) { return new self(...args, ...arguments) } return self.apply(context, [...args, ...arguments]) }}instanceofinstanceof运算符用于检测构造函数的prototype属性是否呈现在某个实例对象的原型链上。 ...

January 6, 2023 · 7 min · jiezi

关于javascript:从零到一手写迷你版Vue

Vue响应式设计思路Vue响应式次要蕴含: 数据响应式监听数据变动,并在视图中更新Vue2应用Object.defineProperty实现数据劫持Vu3应用Proxy实现数据劫持模板引擎提供形容视图的模板语法插值表达式{{}}指令 v-bind, v-on, v-model, v-for,v-if渲染将模板转换为html解析模板,生成vdom,把vdom渲染为一般dom数据响应式原理 数据变动时能自动更新视图,就是数据响应式Vue2应用Object.defineProperty实现数据变动的检测 原理解析new Vue()⾸先执⾏初始化,对data执⾏响应化解决,这个过程发⽣在Observer中同时对模板执⾏编译,找到其中动静绑定的数据,从data中获取并初始化视图,这个过程发⽣在 Compile中同时定义⼀个更新函数和Watcher实例,未来对应数据变动时,Watcher会调⽤更新函数因为data的某个key在⼀个视图中可能呈现屡次,所以每个key都须要⼀个管家Dep来治理多个 Watcher未来data中数据⼀旦发⽣变动,会⾸先找到对应的Dep,告诉所有Watcher执⾏更新函数 一些要害类阐明CVue:自定义Vue类 Observer:执⾏数据响应化(分辨数据是对象还是数组) Compile:编译模板,初始化视图,收集依赖(更新函数、 watcher创立) Watcher:执⾏更新函数(更新dom) Dep:治理多个Watcher实例,批量更新 波及要害办法阐明observe: 遍历vm.data的所有属性,对其所有属性做响应式,会做繁难判断,创立Observer实例进行真正响应式解决 html页面<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cvue</title> <script src="./cvue.js"></script></head><body> <div id="app"> <p>{{ count }}</p> </div> <script> const app = new CVue({ el: '#app', data: { count: 0 } }) setInterval(() => { app.count +=1 }, 1000); </script></body></html>CVue创立根本CVue构造函数:执⾏初始化,对data执⾏响应化解决// 自定义Vue类class CVue { constructor(options) { this.$options = options this.$data = options.data // 响应化解决 observe(this.$data) }}// 数据响应式, 批改对象的getter,setterfunction defineReactive(obj, key, val) { // 递归解决,解决val是嵌套对象状况 observe(val) Object.defineProperty(obj, key, { get() { return val }, set(newVal) { if(val !== newVal) { console.log(`set ${key}:${newVal}, old is ${val}`) val = newVal // 持续进行响应式解决,解决newVal是对象状况 observe(val) } } })}// 遍历obj,对其所有属性做响应式function observe(obj) { // 只解决对象类型的 if(typeof obj !== 'object' || obj == null) { return } // 实例化Observe实例 new Observe(obj)}// 依据传入value的类型做相应的响应式解决class Observe { constructor(obj) { if(Array.isArray(obj)) { // TODO } else { // 对象 this.walk(obj) } } walk(obj) { // 遍历obj所有属性,调用defineReactive进行响应化 Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key])) }}参考 前端进阶面试题具体解答 ...

January 6, 2023 · 5 min · jiezi

关于javascript:前端经典面试题有答案

Promise.resolvePromise.resolve = function(value) { // 1.如果 value 参数是一个 Promise 对象,则一成不变返回该对象 if(value instanceof Promise) return value; // 2.如果 value 参数是一个具备 then 办法的对象,则将这个对象转为 Promise 对象,并立刻执行它的then办法 if(typeof value === "object" && 'then' in value) { return new Promise((resolve, reject) => { value.then(resolve, reject); }); } // 3.否则返回一个新的 Promise 对象,状态为 fulfilled return new Promise(resolve => resolve(value));}display的属性值及其作用属性值作用none元素不显示,并且会从文档流中移除。block块类型。默认宽度为父元素宽度,可设置宽高,换行显示。inline行内元素类型。默认宽度为内容宽度,不可设置宽高,同行显示。inline-block默认宽度为内容宽度,能够设置宽高,同行显示。list-item像块类型元素一样显示,并增加款式列表标记。table此元素会作为块级表格来显示。inherit规定应该从父元素继承display属性的值。代码输入后果function Dog() { this.name = 'puppy'}Dog.prototype.bark = () => { console.log('woof!woof!')}const dog = new Dog()console.log(Dog.prototype.constructor === Dog && dog.constructor === Dog && dog instanceof Dog)输入后果:true ...

January 6, 2023 · 5 min · jiezi

关于javascript:谈谈前端性能优化面试版

前言当咱们去面试的时候,很大概率会被面试官问这么一个问题:你有尝试过对我的项目做性能优化吗?或者你理解哪些性能优化的办法?听到这个问题的你可能是这样的: 似曾相识但又说不清楚,往往只能零散地说出那么几点,难以做到有条理的答复。那么,本文就带你简略理解前端性能优化的几个次要方面,旨在抛砖引玉。 一、资源的合并和压缩申请过程中一些潜在的性能优化点: dns是否能够通过缓存缩小dns查问工夫?网络申请的过程如何走最近的网络环境?雷同的动态资源是否能够缓存?是否缩小http申请的大小和次数?是否进行服务端渲染?总结: 深刻了解http申请的过程是前端性能优化的外围。 优化外围 缩小http申请数量;缩小申请资源的大小;google首页案例学习 html压缩;css压缩;js的压缩和凌乱;文件合并;开启gzip;1.html压缩HTML代码压缩就是压缩一些在文本文件中有意义,然而在HTML中不显示的字符,包含空格,制表符,换行符等,还有一些其余意义的字符,如HTML正文也能够被压缩; 一个简略的计算: google的流量,占到整个互联网的40%,预计2016年寰球网络流量将达到1.3ZB(1ZB = 10^9TB),那么google在2016年的流量就是1.3ZB * 40%,如果google每1MB申请缩小一个字节,每年能够节俭流量近500TB流量。 如何进行html压缩 应用在线网站进行压缩;nodejs提供的html-minifier工具;后端模板引擎渲染压缩;2.css代码压缩分为两局部: 有效代码的压缩;css语义合并;如何进行css压缩 应用在线网站进行压缩;应用html-minifier对html中的css进行压缩;应用clean-css对css进行压缩;3.js压缩与凌乱(美化)包含: 有效字符的删除(空格,回车等);剔除正文;代码语义的缩减和优化;代码爱护(如果代码不经解决,客户端可间接窥探代码破绽);JS压缩与凌乱(美化) 应用在线网站进行压缩应用html-minifier对html中的js进行压缩;应用uglify.js2对js进行压缩;4.文件合并文件合并的益处: 右边的示意应用http长链接keep-alive但不合并申请的状况,须要分三次去获取a.js、b.js、c.js;左边是应用长链接并且合并申请的状况,只须要发送一次获取合并文件a-b-c.js的申请,就能将三个文件都申请回来。 不合并申请有下列毛病: 文件与文件之间有插入的上行申请,会减少N-1个网络提早;受丢包问题的影响更重大:因为每次申请都可能呈现丢包的状况,缩小申请能无效缩小丢包状况;keep-alive自身也存在问题:通过代理服务器时可能会被断开;文件合并存在的问题 首屏渲染问题:当申请js文件的时候,如果页面渲染只依赖a.js文件,因为文件合并,须要期待合并后的a-b-c.js文件申请回来能力持续渲染,这样就会导致页面渲染速度变慢。这种状况大多呈现在现代化的前端框架,如Vue等的应用过程中;缓存生效问题:合并后的文件a-b-c.js中只有其中一个文件(比方a.js)发生变化,那么整个合并文件都将生效,而不采纳文件合并就不会呈现这种状况;应用倡议 公共库合并:将不常常发生变化的公共组件库文件进行合并;将不同页面的js文件独自合并:比方在单页面利用SPA中,当路由跳转到具体的页面时才申请该页面须要的js文件;如何进行文件合并 应用在线网站进行文件合并;应用nodejs实现文件合并;应用webpack等前端构件化工具也能够很好地实现;二、图片相干的优化有损压缩过程: 一张JPG图片的解析别离要进行: 色彩空间的转换:从RGB的色彩空间转到其余的色彩空间 ;进行重采样:辨别高频和低频的色彩变换;进行DCT过程:对高频的色彩采样后果进行压缩,这样压缩的收益会比拟大;再对数据进行量化;最初进行编码(encoding);最终失去JPEG-Compressed Image Data,即真正显示进去的JPG图片。尽管这是一种有损压缩,然而很多状况下,这些损失的数据并不影响显示; png8/png24/png32之间的区别 png8:256色 + 反对通明;png24:2^24色 + 不反对通明;png32:2^32色 + 反对通明;参考 前端进阶面试题具体解答 不同格局图片罕用的业务场景 jpg有损压缩,压缩率高,反对通明;利用:大部分不须要通明图片的业务场景;png反对通明,浏览器兼容好;利用:大部分须要通明图片的业务场景;webp(2010年由谷歌推出)压缩水平更好,在ios webview中有兼容性问题;利用:安卓全副;svg矢量图,代码内嵌,绝对较小,用于图片款式绝对简略的场景;利用:比方logo和iconfont;1.图片压缩针对实在图片状况,舍弃一些绝对无关紧要的色调信息,对图片进行压缩; 2.css雪碧图将网站上用到的一些图片整合到一张独自的图片中,从而缩小网站HTTP申请数量。原理为:设定整张雪碧图可示区域,将想要显示的图标定位到该处(左上角);毛病:整合图片比拟大时,一次加载比较慢。 如天猫的雪碧图:很多状况下,并不是所有的小图标都放在一张雪碧图中,而是会适当进行拆分。当初应用雪碧图的场景比拟少了。 主动生成雪碧图款式 3.网页内联图片(Image inline)将图片的内容内嵌到html当中,缩小网站的HTTP申请数量,罕用于解决小图标和背景图片。网页内联图片写法为: <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA..." alt="">毛病: 浏览器不会缓存内联图片资源;兼容性较差,只反对ie8以上浏览器;超过1000kb的图片,base64编码会使图片大小增大,导致网页整体下载速度减慢;所以要依据场景应用,不过内联图片缩小HTTP申请的长处还是很显著的。比方,在开发中小于4KB或8KB的图片都会通过构建工具主动inline到HTML中,这种状况下Image inline带来的图片大小增长其实是比减少HTTP申请次数更优的。 4.矢量图SVG与iconfont应用iconfont解决icon问题 应尽量应用该形式,比方能够采纳阿里巴巴矢量图库: 能够抉择格局进行下载: 能够看到它们的大小有着显著的差别: 应用SVG进行矢量图的管制 SVG意为可缩放矢量图形(Scalable Vector Graphics)。SVG 应用 XML 格局定义图像。 5.webpwebp的劣势体现在它具备更优的图像压缩算法,能带来更小的图片体积,而且领有肉眼辨认无差别的图像品质;同时具备了无损和有损的压缩模式、Alpha通明以及动画的个性。在JPEG和PNG上的转化成果都十分优良、稳固和对立。安卓上不存在兼容性问题,举荐安卓下应用。 以下为淘宝网首页申请的图片: 能够看到,图片中大量地增加了webp格局的抉择。.jpg_.webp示意当浏览器反对webp时采纳webp格局,否则采纳jpg格局。 上面为B站首页的图片,能够看到根本都采纳了webp格局: ...

January 6, 2023 · 3 min · jiezi

关于javascript:如果才能做好准备好前端面试

对this对象的了解this 是执行上下文中的一个属性,它指向最初一次调用这个办法的对象。在理论开发中,this 的指向能够通过四种调用模式来判断。 第一种是函数调用模式,当一个函数不是一个对象的属性时,间接作为函数来调用时,this 指向全局对象。第二种是办法调用模式,如果一个函数作为一个对象的办法来调用时,this 指向这个对象。第三种是结构器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。第四种是 apply 、 call 和 bind 调用模式,这三个办法都能够显示的指定调用函数的 this 指向。其中 apply 办法接管两个参数:一个是 this 绑定的对象,一个是参数数组。call 办法接管的参数,第一个是 this 绑定的对象,前面的其余参数是传入函数执行的参数。也就是说,在应用 call() 办法时,传递给函数的参数必须一一列举进去。bind 办法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了应用 new 时会被扭转,其余状况下都不会扭转。这四种形式,应用结构器调用模式的优先级最高,而后是 apply、call 和 bind 调用模式,而后是办法调用模式,而后是函数调用模式。 为什么须要浏览器缓存?对于浏览器的缓存,次要针对的是前端的动态资源,最好的成果就是,在发动申请之后,拉取相应的动态资源,并保留在本地。如果服务器的动态资源没有更新,那么在下次申请的时候,就间接从本地读取即可,如果服务器的动态资源曾经更新,那么咱们再次申请的时候,就到服务器拉取新的资源,并保留在本地。这样就大大的缩小了申请的次数,进步了网站的性能。这就要用到浏览器的缓存策略了。 所谓的浏览器缓存指的是浏览器将用户申请过的动态资源,存储到电脑本地磁盘中,当浏览器再次拜访时,就能够间接从本地加载,不须要再去服务端申请了。 应用浏览器缓存,有以下长处: 缩小了服务器的累赘,进步了网站的性能放慢了客户端网页的加载速度缩小了多余网络数据传输代码输入后果var x = 3;var y = 4;var obj = { x: 1, y: 6, getX: function() { var x = 5; return function() { return this.x; }(); }, getY: function() { var y = 7; return this.y; }}console.log(obj.getX()) // 3console.log(obj.getY()) // 6输入后果:3 6 ...

January 6, 2023 · 6 min · jiezi

关于javascript:这些js原型及原型链面试题你能做对几道

一、前言在面试过程中,频频被原型相干常识问住,每次答复都支支吾吾。起初有家十分心仪的公司,在二面时,果不其然,又问原型了! 我痛下决心用了两天工夫钻研了下原型,弄明确后发现世界都亮堂了,原来这么简略 ~ 有些了解还比拟肤浅,随着工夫的推移和了解的深刻,当前还会补充。如果大家发现我了解的有问题,欢送大家在评论中斧正。话不多说,切入正题。 二、构造函数讲原型则离不开构造函数,让咱们先来意识下构造函数。 2.1 构造函数分为 实例成员 和 动态成员让咱们先来看看他们别离是什么样子的。 实例成员: 实例成员就是在构造函数外部,通过this增加的成员。实例成员只能通过实例化的对象来拜访。 动态成员: 在构造函数自身上增加的成员,只能通过构造函数来拜访 function Star(name,age) { //实例成员 this.name = name; this.age = age; } //动态成员 Star.sex = '女'; let stars = new Star('小红',18); console.log(stars); // Star {name: "小红", age: 18} console.log(stars.sex); // undefined 实例无法访问sex属性 console.log(Star.name); //Star 通过构造函数无奈间接拜访实例成员 console.log(Star.sex); //女 通过构造函数可间接拜访动态成员2.2 通过构造函数创建对象该过程也称作实例化 2.2.1 如何通过构造函数创立一个对象? function Father(name) { this.name = name; } let son = new Father('Lisa'); console.log(son); //Father {name: "Lisa"}此时,son就是一个新对象。 ...

January 6, 2023 · 4 min · jiezi

关于javascript:如何不移除p标签而将段落连接起来

这是一个很经典的CSS布局问题,新人彻底了解了这个问题,HTML网页布局思维便已把握了七七八八了。 问题先看一段HTML代码: <!DOCTYPE html><html><body><h1>这是一个题目</h1> <div class="wrapper"> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> </div></body></html>因为p标签默认是块级元素,宽度默认会占满父容器的100%,所以这个代码默认展示进去的款式是这样的: 问题与这个示例无关,是这样的:如何将三行文本“这是一个段落”合并到一行,从左向右排行显示,且不必移除<p>标签? 最简略的解决方案只须要加一行CSS款式代码: .wrapper p { display: inline;}运行成果如下所示: 为什么简略加一个inline款式就能够解决问题?晚期网页为了从向至下流式展现内容,依据须要将标签元素默认分为了两类: 块级元素行内元素块级元素默认占据父容器的100%宽度,同时能够有高度,在不指定高度的时候,高度由子元素沉积决定。例如div、p、h1~h6等标签,但凡默认在网页中占据全副页面宽度的元素,都是块级元素。 而行内元素用于在一行内从左向右展现小内容,行内元素默认只有宽度,没有高度,并且它们的宽度也是由它们自身的内容所决定的。例如a、br、b、em、img、sub、sup、strong等标签,但凡默认不占据100%父容器宽度的元素,都能够视为行内元素。如果想给行内元素指定高度,能够在父容器上给行元素设置line-height款式。 这两类元素的作用,就是合起来展现一个从上至下顺次展现、每行从左至右顺次排列的流布局,如下所示。 回头看咱们的示例,p标签默认是块级标签,它在渲染时要占满页面容器的100%宽度,所以默认成果三行文本“这是一个段落”是从上向下顺次排列的。 当咱们通过类选择器+标签选择器(.wrapper p),批改了所有p标签的display款式后,行将display款式设置为inline,这时候这个页面内的所有p标签曾经不是块级元素了,都变成了行内元素。 HTML元素是什么块级元素,还是行内元素,实质上是由它们携带的默认的CSS款式决定的,也就是由display等于block或inline决定的,等于block就是块级元素,等于inline就是行内元素。因为CSS能够管制所有HTML元素的款式,事实上咱们甚至能够将任何一个HTML元素批改为其余元素————当然如果真批改的话,这里还波及元素属性的问题,在这里咱们只谈款式。HTML元素默认携带的款式是由其名称决定的,所有元素的默认款式都是能够通过CSS代码批改的。 当给p标签设置了display款式为inline当前,这时候p标签的行为与span标签相似了,于是三行文本“这是一个段落”便是从左向右,在一行内展现了,如果一行展现不了,内容还会主动换行,就像其余行内元素所示意进去的行为那样。 由inline-block决定的行内块级元素随着网页布局复杂度的晋升,起初又呈现了inline-block款式值,咱们能够批改示例,看一看将display批改为inline-block之后的成果,如下所示。 成果与批改为inline是类似的,在这个示例中看不出什么差异。事实上inline-blcok代表行内的块级元素,这样的元素既能够在一行之内从左向右主动顺次排列,能够领有本人的高度,又能够作为一个部分的小容器,再包容其余子元素。 inline-blcok款式的呈现,代表CSS在网页布局方面曾经没有什么能力短板了,只有网页设计师想不到的,没有CSS实现的布局。 flex布局但CSS的网页布局能力倒退到这里并没有进行,起初为了更好了解决父容器与子元素的组合款式,flex布局被创造进去了。flex布局可能实现的成果,用以往的CSS也能够实现,但用flex布局的办法实现,代码会更简洁、逻辑会更加清晰、页面的扩展性也更好。 上面作者依然拿下面的示例革新,如果不设置display为inline或inline-block,应用flex布局怎么达到同样的成果呢?也是只增加一行CSS代码就足够了,如下所示。 <!DOCTYPE html><html><body> <style> .wrapper { display: flex; }</style> <h1>这是一个题目</h1> <div class="wrapper"> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> </div></body></html>运行成果如下所示: 成果是一样的。 将display设置为flex就代表了启用flex布局。因为默认状况下flex-direction等于row,子元素会像行内元素那样从左向右排行,所以只写一行display等于flex款式代码就能够了。 flex布局能力很弱小,它不仅能够解决从左向右的横向布局,还能够解决从上向下的纵向布局,两个方向的布局应用的是同一套款式语义。 很多人都感觉这套语义记了又忘,切实很难记住,即便是富有经验的网页设计师在许久不手写CSS代码之后,也须要借助工具才能够将款式代码写对。针对开发者的这个痛点,新版本的Chrome浏览器当初提供了这样的一个flex布局辅助设计性能,如下所示,当咱们给元素增加了display等于flex的款式代码后,前面会呈现一个性能按钮,点击它,会开展一个flex布局互动小面板。点击这个面板上具体的排列项,相应的款式代码即会主动生成。 当前不必再记那些难记的款式名称了,有须要的时候调出这个flex布局互动小面板,入手你发财的小手点一点,所有布局代码都能搞定了。 小结HTML开发次要有两种布局思维:传统div流式布局和flex布局。 还有一种全页面都应用绝对值定位的布局思维,这种布局思维只实用于Web治理后盾或工具Web我的项目等开发场景,对于面向C端用户的场景是不实用的。HTML网页的基本设计哲学是流式布局————整体上从上向下、行内从左向右的流式布局,这种布局能够让HTML内容能够一边加载一边渲染与展现,这是一种很好的设计哲学,不要轻易舍弃这种哲学。 flex布局实质上继承了流式布局的思维,它与流式布局并不抵触,只是丰盛了CSS在父容器子元素组合关系布局上的能力。在网页设计中,当初广泛优先应用flex布局,用最简略的CSS代码达到设计的需要。在具体设计时,配合应用Chrome开发者工具中的flex布局小面板,写起flex布局代码也很容易。 著作权归LIYI所有基于CC BY-SA 4.0协定原文链接:https://yishulun.com/posts/20...

January 5, 2023 · 1 min · jiezi

关于javascript:javascript正则高级用法

先简略看几个罕用根底标识符 ^ 匹配一个输出或一行的结尾, /^a/ // 匹配"an A",而不匹配"An a"$ 匹配一个输出或一行的结尾 /a$/// 匹配"An a",而不匹配"an A"*匹配后面元字符0次或屡次 /ba*/// 匹配b,ba,baa,baaa,...+匹配后面元字符1次或屡次 /ba+/// 匹配ba,baa,baaa,...? 匹配后面元字符0次或1次 /ba?/// 匹配b,ba(x) //匹配x保留x在名为$1...$9的变量中x|y //匹配x或y{n} //准确匹配n次{n,} //匹配n次以上{n,m} //匹配n-m次[xyz] //字符集,匹配这个汇合中的任一一个字符(或元字符),匹配x,y,z[^xyz] //不匹配这个汇合中的任何一个字符正则表达式(Regular Expression)其实是一门工具,通过字符串模式匹配,实现搜寻和替换性能。 它起源于20世纪50年代科学家在数学畛域做的一些钻研工作,起初才被引入到计算机领域中。 从它的命名咱们能够晓得,它是一种用来形容规定的表达式。而它的底层原理也非常简略,就是应用状态机的思维进行模式匹配。 这里先不细纠概念,罕用的办法属性,文档mdn什么都有,也不纠结,直奔主题。 子表达式子表达式(Reg)具备独立的匹配性能,保留独立的匹配后果 作为独立单元能够应用*+?{n,m}等量词 /(ab)?c)/ // 匹配c或者abc作为子模式能够独立解决,并且保留匹配后果子串,可通过RegExp.$1,...$n拜访 var re = /(\w+)\s(\w+)/;var str = "John Smith";var newstr = str.replace(re, "$2, $1");console.log(newstr); // Smith, John以下RegExp属性,不是w3c规范,不过大部浏览器反对 RegExp属性形容$n第 n 个子表达式匹配的字符串,只有1-9$&最初匹配到的字符串,RegExp.lastMatch别名$'最新匹配的右侧子串,RegExp.rightContext 别名$`最新匹配的左侧子串,RegExp.leftContext别名$+匹配到的最初一个子串,RegExp.lastParen别名$_被匹配胜利的原字符串,RegExp.input别名对应replace函数中拜访正则后果的参数 变量名形容$n插入第 n 个子表达式匹配的字符串,只有1-99$&插入匹配的子串$'插入以后匹配的子串左边的内容$`插入以后匹配的子串右边的内容$<name>匹配[Name]具名子表达式的字符串回溯援用(反向援用),模式的前面局部援用后面子表达式曾经匹配到的子字符串 通过反斜杠\加数字来实现的。数字代表子表达式在该正则表达式中的程序。例如: \1 援用的是第一个子表达式的匹配后果 是匹配后果不是匹配模式var s = "<h1>title<h1><p>text<p>";var r = /(<\/?\w+>).*\1/g;// 相当于/(<\/?\w+>).*(<h1>|<p>)/g// 再加(<\/?\w+>)匹配后果 === (<h1>|<p>)匹配后果var a = s.match(r); //返回数组["<h1>title<h1>","<p>text<p>"]子表达式的高级模式非捕捉模式,匹配后果不会保留/(?:\w+)\s(\w+)/// ?:标识非捕捉// $1 从第二个子表达式开始计算命名捕捉,这个用的较少var re = /(?<myName>\w+)\s(\w+)/;console.log("John Smith".match(re));// (?<Name>x)// 匹配后果保留在匹配项的 groups 属性中 ...

January 5, 2023 · 1 min · jiezi

关于javascript:前端二面手写面试题总结

解析 URL Params 为对象let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';parseParam(url)/* 后果{ user: 'anonymous', id: [ 123, 456 ], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型 city: '北京', // 中文需解码 enabled: true, // 未指定值得 key 约定为 true}*/function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来 const paramsArr = paramsStr.split('&'); // 将字符串以 & 宰割后存到数组中 let paramsObj = {}; // 将 params 存到对象中 paramsArr.forEach(param => { if (/=/.test(param)) { // 解决有 value 的参数 let [key, val] = param.split('='); // 宰割 key 和 value val = decodeURIComponent(val); // 解码 val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字 if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则增加一个值 paramsObj[key] = [].concat(paramsObj[key], val); } else { // 如果对象没有这个 key,创立 key 并设置值 paramsObj[key] = val; } } else { // 解决没有 value 的参数 paramsObj[param] = true; } }) return paramsObj;}实现apply办法apply原理与call很类似,不多赘述 ...

January 5, 2023 · 10 min · jiezi

关于javascript:JS继承有哪些你能否手写其中一两种呢

引言JS系列暂定 27 篇,从根底,到原型,到异步,到设计模式,到架构模式等, 本篇是 JS系列中第 3 篇,文章主讲 JS 继承,包含原型链继承、构造函数继承、组合继承、寄生组合继承、原型式继承、 ES6 继承,以及 多继承与 new 。 ES5 继承先定义一个父类 function SuperType () { // 属性 this.name = 'SuperType';}// 原型办法SuperType.prototype.sayName = function() { return this.name;};一、 原型链继承根本思维将父类的实例作为子类的原型 // 父类function SuperType () { this.name = 'SuperType'; // 父类属性}SuperType.prototype.sayName = function () { // 父类原型办法 return this.name;};// 子类function SubType () { this.subName = "SubType"; // 子类属性};SubType.prototype = new SuperType(); // 重写原型对象,代之以一个新类型的实例// 这里实例化一个 SuperType 时, 实际上执行了两步// 1,新创建的对象复制了父类构造函数内的所有属性及办法// 2,并将原型 __proto__ 指向了父类的原型对象SubType.prototype.saySubName = function () { // 子类原型办法 return this.subName;}// 子类实例let instance = new SubType();// instanceof 通过判断对象的 prototype 链来确定对象是否是某个类的实例instance instanceof SubType; // trueinstance instanceof SuperType; // true// 留神SubType instanceof SuperType; // falseSubType.prototype instanceof SuperType ; // true ...

January 5, 2023 · 4 min · jiezi

关于javascript:腾讯前端二面高频手写面试题总结

实现LRU淘汰算法LRU 缓存算法是一个十分经典的算法,在很多面试中常常问道,不仅仅包含前端面试 LRU 英文全称是 Least Recently Used,英译过去就是” 最近起码应用 “的意思。LRU 是一种罕用的页面置换算法,抉择最近最久未应用的页面予以淘汰。该算法赋予每个页面一个拜访字段,用来记录一个页面自上次被拜访以来所经验的工夫 t,当须淘汰一个页面时,抉择现有页面中其 t 值最大的,即最近起码应用的页面予以淘汰艰深的解释: 如果咱们有一块内存,专门用来缓存咱们最近发拜访的网页,拜访一个新网页,咱们就会往内存中增加一个网页地址,随着网页的一直减少,内存存满了,这个时候咱们就须要思考删除一些网页了。这个时候咱们找到内存中最早拜访的那个网页地址,而后把它删掉。这一整个过程就能够称之为 LRU 算法 上图就很好的解释了 LRU 算法在干嘛了,其实非常简单,无非就是咱们往内存外面增加或者删除元素的时候,遵循最近起码应用准则 应用场景 LRU 算法应用的场景十分多,这里简略举几个例子即可: 咱们操作系统底层的内存治理,其中就包含有 LRU 算法咱们常见的缓存服务,比方 redis 等等比方浏览器的最近浏览记录存储vue中的keep-alive组件应用了LRU算法梳理实现 LRU 思路 特点剖析: 咱们须要一块无限的存储空间,因为有限的化就没必要应用LRU算发删除数据了。咱们这块存储空间外面存储的数据须要是有序的,因为咱们必须要程序来删除数据,所以能够思考应用 Array、Map 数据结构来存储,不能应用 Object,因为它是无序的。咱们可能删除或者增加以及获取到这块存储空间中的指定数据。存储空间存满之后,在增加数据时,会主动删除工夫最长远的那条数据。实现需求: 实现一个 LRUCache 类型,用来充当存储空间采纳 Map 数据结构存储数据,因为它的存取时间复杂度为 O(1),数组为 O(n)实现 get 和 set 办法,用来获取和增加数据咱们的存储空间有长度限度,所以无需提供删除办法,存储满之后,主动删除最长远的那条数据当应用 get 获取数据后,该条数据须要更新到最后面具体实现 class LRUCache { constructor(length) { this.length = length; // 存储长度 this.data = new Map(); // 存储数据 } // 存储数据,通过键值对的形式 set(key, value) { const data = this.data; if (data.has(key)) { data.delete(key) } data.set(key, value); // 如果超出了容量,则须要删除最久的数据 if (data.size > this.length) { const delKey = data.keys().next().value; data.delete(delKey); } } // 获取数据 get(key) { const data = this.data; // 未找到 if (!data.has(key)) { return null; } const value = data.get(key); // 获取元素 data.delete(key); // 删除元素 data.set(key, value); // 从新插入元素 return value // 返回获取的值 }}var lruCache = new LRUCache(5);set 办法:往 map 外面增加新数据,如果增加的数据存在了,则先删除该条数据,而后再增加。如果增加数据后超长了,则须要删除最长远的一条数据。data.keys().next().value 便是获取最初一条数据的意思。get 办法:首先从 map 对象中拿出该条数据,而后删除该条数据,最初再从新插入该条数据,确保将该条数据挪动到最后面// 测试// 存储数据 set:lruCache.set('name', 'test');lruCache.set('age', 10);lruCache.set('sex', '男');lruCache.set('height', 180);lruCache.set('weight', '120');console.log(lruCache); ...

January 5, 2023 · 14 min · jiezi

关于javascript:js函数柯里化面试手写版

概念用我本人的话来总结一下,函数柯里化的意思就是你能够一次传很多参数给curry函数,也能够分屡次传递,curry函数每次都会返回一个函数去解决剩下的参数,始终到返回最初的后果。 实例这里还是举几个例子来阐明一下: 柯里化求和函数 // 一般形式 var add1 = function(a, b, c){ return a + b + c; } // 柯里化 var add2 = function(a) { return function(b) { return function(c) { return a + b + c; } } }这里每次传入参数都会返回一个新的函数,这样始终执行到最初一次返回a+b+c的值。然而这种实现还是有问题的,这里只有三个参数,如果哪天产品经理通知咱们须要改成100次?咱们就从新写100次?这很显著不合乎开闭准则,所以咱们须要对函数进行一次批改。 var add = function() { var _args = []; return function() { if(arguments.length === 0) { return _args.reduce(function(a, b) { return a + b; }) } [].push.apply(_args, arguments); return arguments.callee; }}var sum = add();sum(100, 200)(300);sum(400);sum(); // 1000咱们通过判断下一次是否传进来参数来决定函数是否运行,如果持续传进了参数,那咱们持续把参数都保存起来,等运行的时候全副一次性运行,这样咱们就初步实现了一个柯里化的函数。 ...

January 5, 2023 · 3 min · jiezi

关于javascript:2023我的前端面试小结

首屏和白屏工夫如何计算首屏工夫的计算,能够由 Native WebView 提供的相似 onload 的办法实现,在 ios 下对应的是 webViewDidFinishLoad,在 android 下对应的是onPageFinished事件。 白屏的定义有多种。能够认为“没有任何内容”是白屏,能够认为“网络或服务异样”是白屏,能够认为“数据加载中”是白屏,能够认为“图片加载不进去”是白屏。场景不同,白屏的计算形式就不雷同。 办法1:当页面的元素数小于x时,则认为页面白屏。比方“没有任何内容”,能够获取页面的DOM节点数,判断DOM节点数少于某个阈值X,则认为白屏。 办法2:当页面呈现业务定义的错误码时,则认为是白屏。比方“网络或服务异样”。 办法3:当页面呈现业务定义的特征值时,则认为是白屏。比方“数据加载中”。 具体阐明 Event loop家喻户晓 JS 是门非阻塞单线程语言,因为在最后 JS 就是为了和浏览器交互而诞生的。如果 JS 是门多线程的语言话,咱们在多个线程中解决 DOM 就可能会产生问题(一个线程中新加节点,另一个线程中删除节点),当然能够引入读写锁解决这个问题。 JS 在执行的过程中会产生执行环境,这些执行环境会被程序的退出到执行栈中。如果遇到异步的代码,会被挂起并退出到 Task(有多种 task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出须要执行的代码并放入执行栈中执行,所以实质上来说 JS 中的异步还是同步行为。 console.log('script start');setTimeout(function() { console.log('setTimeout');}, 0);console.log('script end');以上代码尽管 setTimeout 延时为 0,其实还是异步。这是因为 HTML5 标准规定这个函数第二个参数不得小于 4 毫秒,有余会主动减少。所以 setTimeout 还是会在 script end 之后打印。 不同的工作源会被调配到不同的 Task 队列中,工作源能够分为 微工作(microtask) 和 宏工作(macrotask)。在 ES6 标准中,microtask 称为 jobs,macrotask 称为 task。 console.log('script start');setTimeout(function() { console.log('setTimeout');}, 0);new Promise((resolve) => { console.log('Promise') resolve()}).then(function() { console.log('promise1');}).then(function() { console.log('promise2');});console.log('script end');// script start => Promise => script end => promise1 => promise2 => setTimeout以上代码尽管 setTimeout 写在 Promise 之前,然而因为 Promise 属于微工作而 setTimeout 属于宏工作,所以会有以上的打印。 ...

January 5, 2023 · 5 min · jiezi

关于javascript:深入理解JS作用域链与执行上下文

变量晋升:变量晋升( hoisting )。 我可恨的 var 关键字:你读完上面内容就会明确题目的含意,先来一段超级简略的代码: <script type="text/javascript"> var str = 'Hello JavaScript hoisting'; console.log(str); // Hello JavaScript hoisting</script>这段代码,很意外地简略,咱们的到了想要的后果,在控制台打印出了:Hello JavaScript hoisting 。 当初,我将这一段代码,改一改,将 调用 放在后面, 申明 放在前面。 很多语言比如说 C 或者 C++ 都是不容许的,然而 javaScript 容许。 你们试着猜猜失去的后果: <script type="text/javascript"> console.log(str); // undefined var str = 'Hello JavaScript hoisting'; console.log(str); // Hello JavaScript hoisting</script>你会感觉很奇怪,在咱们调用之前,为什么咱们的 str = undefined ,而不是报错:未定义??? 我将 var str = 'Hello JavaScript hoisting' 删除后,试试思考这段代码的后果: <script type="text/javascript"> console.log(str); // Uncaught ReferenceError: str is not defined</script>当初失去了,咱们想要的,报错:未定义。 ...

January 5, 2023 · 3 min · jiezi

关于javascript:2023我的前端面试小结

对事件委托的了解(1)事件委托的概念事件委托实质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,父节点能够通过事件对象获取到指标节点,因而能够把子节点的监听函数定义在父节点上,由父节点的监听函数对立解决多个子元素的事件,这种形式称为事件委托(事件代理)。 应用事件委托能够不必要为每一个子元素都绑定一个监听事件,这样缩小了内存上的耗费。并且应用事件代理还能够实现事件的动静绑定,比如说新增了一个子节点,并不需要独自地为它增加一个监听事件,它绑定的事件会交给父元素中的监听函数来解决。 (2)事件委托的特点缩小内存耗费如果有一个列表,列表之中有大量的列表项,须要在点击列表项的时候响应一个事件: <ul id="list"> <li>item 1</li> <li>item 2</li> <li>item 3</li> ...... <li>item n</li></ul>如果给每个列表项一一都绑定一个函数,那对于内存耗费是十分大的,效率上须要耗费很多性能。因而,比拟好的办法就是把这个点击事件绑定到他的父层,也就是 ul 上,而后在执行事件时再去匹配判断指标元素,所以事件委托能够缩小大量的内存耗费,节约效率。 动静绑定事件给上述的例子中每个列表项都绑定事件,在很多时候,须要通过 AJAX 或者用户操作动静的减少或者去除列表项元素,那么在每一次扭转的时候都须要从新给新增的元素绑定事件,给行将删去的元素解绑事件;如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和指标元素的增减是没有关系的,执行到指标元素是在真正响应执行事件函数的过程中去匹配的,所以应用事件在动静绑定事件的状况下是能够缩小很多反复工作的。 // 来实现把 #list 下的 li 元素的事件代理委托到它的父层元素也就是 #list 上:// 给父层元素绑定事件document.getElementById('list').addEventListener('click', function (e) { // 兼容性解决 var event = e || window.event; var target = event.target || event.srcElement; // 判断是否匹配指标元素 if (target.nodeName.toLocaleLowerCase === 'li') { console.log('the content is: ', target.innerHTML); }});在上述代码中, target 元素则是在 #list 元素之下具体被点击的元素,而后通过判断 target 的一些属性(比方:nodeName,id 等等)能够更准确地匹配到某一类 #list li 元素之上; (3)局限性当然,事件委托也是有局限的。比方 focus、blur 之类的事件没有事件冒泡机制,所以无奈实现事件委托;mousemove、mouseout 这样的事件,尽管有事件冒泡,然而只能一直通过地位去计算定位,对性能耗费高,因而也是不适宜于事件委托的。 ...

January 5, 2023 · 6 min · jiezi

关于javascript:经常会采坑的javascript原型应试题

一. 前言原型和原型链在面试中从来备受器重,常常被提及。说难可能也不太难,但要真正齐全了解,吃透它,还是要多下功夫的。 上面为大家简略论述我对原型和原型链的了解,若是感觉有说的不对的中央,还请帮忙斧正,或者敞开页面不节约您的宝贵时间(胆怯) 二. 注释原型JavaScript所有的对象实质上都是通过new 函数创立的,包含对象字面量的模式定义对象(相当于new Object()的语法糖)。所有的函数实质上都是通过new Function创立的,包含Object、Array等(隐式执行,是咱们看不到的但在执行过程中产生过的)所有的函数都是对象。分析Prototype(显式原型) 每个函数都有一个属性prototype,它就是原型,默认状况下它是一个一般Object对象,这个对象是调用该构造函数所创立的实例的原型。 __proto__(谷歌浏览器已更新为[[prototype]],隐式原型)JavaScript中所有对象(除了null)都具备一个__proto__属性,该属性指向该对象的原型。 上图中,函数身上的属性,会被显式的继承到,即 //this.name=’wn’, 此时显式的不存在,所以继承不到,然而函数的原型上有属性,就会被隐式的继承到,即 name: "小南" contructor属性 JavaScript同样存在由原型指向构造函数的属性:constructor,即Func.prototype.constructor --> Func 原型链实例对象在查找属性时,如果查找不到,就会沿着__proto__去与对象关联的原型上查找,如果还查找不到,就去找原型的原型,直至查到最顶层,这也就是原型链的概念。 参考 前端进阶面试题具体解答 通过这张图咱们能够留神到,构造函数Foo的原型prototype 和 构造函数Foo所创立进去的对象实例f1,f2的原型__proto__是一样的都指向Foo().prototype. 这里咱们能够持续思考,往下摸索一下,既然Foo().prototype也是一个对象,那是不是Foo().prototype也有本人的对象原型__proto__呢.答案是必定的,图中咱们也能够看到Foo().prototype的对象原型__proto__指向的是Object.prototype. Object作为最顶端的构造函数,能够看到所有的对象都会通过原型链指向它.这就是为什么新建的对象为什么可能应用 toString() 等办法的起因. 然而咱们能够发现Object.prototype也有本人的__proto__ 然而却指向的是null,null为原型链的起点. 留神!!!那么这里还个问题,仔细的小伙伴曾经发现了,构造函数有本人的原型prototype,然而构造函数也是对象啊,构造函数也有没有__proto__呢.答案是有的.因为每个 JavaScript 函数实际上都是一个 Function 对象。运行 function(){}).constructor === Function // true 便能够失去这个论断。 而且通过图咱们也能够发现 Foo的__proto__指向Function.prototype,而且这里还有个特例,上文也阐明了每个 JavaScript 函数实际上都是一个 Function 对象,所以Function的构造函数原型prototype和对象原型__proto__都是指向同一个Function.prototype. 结语原型和原型链算是js里的一座大山,比拟偏概念性,在面试时是经常出现的,所以闲时能够多拿进去推敲。鄙人写的也略有通俗,心愿能帮到查阅的小伙伴呀。码字不易,还望看到这里的小伙伴用用发财的小手点点赞,与君共勉!

January 5, 2023 · 1 min · jiezi

关于javascript:一文教会你mockMockito和PowerMock双剑合璧

作者:京东物流 杨建民1.什么是Mock Mock有模拟、伪造的含意。Mock测试就是在测试过程中,对于某些不容易结构或者不容易获取的对象,用一个虚构的对象来创立以便测试的测试方法。mock工具应用领域: 实在对象具备不确定的行为,产生不可预测的成果。实在对象很难被创立。实在对象的某些行为很难被触发。实在对象实际上还不存在。 MockIto和PowerMock是泛滥Mock框架中的两种,相似的还有:JMock,EasyMock,大多 Java Mock 库如 EasyMock 或 JMock 都是 expect-run-verify (冀望-运行-验证)形式,而 Mockito 则应用更简略,更直观的办法:在执行后的互动中发问。应用 Mockito,你能够验证任何你想要的。而那些应用 expect-run-verify 形式的库,你经常被迫查看无关的交互。非 expect-run-verify 形式 也意味着,Mockito无需筹备低廉的后期启动。他们的指标是通明的,让开发人员专一于测试选定的行为。 2.解决的问题咱们在写单元测试时,总会遇到相似这些问题: 1. 结构的入参,对于极值、异样边界场景不好复现,相干的逻辑测不到,只能依附测试环境或预发跑,运气不好可能要改好几次代码重启机器验证,费时费力; 2. 依赖他人接口,可能须要他人帮助测试环境数据库插数能力跑通; 3. 依赖的他人的接口还没有开发完,为了不影响提测,如何实现单元测试? 4. 编写的单元测试依赖测试数据库的数据,每次跑都要数据库改数? 5. 对service层加了逻辑,跑单元测试本地验证的时候,因为种种原因,本地环境跑不起来,折腾半天跑起来验证完了,下次开发需要又遇到了另一个问题本地环境启动报错??? 6. 我就想dubug到某一行代码,然而逻辑简单,七拼八凑的参数就是走不到,本人看代码逻辑还要去问他人接口的返回值逻辑??(未完待续……)引入Mockito和PowerMock使得编写单元测试更轻松,更省时,更省力。 3.如何解决问题3.1  应用mock的意义  简略说就是无论谁的本地环境,无论判断条件如许刻薄,无论本地数据库的测试数据被谁删了改了,无论他人接口的返回值逻辑多简单,无论本人代码逻辑多简单,都能独立的、可反复执行的、行级别笼罩的单元测试用例。 3.2 Mockito和PowerMock   一句话说Mockito和PowerMock。当所测逻辑里有动态工具类办法或公有办法咱们心愿他返回特定值时(极值边界、异样测试场景),咱们要用到PowerMock去补救Mockito的有余,除此之外,用Mockito去写单测能实现咱们日常工作95%的场景。 3.3  应用Mcokito和PowerMock的最佳实际3.3.1  引入pom文件 3.3.2  Mockito和PowerMock 两条通用语法  打桩: when(XXxService.xxMethod("冀望入参")).thenReturn("冀望出参"); 验证:verify(XXxService).xxMethod("冀望入参"); 4.举例说明4.1 SpringBoot我的项目下Mockito和PowerMock最佳实际classes: 指定要加载的类properties: 指定要设置属性@InjectMocks: 须要注入mock对象的Bean@MockBean或@Mock: 须要mock的Beanimport X;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.InjectMocks;import org.mockito.MockitoAnnotations;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PowerMockIgnore;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;/** * 测试类A,调用服务B和一个动态工具类X */@RunWith(PowerMockRunner.class)@SpringBootTest(classes = { A.class})@PowerMockIgnore({"javax.management.*"})@PrepareForTest({X.class}) //mock 静态方法public class ATest { @InjectMocks private A a; @Mock private B b; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void Test() { when(b.someMethodB(any())).thenReturn(someThingB()); a.someMethodA(someThingA1(), someThingA2()); verify(b).someMethodB(any()); } /** * 异样边界测试 */ @Test public void test_ExceptionTest() throws ParseException { PowerMockito.mockStatic(X.class); // 模仿异样抛出的场景 when(X.strToDate(anyString(), anyString())).thenThrow(ParseException.class); when(X.convertLocalDateTime(any())).thenReturn(someThing()); when(b.someMethodB(any())).thenReturn(someThingB()); a.someThingA(someThingA1(), someThingA2()); verify(b).someMethodB(any()); }优雅的mock能够思考@spy,当然,mockito还有一些个性能够自行学习如: ...

January 5, 2023 · 1 min · jiezi

关于javascript:虚拟现实-VR-碰撞-3D-可视化图扑打造一体化管控平台

前言工信部《虚拟现实产业倒退白皮书 5.0 》中明确提出:“通过财政资金促成虚拟现实技术产业化,反对面向工业、文化、教育等重点行业的虚拟现实技术利用”。 虚拟现实 VR 技术以用户体验视角为核心,跟踪反馈在 3D 场景中的动作,借助软硬件设施,使用户齐全沉迷其中。虚拟现实软件通常为实时视景仿真模仿驱动软件,用于环境渲染、视觉个性定义、场景形容。其蕴含多类可交互的可视化脚本,通过可视化操作建设三维场景仿真模型,并将其寄存在利用定义文件中,而后应用程序就能够调用对应的函数库对已建好的三维可视化场景进行渲染驱动。  对于虚拟现实 虚拟现实技术(Virtual Reality,VR),又称灵境技术,具备感知性、沉迷感、交互性的重要特色。 以计算机技术为外围,交融三维图形技术、仿真技术、显示技术等多类高新技术的最新倒退成绩,借助计算机等设施生成与真实世界视觉、听觉、触觉等高度近似的数字化环境,从而让处于虚拟世界中的人产生一种身临其境的感觉和体验。 成果展现图扑软件自研 HT for Web 产品通过适配 VR 设施,即可与虚拟环境中的各类物体进行抓取、挪动、拆分等交互动作。现已适配 HTC Vive、Oculus、Qeust2、Pico 等各种 VR 设施。 VR 智慧工业在工业场景中虚拟现实 VR 技术联合 3D 可视化,以数字孪生形式模仿事实中的环境,造成一个可控的虚拟环境空间。虚构场景内更加人性化的解决传统工业设计、研发、拆卸、培修、培训等大多数弊病。 图扑软件 VR 智慧工业场景,使用自研图形引擎,1:1 仿真还原物理设施模型。笼罩生产过程监控、设施点巡检、近程故障诊断、无人值守等工业互联网场景。反对通过预设,实现漫游、手动巡检、主动巡检等作业需要。成果具备强烈的沉迷感,真实感和画面感。 VR 重卡汽车生产线以图扑重卡汽车生产线解决方案为背景,利用自研 HT for Web 产品实在复现设施的基本操作、运行解决、故障剖析等作业态势。 依靠 VR 设施,用户进入虚拟环境,可 360° 全方位行走,模仿事实环境中的拿、放、抓、投等一系列行为,帮忙用户充沛感触到虚拟环境中产品的实在状态,近距离实时把握研发制作、测试运行、经营保护等运作态势。 虚构拆卸场景内依靠 3D 可视化、近程遥控、实时诊断等性能特点,强化与数字孪生模型及数据的兼容水平,倒逼生产和品质两端改良,进步产能利用率,升高返工频率。 虚构流水线场景中同样反对演示车头、车身、机械部件拆解、配备制作、巡检培修以及实操培训等互动展现。坚固作业人员对各类操作技能的娴熟水平,或用作外部专业知识培训遍及,理解汽车构造和运作原理。突破事实当中物理老本的限度,实现从宏观到宏观的综合考量。 对于重卡生产流程演示可视化场景,能够查阅《推动中国制作降级,汽车装配车间生产流水线 3D 可视化》案例文章。 VR 设施拆解演示以往在钻研工业设施的应用和结构时,通常须要将设施拆解再组合。但因为很多机械设备自身具备肯定危险性,在拆解组合过程中带来肯定危险。且局部设施价格昂贵,重复拆解也会升高设施的使用寿命。如传动装置的齿轮传动、链传动和带传动,亦或是压力机械的冲床、剪床、弯边机、粉碎机、碾压机、压印机和模压机等等。图扑软件 VR 可视化的呈现,完满的解决了这些难题。 通过图扑软件图形引擎弱小的渲染性能,将工业设施的各个部件孪生搭建。进入虚拟空间后,以遥控 VR 手柄收回的射线代替双手,将模型抓取至需要地位,具体查看其前、后、左、右、上、下等任意角度。无效防止了因事实机械设备过重、过贵、过大,而造成得展现不全面。 针对设施布局可削减拆解演示模块,利用 VR 手柄对设施整机进行拆解、组装、旋转等操作,展示外部布局细节,配合面板释义,论述设施作用和性能。 或将设施透明化展示,加以具备科技感的线框模式,不便作业人员理解外在结构特征及运作原理。图扑软件可提供独具创新性的 VR 手电筒透视巡检性能,帮忙更无效解决难以“透视”把握外部结构的难题,缩短设施培修周期,大幅晋升工作精度与运维效率。 ...

January 4, 2023 · 1 min · jiezi

关于javascript:Nydus-镜像扫描加速

文|余硕 上海交通大学22届毕业生阿里云开发工程师 从事云原生底层零碎的开发和摸索工作。 本文 6369 字 浏览 16 分钟 GitLink 编程夏令营是在 CCF 中国计算机学会领导下,由 CCF 开源倒退委员会(CCF ODC)举办的面向全国高校学生的暑期编程流动。 这是往年的夏令营流动中,余硕同学加入 Nydus 开源我的项目的总结,次要介绍了 Nydus 为反对镜像扫描与修复所做的钻研与相干工作。 PART. 1 课题背景Nydus 开源镜像减速框架Nydus 是 CNCF 孵化我的项目 Dragonfly 的子项目,它提供了容器镜像,代码包按需加载的能力。Nydus 利用时无需期待全副数据下载实现便可开始服务。 Nydus 在生产环境中曾经撑持了每日百万级别的减速镜像容器创立。它在容器启动性能、镜像空间占用、网络带宽效率、端到端数据一致性等方面相比 OCI v1 格局有着微小劣势,并可扩大至其它数据散发场景,比方 NPM 包懒加载等。 目前 Nydus 由蚂蚁团体、阿里云、字节跳动联合开发。Containerd、Podman 社区曾经承受了 Nydus 运行时作为其社区子项目,它也是 Kata Containers 以及 Linux v5.19 内核态原生反对的镜像减速计划。 无关 Nydus 镜像减速开源我的项目的具体介绍,能够参考:Nydus——下一代容器镜像的摸索实际。 我的项目形容为 Nydus 镜像减少一个扫描和修复的命令行工具,蕴含以下性能: 提供一个 Nydus 镜像 url 和须要替换的文件列表;应用工具拉取镜像 Bootstrap;找到镜像中对应的文件并替换;打包成新的镜像并上传回 Registry。概括来说,原有我的项目指标是为 Nydus 镜像实现一个扫描和修复的命令行工具,其中这些性能是这个工具或者工具组的实现流程。 但此我的项目具备肯定的实验性,其外围是为 Nydus 格局的镜像提供扫描和修复的性能或者指引。如果存在更好的形式,我的项目最终不肯定要依照原有我的项目形容去实现。因而在接下来的课题实现过程中,咱们首先对已有镜像扫描/修复的工具与服务进行了调研,来确定此课题计划的最终状态。 ...

January 4, 2023 · 3 min · jiezi

关于javascript:滴滴前端一面经典手写面试题2

实现bind实现bind要做什么 返回一个函数,绑定this,传递预置参数bind返回的函数能够作为构造函数应用。故作为构造函数时应使得this生效,然而传入的参数仍然无效// mdn的实现if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // this instanceof fBound === true时,阐明返回的fBound被当做new的结构函数调用 return fToBind.apply(this instanceof fBound ? this : oThis, // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 保护原型关系 if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } // 上行的代码使fBound.prototype是fNOP的实例,因而 // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例 fBound.prototype = new fNOP(); return fBound; };}手写 Promise.all1) 外围思路 ...

January 4, 2023 · 9 min · jiezi

关于javascript:面试官请实现Javascript发布订阅模式2

简介公布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态产生扭转的时候,所有依赖他的对象都会失去告诉。 回顾已经作为一名前端开发人员,给DOM节点绑定事件可是再频繁不过的事件。比方如下代码 document.body.addEventListener('click',function () { alert(2333); },false); document.body.click();//模仿点击事件这里咱们订阅了document.body的click事件,当body被点击的时候,他就向订阅者公布这个音讯,弹出2333.咱们也能够随便的减少和删除订阅者,当音讯一公布,所有的订阅者都会收到音讯。 document.body.addEventListener('click',function () { alert(11111); },false); document.body.addEventListener('click',function () { alert(222); },false); document.body.addEventListener('click',function () { alert(333); },false); document.body.click();//模仿点击事件值得注意的是,手动触发事件这里咱们间接用了document.body.click();然而更好的做法是IE下用fireEvent,规范浏览器下用dispatchEvent,如下: let fireEvent = function (element,event) { if (document.createEventObject) { var evt = document.createEventObject(); return element.fireEvent('on'+event,evt); }else{ var evt = document.createEvent('HTMLEvents'); evt.initEvent(event,true,true); return element.dispatchEvent(evt); } } document.addEventListener('shout',function (event) { alert('shout'); }) fireEvent(document,'shout');畅谈当初人的日常生活离不开各种人际交涉,比方你的敌人有很多,这时候你要结婚了,要以你为发布者,关上你的通讯录,挨个打电话告诉各个订阅者你要结婚的音讯。形象一下,实现公布-订阅模式须要: 发布者(你)缓存列表(通讯录,你的敌人们相当于订阅了你的所有音讯)公布音讯的时候遍历缓存列表,顺次触发外面寄存的订阅者的回调函数(挨个打电话)另外,回调函数中还能够增加很多参数,,订阅者能够接管这些参数,比方你会通知他们婚礼工夫,地点等,订阅者收到音讯后能够进行各自的解决。let yourMsg = {};yourMsg.peopleList = [];yourMsg.listen = function (fn) { this.peopleList.push(fn);}yourMsg.triger = function () { for(var i = 0,fn;fn=this.peopleList[i++];){ fn.apply(this,arguments); }}yourMsg.listen(function (name) { console.log(`${name}收到了你的音讯`);})yourMsg.listen(function (name) { console.log('哈哈');})yourMsg.triger('张三');yourMsg.triger('李四'); ...

January 4, 2023 · 2 min · jiezi

关于javascript:滴滴前端一面常考手写面试题合集

应用Promise封装AJAX申请// promise 封装实现:function getJSON(url) { // 创立一个 promise 对象 let promise = new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest(); // 新建一个 http 申请 xhr.open("GET", url, true); // 设置状态的监听函数 xhr.onreadystatechange = function() { if (this.readyState !== 4) return; // 当申请胜利或失败时,扭转 promise 的状态 if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; // 设置谬误监听函数 xhr.onerror = function() { reject(new Error(this.statusText)); }; // 设置响应的数据类型 xhr.responseType = "json"; // 设置申请头信息 xhr.setRequestHeader("Accept", "application/json"); // 发送 http 申请 xhr.send(null); }); return promise;}树形构造转成列表(解决菜单)[ { id: 1, text: '节点1', parentId: 0, children: [ { id:2, text: '节点1_1', parentId:1 } ] }]转成[ { id: 1, text: '节点1', parentId: 0 //这里用0示意为顶级节点 }, { id: 2, text: '节点1_1', parentId: 1 //通过这个字段来确定子父级 } ...]实现代码如下: ...

January 4, 2023 · 12 min · jiezi

关于javascript:高频js手写题之实现数组扁平化深拷贝总线模式

前言今人学识无遗力,少壮时间老始成。纸上得来终觉浅,绝知此事要躬行。看懂一道算法题很快,但咱们必须将这道题的思路理清、手写进去。 三道js手写题的思路和代码实现数组扁平化演示成果 将[1, [1, 2], [1, [2]]] 变成 [1, 1, 2, 1, 2] 第一种: 间接应用.flat console.log([1, [1,2],[1,[2]]].flat(3));能够将多维数组,降维,传的参数是多少就降多少维个别间接传参数为 Infinity(简略粗犷) 第二种: 递归办法的办法 + 借用数组的API实现(1) function flattten(arr) { var result = []; for(var i = 0, len = arr.length; i < len; i++) { if(Array.isArray(arr[i])) { // Array.isArray 判断是否为数组 result = result.concat(flattten(arr[i])) // concat() 办法用于连贯两个或多个数组。 } else { result.push(arr[i]) } } return result;}(2) function flatten(arr) { return arr.reduce((pre, cur) => { return pre.concat(Array.isArray(cur) ? flatten(cur) : cur); }, []);}第四种: some + ...(扩大运算符) + .concat ...

January 4, 2023 · 5 min · jiezi

关于javascript:input-获取光标位置与设置光标位置

需要输入框,反对键盘输入与快捷按键 输出,UI 如下「基于antd」: 关键点:键盘输入间接应用 input onChange 事件即可,快捷按键输出须要依据光标地位插入,插入后光标在新插入的字符后。 解决方案获取 input 光标地位通过 element.selectionStart 获取光标地位。 const inputDom = document.getElementById("input")const selectionStart = inputDom.selectionStart 如图,此时的 selectionStart 是 3。 设置 input 光标通过 element.setSelectionRange() 设置光标地位,前提是 input 被 focus。 inputDom.focus()// focus() 异步,所以加了 setTimeoutsetTimeout(() => { const nextSelection = selectionStart + 1 inputDom.setSelectionRange(nextSelection, nextSelection)}, 0)element.setSelectionRange 语法 element.setSelectionRange(selectionStart, selectionEnd [, selectionDirection]); selectionStart: 被选中的第一个字符的地位索引, 从 0 开始。如果这个值比元素的 value 长度还大,则会被看作 value 最初一个地位的索引。selectionEnd: 被选中的最初一个字符的下一个地位索引。如果这个值比元素的 value 长度还大,则会被看作 value 最初一个地位的索引。selectionDirection:抉择方向。forward/backward/none如果 selectionStart 与 selectionEnd 雷同,不选中任何,光标汇集在 selectionStart/selectionEnd。 ...

January 4, 2023 · 2 min · jiezi

关于javascript:这样回答前端面试题才能拿到offer

什么是文档的预解析?Webkit 和 Firefox 都做了这个优化,当执行 JavaScript 脚本时,另一个线程解析剩下的文档,并加载前面须要通过网络加载的资源。这种形式能够使资源并行加载从而使整体速度更快。须要留神的是,预解析并不扭转 DOM 树,它将这个工作留给主解析过程,本人只解析内部资源的援用,比方内部脚本、样式表及图片。 代码输入后果async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') resolve('promise1 resolve') }).then(res => console.log(res)) console.log('async1 success'); return 'async1 end'}console.log('srcipt start')async1().then(res => console.log(res))console.log('srcipt end')这里是对下面一题进行了革新,加上了resolve。 输入后果如下: script startasync1 startpromise1script endpromise1 resolveasync1 successasync1 end常见浏览器所用内核(1) IE 浏览器内核:Trident 内核,也是俗称的 IE 内核; (2) Chrome 浏览器内核:统称为 Chromium 内核或 Chrome 内核,以前是 Webkit 内核,当初是 Blink内核; (3) Firefox 浏览器内核:Gecko 内核,俗称 Firefox 内核; (4) Safari 浏览器内核:Webkit 内核; (5) Opera 浏览器内核:最后是本人的 Presto 内核,起初退出谷歌大军,从 Webkit 又到了 Blink 内核; ...

January 4, 2023 · 11 min · jiezi

关于javascript:前端面试前端性能优化篇

不论是什么样的前端面试,总会问到的一个问题:前端性能优化。 置信如果这个问题没有答好,在面试中会很被动。 于是,趁着这个天天宅的期间,好好的整顿了一番。 Start~ 一、HTML优化渲染程序1、CSS样式表置于头部,CSS会一边加载一边渲染2、JS脚本置于尾部,JS在未加载实现之前,会阻塞渲染3、应用内部的样式表和脚本,优先加载出HTML构造4、要害JS、CSS代码能够内嵌在HTML中,比方:rem动静等5、防止应用iFrame6、应用骨架屏二、CSS优化加载优化1、防止应用css的@import2、防止应用通配符3、防止应用!impotant4、优化css reset,我的项目中不会用到这么多reset5、防止应用css表达式动画优化1、能够应用transform开启图形减速2、用translate取代left,能够防止页面重排选择器优化1、选择器嵌套尽量不要超过三层2、id选择器尽量不要嵌套3、应用继承体积优化1、提取公共CSS三、JS优化运行速度1、如果没有兼容问题,尽量应用原生办法2、依据兼容浏览器的最低版本,思考是否应用polyfill3、switch语句绝对if,能够较快通过将case语句依照最可能到最不可能的程序进行组织4、位运算较快。当进行数字运算时,位运算操作要比任何布尔运算或者算数运算快5、巧用||和&&布尔运算符,能够缩小执行代码语句6、应用加号拼接是最快的,其次是String()、.toString()、new String()7、须要应用定时器时,用setTimeout取代setInterval,setInterval会始终占用内存8、制作JS动画时,应用requestAnimationFrame取代setTimeout和setInterval变量优化1、防止全局查找,能够将须要拜访的属性用变量保留2、应用变量比应用对象属性和数组元素要快3、对于蕴含大量数据而不须要操作的对象,能够应用Object.freeze解冻对象,放慢运行速度缩小无用操作1、应用节流、防抖2、应用事件委托取代大量事件的绑定3、若须要对DOM进行大量操作,能够应用Fragment缩小操作次数缩小未应用代码1、进行tree-shaking,删减未应用的代码算法优化1、增加key值,最大效益的应用虚构DOM,缩小Diff工夫2、应用benchmark测试不同算法的性能,择优四、网络优化申请数量下限:1、每个网站最多容许同时6个申请,能够思考将资源分类部署申请速度优化:1、应用CDN,能够减速资源的申请速度加载工夫调配:1、外围资源预加载2、大体积资源按需加载(Webpack拆包)缩小加载体积1、压缩图片2、压缩HTML、CSS、JS代码3、开启网络压缩,如:GZIP参考 前端进阶面试题具体解答 缩小加载次数1、制作精灵图2、将小图片转换为base64字符串3、应用浏览器缓存4、应用前端缓存,如: LocalStorage、Cookie、SessionStorage等5、缩小重定向申请,比方:nginx反向代理的重定向6、防止应用服务端字体五、React性能优化1、优化react事件,防止应用闭包函数 2、应用继续化数据结构Immutable对redux进行治理 3、优化shuoldComponentUpdate生命周期定义根底组件BaseComponent取代React.Component 4、应用纯组件PureComponent 5、增加Key值 注:以上总结的可能不残缺,能够在评论区补充,我后续补充上,谢谢~

January 4, 2023 · 1 min · jiezi

关于javascript:大厂前端面试考什么

nextTicknextTick 能够让咱们在下次 DOM 更新循环完结之后执行提早回调,用于取得更新后的 DOMnextTick次要应用了宏工作和微工作。依据执行环境别离尝试采纳 PromiseMutationObserversetImmediate如果以上都不行则采纳setTimeout定义了一个异步办法,屡次调用nextTick会将办法存入队列中,通过这个异步办法清空以后队列Promise.allSettled形容:等到所有promise都返回后果,就返回一个promise实例。 实现: Promise.allSettled = function(promises) { return new Promise((resolve, reject) => { if(Array.isArray(promises)) { if(promises.length === 0) return resolve(promises); let result = []; let count = 0; promises.forEach((item, index) => { Promise.resolve(item).then( value => { count++; result[index] = { status: 'fulfilled', value: value }; if(count === promises.length) resolve(result); }, reason => { count++; result[index] = { status: 'rejected'. reason: reason }; if(count === promises.length) resolve(result); } ); }); } else return reject(new TypeError("Argument is not iterable")); });}实现 JSONP 跨域JSONP 外围原理:script 标签不受同源策略束缚,所以能够用来进行跨域申请,长处是兼容性好,然而只能用于 GET 申请; ...

January 4, 2023 · 4 min · jiezi

关于javascript:前端面试指南之JS面试题总结

1. JS 有哪些数据类型?依据 JavaScript 中的变量类型传递形式,分为根本数据类型和援用数据类型两大类七种。 根本数据类型包含Undefined、Null、Boolean、Number、String、Symbol (ES6新增)六种。援用数据类型只有Object一种,次要包含对象、数组和函数。 判断数据类型采纳typeof操作符,有两种语法: typeof 123;//语法一const FG = 123;typeof FG;//语法二typeof(null) //返回 object;null == undefined //返回true,因为undefined派生自null;null === undefined //返回false。2. 根本数据类型和援用数据类型有什么区别?(1)两者作为函数的参数进行传递时: 根本数据类型**传入的是数据的正本**,原数据的更改不会影响传入后的数据。 援用数据类型**传入的是数据的援用地址**,原数据的更改会影响传入后的数据。 (2)两者在内存中的存储地位: 根本数据类型**存储在栈中**。 援用数据类型在**栈中存储了指针**,该指针指向的**数据实体存储在堆中**。 3. 判断数据类型的办法有哪些?(1)利用typeof能够判断数据的类型; (2)A instanceof B能够用来判断A是否为B的实例,但它不能检测 null 和 undefined; (3)B.constructor == A能够判断A是否为B的原型,但constructor检测 Object与instanceof不一样,还能够解决根本数据类型的检测。 不过函数的 constructor 是不稳固的,这个次要体现在把类的原型进行重写,在重写的过程中很有可能呈现把之前的constructor给笼罩了,这样检测进去的后果就是不精确的。(4)Object.prototype.toString.call() Object.prototype.toString.call() 是最精确最罕用的形式。4. 与深拷贝有何区别?如何实现?浅拷贝只复制指向某个对象的指针,而不复制对象自身。浅拷贝的实现形式有: (1)Object.assign():需注意的是指标对象只有一层的时候,是深拷贝; (2)扩大运算符; 深拷贝就是在拷贝数据的时候,将数据的所有援用构造都拷贝一份。深拷贝的实现形式有: (1)手写遍历递归赋值; (2)联合应用JSON.parse()和JSON.stringify()办法。 5. let、const的区别是什么?var、let、const都是用于申明变量或函数的关键字。其区别在于: varletconst作用域函数作用域块级作用域块级作用域作用域内申明晋升有无(暂时性死区)无是否可反复申明是否否是否可反复赋值是是否(常量)初始化时是否必须赋值否否是6. 什么是执行上下文和执行栈?变量或函数的执行上下文,决定了它们的行为以及能够拜访哪些数据。每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上(如DOM中全局上下文关联的便是window对象)。 每个函数调用都有本人的上下文。当代码执行流进入函数时,函数的上下文被推到一个执行栈中。在函数执行完之后,执行栈会弹出该函数上下文,在其上的所有变量和函数都会被销毁,并将控制权返还给之前的执行上下文。 JS的执行流就是通过这个执行栈进行管制的。 7. 什么是作用域和作用域链?作用域能够了解为一个独立的地盘,能够了解为标识符所能失效的范畴。作用域最大的用途就是隔离变量,不同作用域下同名变量不会有抵触。ES6中有全局作用域、函数作用域和块级作用域三层概念。 当一个变量在以后块级作用域中未被定义时,会向父级作用域(创立该函数的那个父级作用域)寻找。如果父级仍未找到,就会再一层一层向上寻找,直到找到全局作用域为止。这种一层一层的关系,就是作用域链 。 8. 作用域和执行上下文的区别是什么?(1)函数的执行上下文只在函数被调用时生成,而其作用域在创立时曾经生成; (2)函数的作用域会蕴含若干个执行上下文(有可能是零个,当函数未被调用时)。 9. this指向的各种状况都有什么?this的指向只有在调用时能力被确定,因为this是执行上下文的一部分。 (1)全局作用域中的函数:其外部this指向window: ...

January 4, 2023 · 3 min · jiezi

关于javascript:用TodoList实例告诉你怎么在项目中使用TypeScript

为什么用todolist古代的框架教程目前再也不是写个hello world那么简略了,而是须要有肯定根底能力可能做到数据绑定、遍历、条件判断等各种逻辑,而能实现这一系列内容的,todolist就是个很好的实现,比方react的教程、solijs教程都是以todolist为例 当然,你如果想看各种框架实现todolist的话,你能够拜访TodoMVC【https://todomvc.com/】,这外面展现了各种框架如何实现了todolist todolist的ts化然而对于ts教程来说,只有官网的一些实例,并没有一个很好的我的项目上的教程,也就是无关实战的局部,很多同学在学习了ts之后,只会一些根底的js类型的设置,放在我的项目中就不分明了,所以咱们就出了这个教程 当然在开始之前,咱们要理解这个教程不依赖任何的前端库,比方react,vue等,同时也为了节省时间,咱们仅仅是放出一些要害的ts代码,不须要将整个利用都展现进去,同样可能让你晓得ts的应用 数据到视图 一个tudolist对应的数据是怎么样的?就拿方才的视图来看的话,它应该是一个对象数组,数据应该是这样的 [ { id: 1, text: '待办事项1', done: false }, { id: 2, text: '待办事项2', done: false }, { id: 3, text: '待办事项3', done: false }]其中id是每一个代办事项的惟一标识,text是事项名称,done示意是否实现 当咱们点击实现的时候,实际上就是每一项的done产生了变动,数据发生变化之后驱动咱们的视图做出对应的扭转 实现handleTodoItem对应的上述的点击事件,咱们实现一下它的伪代码,当其点击的时候,须要解决对应的数据,先应用js实现 function handleTodoItem(todo){ // 点击的时候todo中的done的布尔值取反 return { ...todo, done: !todo.done }}而后咱们应用ts进行优化 type Todo = { id: number; text: string; done: boolean;}// 如果某个变量是todo类型,能够这样const todoItem: Todo = { id: 1, text: '待办事项1', done: false}这样ts类型就是失常的,如果相应的todoItem不匹配,则编译就会产生谬误,能够让谬误提前感知,并且如果我的项目中有配置的ts相干,vscode中就会给出对应的错误信息 ...

January 3, 2023 · 2 min · jiezi

关于javascript:商业智能BI工具评估指南

随着行业软件业务性能的不断完善,同行业软件日趋趋同,竞争更加白热化。同时,随着企业数字化转型的深刻,企业本身对数据的应用需要越来越强烈。在用户的业务处理过程中,在业务软件内间接给用户提供数据分析后果具备更高的及时性和理论价值,企业用户无需寻找业务零碎之外的第三方工具来满足业务数据分析的须要,从而晋升行业软件给用户的综合价值、用户黏性和产品竞争力,为软件供应商的业务倒退带来全新的增长点。 现在,简直所有的数据驱动型企业对BI软件的认知已达成共识,大大小小的公司都意识到了“数据就是力量”。而如果想借助这种“力量”,就必须应用适合的工具。 在不久的未来,BI或者会朝着这样的方向倒退:企业购买仪表板、报表类软件并不只是为了供其外部应用,同时也心愿可能将这种高级剖析性能和报表集成到他们本人的产品中,这就是所谓的嵌入式BI。 BI工具最有价值的方面之一是其功能丰富且经济高效的仪表板环境。并且在数据可视化应用程序中领有您可能须要的所有性能(以及一些您不晓得本人须要的性能),除此之外它也易于应用。市面上BI 工具令人目迷五色,到底如何抉择如何评估如何选型合乎本人我的项目需要的BI工具呢? 本文总结了7个性能点: 1.应用GUI轻松实现可视化 2.多种数据可视化类型 3.反对的各种数据源 4.具备可扩展性的内置安全性 5.挪动敌对且易于集成 6.实时数据反馈 7.数据分析和交互 应用GUI轻松实现可视化 应用商业智能工具尽可能的应用简略,操作易懂,只须要单击几下即可创立实时、可视化的仪表板和报告。要创立仪表板,首先将您的数据上传到BI 工具,而后开始将所需的数据可视化拖放到设计环境中。创立实时过滤数据的跳转至和切片器。这些可视化很容易调换,并在创立仪表板时提供灵活性和速度。 够丰盛的数据可视化类型 BI工具最重要最直观的能力就是数据可视化大屏,那么肯定要创立出酷炫科技的可视化大屏才可能让用户直观感触到产品能力,因而仪表板提供的相对灵活性。图表、表格、地图等30多种数据可视化,开箱即用,并且能够依据业务需要增加自定义可视化图表。上面列出了这些图表: 图表: ·        柱形图、范畴柱形图、沉积柱形图、百分比沉积柱形图 ·        条形图、范畴条形图、沉积条形图、百分比沉积条形图 ·        面积图、范畴面积图、沉积面积图、沉积面积百分比图 ·        折线图、饼图、圆环图、玫瑰图 ·        径向沉积条形图、夕阳形图、极坐标条形图、极坐标沉积条形图 ·        雷达图、填充雷达图、散点图、气泡图 ·        树形图、组合图、漏斗、仪表 ·        指标、KPI 图表、卡片图表 表: ·        数据透视表、数据表、KPI 矩阵 地图: ·        世界地图,平面图。GIS 地图,自定义地图,3D地图,物理场景地图 高阶图表: ·        计算图表、多源图表 动效:3D动效 足够多的数据源品种比方惯例业务数据库,反对一系列不同的数据源选项,例如: OracleSqlserver,mysql,Postgres,Snowflake达梦数据库阿里云ExceljsonCSVXMLMongoDBODBCODataIOT散失数据还有更多,每次次要补丁降级都会增加额定的潜在数据源。如果您的数据产生更改,您的仪表板会实时反映它。您将可能轻松连贯到您的零碎和数据库并展示对您或您的客户最有意义的刷新工夫,或者通过应用推送数据集或流数据集设置实时数据更新。这两种数据集类型都容许用户领有将数据发送到Wyn的外部设备或应用程序,这些数据能够间接流式传输到您的仪表板。次要区别在于 Push数据集将数据存储在服务器的缓存中,因而保留了历史数据。 Wyn的数据源管理器洁净且易于应用。 具备可扩展性的内置安全性 肯定要容许管理员在组织内创立用户,而后为用户调配角色、用户上下文,如果Wyn提供的属性不够,管理员能够调配自定义属性。用户上下文用于治理申明名称和用户属性名称之间的映射,容许定义、管制和增加自定义申明。这意味着用户只会拜访他们被容许查看的数据,并且读写权限基于管理员授予的权限。无关这些设置的更多信息,请在此处拜访咱们的帐户治理文档,并通过单击此处理解无关如何应用Wyn设置多租户医疗保健应用程序的更多信息: ...

January 3, 2023 · 1 min · jiezi

关于javascript:巧用数据分析表达式让数据指标创建更简单

实现数据+业务一体化的指标剖析 从批发零碎进化史get 数据统计的需要变更批发零碎须要的数据统计需要 V1.0只须要获取当日累计的销售额,于是店老板就用 Excel或者纸质的表格创立了一个表,表中蕴含销售的日期工夫,销售的产品,销售的数量,以及卖出的单价是多少。如此每天进行一个汇总,或者月底进行汇总就能够晓得当天或当月的销售额是什么状况了。 在 Wyn BI 数据可视化大屏设计工具(https://www.grapecity.com.cn/...),咱们能够间接将对应的销售数量拖拽到【数值】字段会主动进行共计,这就是批发零碎须要的V1版本需要,实现非常简单 批发零碎须要的数据统计需要 V2.0随着商店销售业绩额的增长,销售品类的增多,无奈用繁多的表格进行统计和记录,因而老板须要新增数据表,如产品表,销售表,来剖析每个产品的库存量,销量,以及哪个工夫比拟销量比拟好,因而能够动静减少库存来保障货源的短缺,须要更进一步的数据分析。 如果让程序员来搞定这个需要,他们会通过编写 SQL 代码来实现: select产品名称, sum(销售小计) as 销售总计from(select \*,销售数量\*售价as 销售小计from 销售表left join 产品表on ... )tmpgroup by 产品名称 然而应用 Wyn BI数据可视化大屏设计器中提供的数据模型,能够减少计算字段,该需要在 Wyn BI 数据可视化大屏设计器中,通过新增计算字段造成销售额这样的指标,Wyn BI工具中所提供的计算表达式,即可实现常见的数学解决,如加减乘除,字符串加工解决,如截取某一部分字符内容,批改日期格局等。 数据模型,将销售表和产品表应用产品ID关联起来,即可省去编写SQL语句: 批发零碎须要的数据统计需要 V3.0随着批发业务的倒退,老板须要的数据分析不再是为了短缺的货源保障大批量的销售,更心愿人货场三要素配比的协调,并依据每月的销售数据以及各人的销售业绩,经营老本等各因素可能放弃安稳的倒退,及时发现暗藏的危险,制订好适合的市场流动。因而须要多维度的数据分析: 在Wyn 商业智能BI 工具中,咱们能够通过提供的计算表达式,计算各产品销量,人员业绩排名,销售淡旺季等来辅助决策,到底是如何实现的?咱们须要引入 Wyn WAX计算表达式为数据可视化大屏设计提供指标运算。 那么如何应用 WAX计算表达式轻松实现不同维度的数据指标计算? 先来理解下 WAX计算表达式 是什么? WAX简介-WAX计算表达式在理论展现仪表板过程中,常常须要展现销售状况的数据,比方销售额,销售利润等。这些都是在数据集或数据模型中间接存在的数据字段,能够间接拖拽应用。 但当咱们心愿在仪表板中展现诸如总销售利润率时,就无奈间接拖拽应用了,因为这类字段是无奈间接通过拖拽主动聚合的业务逻辑,此时就须要一种更强的计算能力。 因而总有一些辣手的小需要,牵动着IT人员的心,比方依据地区,统计上一月的老本利润率,依据产品类别,计算环比增长率,那么“上一月”“环比”总是动静扭转的,即本月是8月份,那么上一月份就是7月份,随着时间推移,上一月可能会变成8月份。因而IT 人员总心愿可能一劳永逸,应用一个变量来始终获取以后月份的上月份,而不须要每个月都来批改。那么 Wyn 商业智能提供的 WAX剖析表达式即来解决这样的痛点: WAX剖析表达式Wyn Analytic Expression,Wyn 剖析表达式,是一种表达式语言。齐全独立于数据源类型,语法简略,编辑器智能,无需学习数据库语言,也无需学习编程语言,能够在智能编辑器和内置模板的根底上疾速上手,总共提供了18种罕用的运算符和9大类罕用函数。 在制作仪表板的过程中,用户能够依据剖析场景的须要灵便的编写和计算本人想要的更多指标,比方:销售完成率,销售完成率同比,客流量环比,排名等,让大屏的内容更具价值。 应用WAX 轻松编写,即可实现动静获取老本利润率和环比增长率在数据可视化大屏设计中: ...

January 3, 2023 · 1 min · jiezi

关于javascript:2023前端必会手写面试题整理

实现一个compose函数组合多个函数,从右到左,比方:compose(f, g, h) 最终失去这个后果 (...args) => f(g(h(...args))).题目形容:实现一个 compose 函数 // 用法如下:function fn1(x) { return x + 1;}function fn2(x) { return x + 2;}function fn3(x) { return x + 3;}function fn4(x) { return x + 4;}const a = compose(fn1, fn2, fn3, fn4);console.log(a(1)); // 1+4+3+2+1=11实现代码如下 function compose(...funcs) { if (!funcs.length) return (v) => v; if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => { return (...args) => a(b(...args))) }}compose创立了一个从右向左执行的数据流。如果要实现从左到右的数据流,能够间接更改compose的局部代码即可实现更换Api接口:把reduce改为reduceRight交互包裹地位:把a(b(...args))改为b(a(...args))实现迭代器生成函数咱们说迭代器对象全凭迭代器生成函数帮咱们生成。在ES6中,实现一个迭代器生成函数并不是什么难事儿,因为ES6早帮咱们思考好了全套的解决方案,内置了贴心的 生成器 (Generator)供咱们应用: ...

January 3, 2023 · 16 min · jiezi

关于javascript:自己手写一个redux

提起 Redux 咱们想到最多的应该就是 React-redux 这个库,可是实际上 Redux 和 React-redux 并不是同一个货色, Redux 是一种架构模式,源于 Flux。 React-redux 是 Redux 思维与 React 联合的一种具体实现。 在咱们应用 React 的时候,经常会遇到组件深层次嵌套且须要值传递的状况,如果应用 props 进行值的传递,显然是十分苦楚的。为了解决这个问题,React 为咱们提供了原生的 context API,但咱们用的最多的解决方案却是应用 React-redux 这个基于 context API 封装的库。 本文并不介绍 React-redux 的具体用法,而是通过一个小例子,来理解下什么是 redux。 好了,当初咱们言归正传,来实现咱们本人的 redux。 一、最后首先,咱们用 creat-react-app 来创立一个我的项目,删除 src 下冗余局部,只保留 index.js,并批改 index.html 的 DOM 构造: # index.html<div id="root"> <div id="head"></div> <div id="body"></div></div>咱们在 index.js 中创立一个对象,用它来贮存、治理咱们整个利用的数据状态,并用渲染函数把数据渲染在页面: const appState = { head: { text: '我是头部', color: 'red' }, body: { text: '我是body', color: 'green' }}function renderHead (state){ const head = document.getElementById('head') head.innerText = state.head.text; head.style.color = state.head.color;}function renderBody (state){ const body = document.getElementById('body') body.innerText = state.body.text; body.style.color = state.body.color;}function renderApp (state){ renderHead(state); renderBody(state);}renderApp(appState);此时运行代码,关上页面,咱们能够看到,在 head 中曾经呈现了红色字体的‘我是头部’,在 body 中呈现了绿色字体的‘我是body’。 ...

January 3, 2023 · 4 min · jiezi

关于javascript:字节前端高频手写面试题持续更新中

Promise// 模仿实现Promise// Promise利用三大伎俩解决回调天堂:// 1. 回调函数提早绑定// 2. 返回值穿透// 3. 谬误冒泡// 定义三种状态const PENDING = 'PENDING'; // 进行中const FULFILLED = 'FULFILLED'; // 已胜利const REJECTED = 'REJECTED'; // 已失败class Promise { constructor(exector) { // 初始化状态 this.status = PENDING; // 将胜利、失败后果放在this上,便于then、catch拜访 this.value = undefined; this.reason = undefined; // 胜利态回调函数队列 this.onFulfilledCallbacks = []; // 失败态回调函数队列 this.onRejectedCallbacks = []; const resolve = value => { // 只有进行中状态能力更改状态 if (this.status === PENDING) { this.status = FULFILLED; this.value = value; // 胜利态函数顺次执行 this.onFulfilledCallbacks.forEach(fn => fn(this.value)); } } const reject = reason => { // 只有进行中状态能力更改状态 if (this.status === PENDING) { this.status = REJECTED; this.reason = reason; // 失败态函数顺次执行 this.onRejectedCallbacks.forEach(fn => fn(this.reason)) } } try { // 立刻执行executor // 把外部的resolve和reject传入executor,用户可调用resolve和reject exector(resolve, reject); } catch(e) { // executor执行出错,将谬误内容reject抛出去 reject(e); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; onRejected = typeof onRejected === 'function'? onRejected : reason => { throw new Error(reason instanceof Error ? reason.message : reason) } // 保留this const self = this; return new Promise((resolve, reject) => { if (self.status === PENDING) { self.onFulfilledCallbacks.push(() => { // try捕捉谬误 try { // 模仿微工作 setTimeout(() => { const result = onFulfilled(self.value); // 分两种状况: // 1. 回调函数返回值是Promise,执行then操作 // 2. 如果不是Promise,调用新Promise的resolve函数 result instanceof Promise ? result.then(resolve, reject) : resolve(result); }) } catch(e) { reject(e); } }); self.onRejectedCallbacks.push(() => { // 以下同理 try { setTimeout(() => { const result = onRejected(self.reason); // 不同点:此时是reject result instanceof Promise ? result.then(resolve, reject) : resolve(result); }) } catch(e) { reject(e); } }) } else if (self.status === FULFILLED) { try { setTimeout(() => { const result = onFulfilled(self.value); result instanceof Promise ? result.then(resolve, reject) : resolve(result); }); } catch(e) { reject(e); } } else if (self.status === REJECTED) { try { setTimeout(() => { const result = onRejected(self.reason); result instanceof Promise ? result.then(resolve, reject) : resolve(result); }) } catch(e) { reject(e); } } }); } catch(onRejected) { return this.then(null, onRejected); } static resolve(value) { if (value instanceof Promise) { // 如果是Promise实例,间接返回 return value; } else { // 如果不是Promise实例,返回一个新的Promise对象,状态为FULFILLED return new Promise((resolve, reject) => resolve(value)); } } static reject(reason) { return new Promise((resolve, reject) => { reject(reason); }) } static all(promiseArr) { const len = promiseArr.length; const values = new Array(len); // 记录曾经胜利执行的promise个数 let count = 0; return new Promise((resolve, reject) => { for (let i = 0; i < len; i++) { // Promise.resolve()解决,确保每一个都是promise实例 Promise.resolve(promiseArr[i]).then( val => { values[i] = val; count++; // 如果全副执行完,返回promise的状态就能够扭转了 if (count === len) resolve(values); }, err => reject(err), ); } }) } static race(promiseArr) { return new Promise((resolve, reject) => { promiseArr.forEach(p => { Promise.resolve(p).then( val => resolve(val), err => reject(err), ) }) }) }}请实现一个 add 函数,满足以下性能add(1); // 1add(1)(2); // 3add(1)(2)(3);// 6add(1)(2, 3); // 6add(1, 2)(3); // 6add(1, 2, 3); // 6function add(...args) { // 在外部申明一个函数,利用闭包的个性保留并收集所有的参数值 let fn = function(...newArgs) { return add.apply(null, args.concat(newArgs)) } // 利用toString隐式转换的个性,当最初执行时隐式转换,并计算最终的值返回 fn.toString = function() { return args.reduce((total,curr)=> total + curr) } return fn}考点: ...

January 3, 2023 · 11 min · jiezi

关于javascript:面试官能用JavaScript手写一个bind函数吗

常常会看到网上各种手写bind的教程,上面是我在本人实现手写bind的过程中遇到的问题与思考。如果对于如何实现一个手写bind还有纳闷的话,那么能够先看看下面两篇文章。 手写bind vs 原生bind咱们先应用一个典型的手写bind的例子,代码如下: Function.prototype.bind2 = function (context) { if (typeof this !== "function") { throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); } var self = this; var args = Array.prototype.slice.call(arguments, 1); var fNOP = function () {}; var fBound = function () { var bindArgs = Array.prototype.slice.call(arguments); return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs)); } fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound;}咱们首先用原生bind运行一下代码 ...

January 3, 2023 · 1 min · jiezi

关于javascript:前端高频面试题集锦

你有没有在面试中遇到特地奇葩的js隐形转换的面试题,第一反馈是怎么会是这样呢?难以自信,js到底是怎么去计算失去后果,你是否有深刻去理解其原理呢?上面将深刻解说其实现原理。 其实这篇文章初稿三个月前就写好了,在我读一些源码库时,遇到了这些基础知识,想归档整顿下,就有了这篇文章。因为始终忙没工夫整顿,最近看到了这个比拟热的题,决定把这篇文章整顿下。 const a = { i: 1, toString: function () { return a.i++; }}if (a == 1 && a == 2 && a == 3) { console.log('hello world!');}网上给出了很多不错的解析过程,读了上面内容,你将更深刻的理解其执行过程。 1、js数据类型js中有7种数据类型,能够分为两类:原始类型、对象类型: 根底类型(原始值): Undefined、 Null、 String、 Number、 Boolean、 Symbol (es6新出的,本文不探讨这种类型)简单类型(对象值): object2、三种隐式转换类型js中一个难点就是js隐形转换,因为js在一些操作符下其类型会做一些变动,所以js灵便,同时造成易出错,并且难以了解。 波及隐式转换最多的两个运算符 + 和 ==。 +运算符即可数字相加,也能够字符串相加。所以转换时很麻烦。== 不同于===,故也存在隐式转换。- * / 这些运算符只会针对number类型,故转换的后果只能是转换成number类型。 既然要隐式转换,那到底怎么转换呢,应该有一套转换规则,能力追踪最终转换成什么了。 隐式转换中次要波及到三种转换: 1、将值转为原始值,ToPrimitive()。 2、将值转为数字,ToNumber()。 3、将值转为字符串,ToString()。 2.1、通过ToPrimitive将值转换为原始值js引擎外部的形象操作ToPrimitive有着这样的签名: ToPrimitive(input, PreferredType?) input是要转换的值,PreferredType是可选参数,能够是Number或String类型。他只是一个转换标记,转化后的后果并不一定是这个参数所值的类型,然而转换后果肯定是一个原始值(或者报错)。 2.1.1、如果PreferredType被标记为Number,则会进行上面的操作流程来转换输出的值。1、如果输出的值曾经是一个原始值,则间接返回它2、否则,如果输出的值是一个对象,则调用该对象的valueOf()办法, 如果valueOf()办法的返回值是一个原始值,则返回这个原始值。3、否则,调用这个对象的toString()办法,如果toString()办法返回的是一个原始值,则返回这个原始值。4、否则,抛出TypeError异样。2.1.2、如果PreferredType被标记为String,则会进行上面的操作流程来转换输出的值。1、如果输出的值曾经是一个原始值,则间接返回它2、否则,调用这个对象的toString()办法,如果toString()办法返回的是一个原始值,则返回这个原始值。3、否则,如果输出的值是一个对象,则调用该对象的valueOf()办法, 如果valueOf()办法的返回值是一个原始值,则返回这个原始值。4、否则,抛出TypeError异样。既然PreferredType是可选参数,那么如果没有这个参数时,怎么转换呢?PreferredType的值会依照这样的规定来主动设置: 1、该对象为Date类型,则PreferredType被设置为String2、否则,PreferredType被设置为Number2.1.3、valueOf办法和toString办法解析下面次要提及到了valueOf办法和toString办法,那这两个办法在对象里是否肯定存在呢?答案是必定的。在控制台输入Object.prototype,你会发现其中就有valueOf和toString办法,而Object.prototype是所有对象原型链顶层原型,所有对象都会继承该原型的办法,故任何对象都会有valueOf和toString办法。 先看看对象的valueOf函数,其转换后果是什么?对于js的常见内置对象:Date, Array, Math, Number, Boolean, String, Array, RegExp, Function。 ...

January 3, 2023 · 3 min · jiezi

关于javascript:令人头秃的js隐式转换面试题你能做对吗

你有没有在面试中遇到特地奇葩的js隐形转换的面试题,第一反馈是怎么会是这样呢?难以自信,js到底是怎么去计算失去后果,你是否有深刻去理解其原理呢?上面将深刻解说其实现原理。 其实这篇文章初稿三个月前就写好了,在我读一些源码库时,遇到了这些基础知识,想归档整顿下,就有了这篇文章。因为始终忙没工夫整顿,最近看到了这个比拟热的题,决定把这篇文章整顿下。 const a = { i: 1, toString: function () { return a.i++; }}if (a == 1 && a == 2 && a == 3) { console.log('hello world!');}网上给出了很多不错的解析过程,读了上面内容,你将更深刻的理解其执行过程。 1、js数据类型js中有7种数据类型,能够分为两类:原始类型、对象类型: 根底类型(原始值): Undefined、 Null、 String、 Number、 Boolean、 Symbol (es6新出的,本文不探讨这种类型)简单类型(对象值): object2、三种隐式转换类型js中一个难点就是js隐形转换,因为js在一些操作符下其类型会做一些变动,所以js灵便,同时造成易出错,并且难以了解。 波及隐式转换最多的两个运算符 + 和 ==。 +运算符即可数字相加,也能够字符串相加。所以转换时很麻烦。== 不同于===,故也存在隐式转换。- * / 这些运算符只会针对number类型,故转换的后果只能是转换成number类型。 既然要隐式转换,那到底怎么转换呢,应该有一套转换规则,能力追踪最终转换成什么了。 隐式转换中次要波及到三种转换: 1、将值转为原始值,ToPrimitive()。 2、将值转为数字,ToNumber()。 3、将值转为字符串,ToString()。 2.1、通过ToPrimitive将值转换为原始值js引擎外部的形象操作ToPrimitive有着这样的签名: ToPrimitive(input, PreferredType?) input是要转换的值,PreferredType是可选参数,能够是Number或String类型。他只是一个转换标记,转化后的后果并不一定是这个参数所值的类型,然而转换后果肯定是一个原始值(或者报错)。 2.1.1、如果PreferredType被标记为Number,则会进行上面的操作流程来转换输出的值。1、如果输出的值曾经是一个原始值,则间接返回它2、否则,如果输出的值是一个对象,则调用该对象的valueOf()办法, 如果valueOf()办法的返回值是一个原始值,则返回这个原始值。3、否则,调用这个对象的toString()办法,如果toString()办法返回的是一个原始值,则返回这个原始值。4、否则,抛出TypeError异样。2.1.2、如果PreferredType被标记为String,则会进行上面的操作流程来转换输出的值。1、如果输出的值曾经是一个原始值,则间接返回它2、否则,调用这个对象的toString()办法,如果toString()办法返回的是一个原始值,则返回这个原始值。3、否则,如果输出的值是一个对象,则调用该对象的valueOf()办法, 如果valueOf()办法的返回值是一个原始值,则返回这个原始值。4、否则,抛出TypeError异样。既然PreferredType是可选参数,那么如果没有这个参数时,怎么转换呢?PreferredType的值会依照这样的规定来主动设置: 1、该对象为Date类型,则PreferredType被设置为String2、否则,PreferredType被设置为Number2.1.3、valueOf办法和toString办法解析下面次要提及到了valueOf办法和toString办法,那这两个办法在对象里是否肯定存在呢?答案是必定的。在控制台输入Object.prototype,你会发现其中就有valueOf和toString办法,而Object.prototype是所有对象原型链顶层原型,所有对象都会继承该原型的办法,故任何对象都会有valueOf和toString办法。 先看看对象的valueOf函数,其转换后果是什么?对于js的常见内置对象:Date, Array, Math, Number, Boolean, String, Array, RegExp, Function。 ...

January 3, 2023 · 3 min · jiezi

关于javascript:那些高级前端是如何回答面试题的

TCP和UDP的区别 UDPTCP是否连贯无连贯面向连贯是否牢靠不牢靠传输,不应用流量管制和拥塞管制牢靠传输(数据程序和正确性),应用流量管制和拥塞管制连贯对象个数反对一对一,一对多,多对一和多对多交互通信只能是一对一通信传输方式面向报文面向字节流首部开销首部开销小,仅8字节首部最小20字节,最大60字节实用场景实用于实时利用,例如视频会议、直播实用于要求牢靠传输的利用,例如文件传输CSS中可继承与不可继承属性有哪些一、无继承性的属性 display:规定元素应该生成的框的类型文本属性:vertical-align:垂直文本对齐text-decoration:规定增加到文本的装璜text-shadow:文本暗影成果white-space:空白符的解决unicode-bidi:设置文本的方向盒子模型的属性:width、height、margin、border、padding背景属性:background、background-color、background-image、background-repeat、background-position、background-attachment定位属性:float、clear、position、top、right、bottom、left、min-width、min-height、max-width、max-height、overflow、clip、z-index生成内容属性:content、counter-reset、counter-increment轮廓款式属性:outline-style、outline-width、outline-color、outline页面款式属性:size、page-break-before、page-break-after声音款式属性:pause-before、pause-after、pause、cue-before、cue-after、cue、play-during二、有继承性的属性 字体系列属性font-family:字体系列font-weight:字体的粗细font-size:字体的大小font-style:字体的格调文本系列属性text-indent:文本缩进text-align:文本程度对齐line-height:行高word-spacing:单词之间的间距letter-spacing:中文或者字母之间的间距text-transform:管制文本大小写(就是uppercase、lowercase、capitalize这三个)color:文本色彩元素可见性visibility:管制元素显示暗藏列表布局属性list-style:列表格调,包含list-style-type、list-style-image等光标属性cursor:光标显示为何种状态单行、多行文本溢出暗藏单行文本溢出overflow: hidden; // 溢出暗藏text-overflow: ellipsis; // 溢出用省略号显示white-space: nowrap; // 规定段落中的文本不进行换行多行文本溢出overflow: hidden; // 溢出暗藏text-overflow: ellipsis; // 溢出用省略号显示display:-webkit-box; // 作为弹性伸缩盒子模型显示。-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列形式:从上到下垂直排列-webkit-line-clamp:3; // 显示的行数留神:因为下面的三个属性都是 CSS3 的属性,没有浏览器能够兼容,所以要在后面加一个-webkit- 来兼容一部分浏览器。 手写题:实现柯里化事后设置一些参数 柯里化是什么:是指这样一个函数,它接管函数 A,并且能返回一个新的函数,这个新的函数可能处理函数 A 的残余参数 function createCurry(func, args) { var argity = func.length; var args = args || []; return function () { var _args = [].slice.apply(arguments); args.push(..._args); if (args.length < argity) { return createCurry.call(this, func, args); } return func.apply(this, args); }}isNaN 和 Number.isNaN 函数的区别?函数 isNaN 接管参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因而非数字值传入也会返回 true ,会影响 NaN 的判断。函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再持续判断是否为 NaN ,不会进行数据类型的转换,这种办法对于 NaN 的判断更为精确。对浏览器的了解浏览器的次要性能是将用户抉择的 web 资源出现进去,它须要从服务器申请资源,并将其显示在浏览器窗口中,资源的格局通常是 HTML,也包含 PDF、image 及其他格局。用户用 URI(Uniform Resource Identifier 对立资源标识符)来指定所申请资源的地位。 ...

January 3, 2023 · 4 min · jiezi

关于javascript:假如面试官问你Babel的原理该怎么回答

1. 什么是 Babel简略地说,Babel 可能转译 ECMAScript 2015+ 的代码,使它在旧的浏览器或者环境中也可能运行。 // es2015 的 const 和 arrow functionconst add = (a, b) => a + b;// Babel 转译后var add = function add(a, b) { return a + b;};Babel 的性能很纯正。咱们传递一段源代码给 Babel,而后它返回一串新的代码给咱们。就是这么简略,它不会运行咱们的代码,也不会去打包咱们的代码。它只是一个编译器。 赫赫有名的 Taro 也是利用 Babel 将 React 语法转化成小程序模板。 2. Babel的包形成外围包 babel-core:babel转译器自身,提供了babel的转译API,如babel.transform等,用于对代码进行转译。像webpack的babel-loader就是调用这些API来实现转译过程的。babylon:js的词法解析器,AST生成babel-traverse:用于对AST(形象语法树,想理解的请自行查问编译原理)的遍历,次要给plugin用babel-generator:依据AST生成代码性能包 babel-types:用于测验、构建和扭转AST树的节点babel-template:辅助函数,用于从字符串模式的代码来构建AST树节点babel-helpers:一系列预制的babel-template函数,用于提供给一些plugins应用babel-code-frames:用于生成错误信息,打印出谬误点源代码帧以及指出出错地位babel-plugin-xxx:babel转译过程中应用到的插件,其中babel-plugin-transform-xxx是transform步骤应用的babel-preset-xxx:transform阶段应用到的一系列的plugin(官网写好的插件)babel-polyfill:JS规范新增的原生对象和API的shim,实现上仅仅是core-js和regenerator-runtime两个包的封装babel-runtime:性能相似babel-polyfill,个别用于library或plugin中,因为它不会净化全局作用域工具包 babel-cli:babel的命令行工具,通过命令行对js代码进行转译 babel-register:通过绑定node.js的require来主动转译require援用的js代码文件 babel8 将包名变为了@babel 3. 原理 Babel 转换 JS 代码能够分成以下三个大步骤: Parser(解析):此过程承受转换之前的源码,输入 AST(形象语法树)。在 Babel 中负责此过程的包为 babel/parser;Transform(转换):此过程承受 Parser 输入的 AST(形象语法树),输入转换后的 AST(形象语法树)。在 Babel 中负责此过程的包为 @babel/traverse;Generator(生成):此过程承受 Transform 输入的新 AST,输入转换后的源码。在 Babel 中负责此过程的包为 @babel/generator。所以AST相干常识,你应该事后就理解了 ...

January 3, 2023 · 7 min · jiezi

关于javascript:Mand-Mobile-滴滴出品的适用于金融项目的-Vue-移动端-UI-组件库免费开源灵活快速丰富实用

举荐一款可用性很强的挪动 UI 组件库,交互粗疏,有不少间接就能够用的金融行业的组件。 对于 Mand MobileMand Mobile 是一款由滴滴前端团队出品、专为金融场景设计的挪动端 Vue 2 组件库,能够帮忙前端开发者疾速构建我的项目,UI 格调也很业余谨严。目前已理论利用于滴滴四大金融业务板块的10余款产品中。 Mand Mobile 组件库个性超过40个的实用组件,可能满足惯例的挪动端开发的根本需要,尤其是对金融场景的需要进行了特地反对UI 视觉标准对立。由滴滴金融设计师设计并保护,保障了高度的视觉一致性反对按需加载,应用灵便,防止引入无用代码,导出es,umd两种格局以及px, vh/vw两种款式单位反对款式主题配置,拓展灵便,轻松适应不同的设计格调反对 TypeScript反对服务端渲染开发上手体验Mand Mobile 是一款基于 Vue 2 开发的挪动端 UI 组件库,UI 的设计格调是谨严的中性风,有很多轻微的交互细节,体验晦涩难受,用在惯例的挪动端我的项目齐全没问题,尤其是针对金融行业做了优化,我第一次看到这个 UI 组件库,就感觉十分难看,毕竟当初很多组件库的代码实现大同小异,很多时候抉择一款组件库,是冲着颜值去的。 反对 npm 或 yarn : 引入组件库: 当然也能够借助 babel-plugin-import 或 ts-import-plugin 来按需引入。官网的开发文档很具体,应用也很简略。 值得关注的是,有一些专为金融行业而设计的组件十分实用,比方金融数字、收银台、数字键盘等,这些组件体验优良,拿来就用,能节俭大量的开发工夫。 和很多大厂出品的组件库一样,Mand Mobile 除了提供组件库供开发者应用,也蕴含了设计规范、Sketch 设计源文件供设计师应用,甚至是代码编写标准、代码提交标准,都是对提高效率非常有用的材料。 收费开源阐明Mand Mobile 是由滴滴出品的基于 Vue 2 开发的前端 UI 组件库,我的项目源码基于 Apache 2.0 开源协定托管在 Github 上,任何集体和公司都能够收费下载应用,也能够用在商业我的项目上。 相干网址:https://www.thosefree.com/man...

January 2, 2023 · 1 min · jiezi

关于javascript:基础篇-变量-varletconst

在 ES6 呈现之前,js 定义变量的关键字只有 var。 在 ES6 之后才新增了 let 和 const。新的变量申明关键字呈现,也带来了一些新的变动。Enjoy it :) var在 ES6 呈现以前, JavaScript 定义变量的关键字只有 var 申明作用域应用 var 操作符定义的变量,会成为蕴含它的函数的局部变量,这意味着该变量会在函数退出的时候被销毁。 function foo() { var name = 'foo'; console.log(name); // foo}foo();console.log(name); // Error全局变量如果在定义变量时,没有应用 var 关键字,这时候,所申明的变量将会变成全局变量。 function foo() { // without keyword 'var' name = 'foo'; console.log(name); // foo}foo();console.log(name); // foo上述代码将会变成下述代码,变量 name 的申明被提到了全局顶部。尽管能够通过这种形式来申明一个全局变量,这种形式强烈不举荐,这会使得全局变量被净化,也会使得代码变得难以保护。 var name; function foo() { name = 'foo';}在严格模式下,如果未声明间接进行赋值操作,会间接抛出 ReferenceError 异样。晋升 Hoisting在开始这大节之前,先思考一下下述代码会打印什么内容呢? 会间接报错抛出 Error 么? 还是失常打印出一个 foo? 或者是 undefined? ...

January 2, 2023 · 3 min · jiezi

关于javascript:高级前端二面手写面试题边面边更

解析 URL Params 为对象let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';parseParam(url)/* 后果{ user: 'anonymous', id: [ 123, 456 ], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型 city: '北京', // 中文需解码 enabled: true, // 未指定值得 key 约定为 true}*/function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来 const paramsArr = paramsStr.split('&'); // 将字符串以 & 宰割后存到数组中 let paramsObj = {}; // 将 params 存到对象中 paramsArr.forEach(param => { if (/=/.test(param)) { // 解决有 value 的参数 let [key, val] = param.split('='); // 宰割 key 和 value val = decodeURIComponent(val); // 解码 val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字 if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则增加一个值 paramsObj[key] = [].concat(paramsObj[key], val); } else { // 如果对象没有这个 key,创立 key 并设置值 paramsObj[key] = val; } } else { // 解决没有 value 的参数 paramsObj[param] = true; } }) return paramsObj;}异步并发数限度/** * 关键点 * 1. new promise 一经创立,立刻执行 * 2. 应用 Promise.resolve().then 能够把工作加到微工作队列,避免立刻执行迭代办法 * 3. 微工作处理过程中,产生的新的微工作,会在同一事件循环内,追加到微工作队列里 * 4. 应用 race 在某个工作实现时,持续增加工作,放弃工作依照最大并发数进行执行 * 5. 工作实现后,须要从 doingTasks 中移出 */function limit(count, array, iterateFunc) { const tasks = [] const doingTasks = [] let i = 0 const enqueue = () => { if (i === array.length) { return Promise.resolve() } const task = Promise.resolve().then(() => iterateFunc(array[i++])) tasks.push(task) const doing = task.then(() => doingTasks.splice(doingTasks.indexOf(doing), 1)) doingTasks.push(doing) const res = doingTasks.length >= count ? Promise.race(doingTasks) : Promise.resolve() return res.then(enqueue) }; return enqueue().then(() => Promise.all(tasks))}// testconst timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i))limit(2, [1000, 1000, 1000, 1000], timeout).then((res) => { console.log(res)})解析 URL Params 为对象let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';parseParam(url)/* 后果{ user: 'anonymous', id: [ 123, 456 ], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型 city: '北京', // 中文需解码 enabled: true, // 未指定值得 key 约定为 true}*/function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来 const paramsArr = paramsStr.split('&'); // 将字符串以 & 宰割后存到数组中 let paramsObj = {}; // 将 params 存到对象中 paramsArr.forEach(param => { if (/=/.test(param)) { // 解决有 value 的参数 let [key, val] = param.split('='); // 宰割 key 和 value val = decodeURIComponent(val); // 解码 val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字 if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则增加一个值 paramsObj[key] = [].concat(paramsObj[key], val); } else { // 如果对象没有这个 key,创立 key 并设置值 paramsObj[key] = val; } } else { // 解决没有 value 的参数 paramsObj[param] = true; } }) return paramsObj;}Array.prototype.filter()Array.prototype.filter = function(callback, thisArg) { if (this == undefined) { throw new TypeError('this is null or not undefined'); } if (typeof callback !== 'function') { throw new TypeError(callback + 'is not a function'); } const res = []; // 让O成为回调函数的对象传递(强制转换对象) const O = Object(this); // >>>0 保障len为number,且为正整数 const len = O.length >>> 0; for (let i = 0; i < len; i++) { // 查看i是否在O的属性(会查看原型链) if (i in O) { // 回调函数调用传参 if (callback.call(thisArg, O[i], i, O)) { res.push(O[i]); } } } return res;}手写 new 操作符在调用 new 的过程中会产生以上四件事件: ...

January 2, 2023 · 9 min · jiezi

关于javascript:手撕常见JS面试题

高阶函数实现AOP(面向切面编程) Function.prototype.before = function (beforefn) { let _self = this; // 缓存原函数的援用 returnfunction () { // 代理函数 beforefn.apply(this, arguments); // 执行前置函数 return _self.apply(this, arguments); // 执行原函数 } } Function.prototype.after = function (afterfn) { let _self = this; returnfunction () { letset = _self.apply(this, arguments); afterfn.apply(this, arguments); returnset; } } let func = () => console.log('func'); func = func.before(() => { console.log('===before==='); }).after(() => { console.log('===after==='); }); func();输入后果: ===before===func===after=== 当咱们 new 一个类的时候 都产生了什么/** * new2 new关键字的代码实现演示 * @param {function} func 被new的类 (构造函数) */function new2(func) { // 创立了一个实例对象 o,并且这个对象__proto__指向func这个类的原型对象 let o = Object.create(func.prototype); // (在构造函数中this指向以后实例)让这个类作为一般函数值行 并且外面this为实例对象 let k = func.call(o); // 最初再将实例对象返回 如果你在类中显示指定返回值k, // 留神如果返回的是援用类型则将默认返回的实例对象o代替掉 return typeof k === 'object' ? k : o;}// 试验functionM() { // 行将被new的类 this.name = 'liwenli';}let m = new2(M); // 等价于 new M 这里只是模仿console.log(m instanceof M); // instanceof 检测实例console.log(m instanceof Object);console.log(m.__proto__.constructor === M);Object.create 兼容实现let obj1 = {id: 1}; Object._create = (o) => { let Fn = function() {}; // 长期的构造函数 Fn.prototype = o; return new Fn; } let obj2 = Object._create(obj1); console.log(obj2.__proto__ === obj1); // true console.log(obj2.id); // 1 // 原生的Object.create let obj3 = Object.create(obj1); console.log(obj3.__proto__ === obj1); // true console.log(obj3.id); // 1currying 函数柯理化curry 柯理化的实现(递归调用 + valueOf)知识点:valueOf 浏览器环境下 当咱们以log(fn)这种模式取值时,会隐式调用fn本身的valueOf 所以失去的是valueOf的返回值functionfn() {};fn.valueOf = () => console.log('valueof');console.log(fn); // valueofconst mul = x => { const result = y => mul(x * y); // 递归调用mul result.valueOf = () => x; return result;}console.log(mul(2)(3)); // 6// 在下面mul每执行一次,就会返回一个valueOf被改写后的新函数result 并且result执行会在外面调用mul(x * y)// 在result函数的valueOf里保留着 由上一次x * y 传进来的后果x, 也就是上一次x*y 会作为这一次的输入 仍然叫x// 第一次mul(2) 此时 x为2 return resultresult 为 result = y => mul(2 * y); // 第二次 mul(2)(3) 等价于 第一个mul返回的result(3), result执行 => mul(2 * 3) 再次调用mul 将2*3 = 6 的后果作为mul参数// 最初mul(6) x = 6 在返回一个新函数result 此时result的valueOf = () => 6// log(mul(2)(3)) 相当于log的最初返回的result 隐式调用valueOf 返回 6curry 将多参数函数转换为接管繁多参数的函数function fe(a, b, c) { return a + b + c;}function curry(fe) { let args = []; // 参数汇合 let len = args.length; returnfunctionbar() { args = [...args, ...arguments]; // 收集参数 if (args.length >= fe.length) { return fe.apply(this, args); } return bar; }}console.log(curry(fe)(1)(2)(3)); // 6currying 局部求值 // currying 函数柯理化 let currying = function(fn) { let args = []; returnfunctionfe() { if (arguments.length === 0) { return fn.apply(this, args); } [].push.apply(args, arguments); return fe; } } let count = currying(function (...rest) { return rest.reduce((prev, cur) => prev + cur, 0); }); console.log(count(100)(200)(10)()); // 310收集参数 提早执行 达到指定次数才执行 // 参数收集 指定次数后执行 function fn(...rest) {console.log(rest);}; function after(fn, time = 1) { let params = []; returnfunction(...rest) { params = [...params, ...rest]; if (--time === 0) { fn.apply(this, params); } } } let newFn = after(fn, 3); // 执行3次 外部fn才会执行 newFn(2); newFn(3); newFn(4);参考 前端进阶面试题具体解答 ...

January 2, 2023 · 12 min · jiezi

关于javascript:高级前端必会手写面试题及答案

循环打印红黄绿上面来看一道比拟典型的问题,通过这个问题来比照几种异步编程办法:红灯 3s 亮一次,绿灯 1s 亮一次,黄灯 2s 亮一次;如何让三个灯一直交替反复亮灯? 三个亮灯函数: function red() { console.log('red');}function green() { console.log('green');}function yellow() { console.log('yellow');}这道题简单的中央在于须要“交替反复”亮灯,而不是“亮完一次”就完结了。 (1)用 callback 实现const task = (timer, light, callback) => { setTimeout(() => { if (light === 'red') { red() } else if (light === 'green') { green() } else if (light === 'yellow') { yellow() } callback() }, timer)}task(3000, 'red', () => { task(2000, 'green', () => { task(1000, 'yellow', Function.prototype) })})这里存在一个 bug:代码只是实现了一次流程,执行后红黄绿灯别离只亮一次。该如何让它交替反复进行呢? ...

January 2, 2023 · 10 min · jiezi

关于javascript:能否手写vue3响应式原理面试进阶

(二)响应式原理利用ES6中Proxy作为拦截器,在get时收集依赖,在set时触发依赖,来实现响应式。 (三)手写实现1、实现Reactive基于原理,咱们能够先写一下测试用例 //reactive.spec.ts describe("effect", () => { it("happy path", () => { const original = { foo: 1 }; //原始数据 const observed = reactive(original); //响应式数据 expect(observed).not.toBe(original); expect(observed.foo).toBe(1); //失常获取数据 expect(isReactive(observed)).toBe(true); expect(isReactive(original)).toBe(false); expect(isProxy(observed)).toBe(true); }); }); 首先实现数据的拦挡解决,通过ES6的Proxy,实现获取和赋值操作。 //reactive.ts //对new Proxy()进行包装 export function reactive(raw) { return createActiveObject(raw, mutableHandlers); } function createActiveObject(raw: any, baseHandlers) { //间接返回一个Proxy对象,实现响应式 return new Proxy(raw, baseHandlers); } //baseHandler.ts //抽离出一个handler对象 export const mutableHandlers = { get:createGetter(), set:createSetter(), }; function createGetter(isReadOnly: Boolean = false, shallow: Boolean = false) { return function get(target, key) { const res = Reflect.get(target, key); // 看看res是否是一个object if (isObject(res)) { //如果是,则进行嵌套解决,使得返回的对象中的 对象 也具备响应式 return isReadOnly ? readonly(res) : reactive(res); } if (!isReadOnly) { //如果不是readonly类型,则收集依赖 track(target, key); } return res; }; } function createSetter() { return function set(target, key, value) { const res = Reflect.set(target, key, value); //触发依赖 trigger(target, key); return res; }; }从上述代码中,咱们能够⚠️留神到track(target, key) 和trigger(target, key) 这两个函数,别离是对依赖的收集和触发。 ...

January 2, 2023 · 5 min · jiezi

关于javascript:滴滴前端常见面试题

浏览器是如何对 HTML5 的离线贮存资源进行治理和加载?在线的状况下,浏览器发现 html 头部有 manifest 属性,它会申请 manifest 文件,如果是第一次拜访页面 ,那么浏览器就会依据 manifest 文件的内容下载相应的资源并且进行离线存储。如果曾经拜访过页面并且资源曾经进行离线存储了,那么浏览器就会应用离线的资源加载页面,而后浏览器会比照新的 manifest 文件与旧的 manifest 文件,如果文件没有产生扭转,就不做任何操作,如果文件扭转了,就会从新下载文件中的资源并进行离线存储。离线的状况下,浏览器会间接应用离线存储的资源。label 的作用是什么?如何应用?label标签来定义表单控件的关系:当用户抉择label标签时,浏览器会主动将焦点转到和label标签相干的表单控件上。 应用办法1:<label for="mobile">Number:</label><input type="text" id="mobile"/>应用办法2:<label>Date:<input type="text"/></label>CSS3的新个性transition:过渡transform: 旋转、缩放、挪动或歪斜animation: 动画gradient: 突变box-shadow: 暗影border-radius: 圆角word-break: normal|break-all|keep-all; 文字换行(默认规定|单词也能够换行|只在半角空格或连字符换行)text-overflow: 文字超出局部解决text-shadow: 程度暗影,垂直暗影,含糊的间隔,以及暗影的色彩。box-sizing: content-box|border-box 盒模型媒体查问 @media screen and (max-width: 960px) {}还有打印printCSS中可继承与不可继承属性有哪些一、无继承性的属性 display:规定元素应该生成的框的类型文本属性:vertical-align:垂直文本对齐text-decoration:规定增加到文本的装璜text-shadow:文本暗影成果white-space:空白符的解决unicode-bidi:设置文本的方向盒子模型的属性:width、height、margin、border、padding背景属性:background、background-color、background-image、background-repeat、background-position、background-attachment定位属性:float、clear、position、top、right、bottom、left、min-width、min-height、max-width、max-height、overflow、clip、z-index生成内容属性:content、counter-reset、counter-increment轮廓款式属性:outline-style、outline-width、outline-color、outline页面款式属性:size、page-break-before、page-break-after声音款式属性:pause-before、pause-after、pause、cue-before、cue-after、cue、play-during二、有继承性的属性 字体系列属性font-family:字体系列font-weight:字体的粗细font-size:字体的大小font-style:字体的格调文本系列属性text-indent:文本缩进text-align:文本程度对齐line-height:行高word-spacing:单词之间的间距letter-spacing:中文或者字母之间的间距text-transform:管制文本大小写(就是uppercase、lowercase、capitalize这三个)color:文本色彩元素可见性visibility:管制元素显示暗藏列表布局属性list-style:列表格调,包含list-style-type、list-style-image等光标属性cursor:光标显示为何种状态单行、多行文本溢出暗藏单行文本溢出overflow: hidden; // 溢出暗藏text-overflow: ellipsis; // 溢出用省略号显示white-space: nowrap; // 规定段落中的文本不进行换行多行文本溢出overflow: hidden; // 溢出暗藏text-overflow: ellipsis; // 溢出用省略号显示display:-webkit-box; // 作为弹性伸缩盒子模型显示。-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列形式:从上到下垂直排列-webkit-line-clamp:3; // 显示的行数留神:因为下面的三个属性都是 CSS3 的属性,没有浏览器能够兼容,所以要在后面加一个-webkit- 来兼容一部分浏览器。 transition和animation的区别transition是适度属性,强调适度,它的实现须要触发一个事件(比方鼠标挪动下来,焦点,点击等)才执行动画。它相似于flash的补间动画,设置一个开始关键帧,一个完结关键帧。animation是动画属性,它的实现不须要触发事件,设定好工夫之后能够本人执行,且能够循环一个动画。它也相似于flash的补间动画,然而它能够设置多个关键帧(用@keyframe定义)实现动画。参考 前端进阶面试题具体解答 head 标签有什么作用,其中什么标签必不可少?标签用于定义文档的头部,它是所有头部元素的容器。 中的元素能够援用脚本、批示浏览器在哪里找到样式表、提供元信息等。 文档的头部形容了文档的各种属性和信息,包含文档的题目、在 Web 中的地位以及和其余文档的关系等。绝大多数文档头部蕴含的数据都不会真正作为内容显示给读者。 ...

January 2, 2023 · 3 min · jiezi

关于javascript:从输入URL到渲染的过程中到底发生了什么

CDN缓存DNSTCP三次握手、四次挥手浏览器渲染过程输出URL到页面渲染过程的一些优化上面我将“从输出URL到渲染的全过程”大略的形容进去,再对其过程加以解释,理解过程中能够做哪些优化。文章内容有点长,须要有足够的急躁看完哟!!上面我要开始啦! 1、URL解析 2、DNS解析 3、建设TCP链接 4、客户端发送申请 5、服务器解决和响应申请 6、浏览器解析并渲染响应内容 7、TCP四次挥手断开连接 一、URL解析地址解析和编码咱们输出URL后,浏览器会解析输出的字符串,判断是URL还是搜寻关键字,如果是URL就开始编码。 一般来说URL只能应用英文字母、阿拉伯数字和某些标点符号,不能应用其余文字和符号,所以,如果URL中有文字就必须编码后应用。然而URL编码很凌乱,不同的操作系统、浏览器、网页字符集,会导致不同的编码后果。所以咱们须要应用JavaScript先对URL编码,而后提交给服务器,不给浏览器插手的机会。咱们通常会应用encodeURI()函数或者encodeURIComponent()函数来编码URL HSTSHSTS(HTTP Strict TransportSecurity)是一种新的Web平安协定,HSTS的作用是强制客户端应用HTTPS与服务器创立连贯。比方你在地址栏输出http://xxx/,浏览器会主动将http转写成https,而后间接向 https://xxx/ 发送申请。 缓存查看浏览器在发送申请之前先查看有没有缓存,过程如下: 浏览器会先去查看强缓存(Expires和cache-control)判断是否过期,如果强缓存失效,间接从缓存中读取资源;若不失效则进行协商缓存(Last-Modified / If-Modified-Since和Etag/If-None-Match),协商缓存由服务器决定是否应用缓存,若协商缓存生效,那么代表该申请的缓存生效,返回200,并从新返回资源和缓存标识,再次存入浏览器缓存中;失效则返回304,并从缓存中读取资源。(协商缓存之前要通过DNS域名解析,之后建设TCP链接) 那么浏览器缓存的地位在哪呢? Service Worker:浏览器独立线程进行缓存Memory Cache:内存缓存Disk Cache:硬盘缓存Push Cache:推送缓存(HTTP/2中的)留神:输出网址之后,会查找内存缓存,没有再找硬盘,都没有就产生网络申请。一般刷新(F5):因为TAB没有敞开,所以内存缓存可用,如果匹配上会被优先应用,其次是磁盘缓存强制刷新(Ctrl+F5):浏览器不应用缓存,因而发送的申请头均带有Cache-control:no-cache,服务器间接返回200和最新内容。 二、进行DNS解析DNS(1)、DNS:把域名和ip地址互相映射分布式数据库,让用户能更不便的拜访互联网,DNS协定运行在UDP协定之上 (2)、DNS解析:通过域名最终失去对应ip地址的过程。 (3)、DNS缓存:浏览器,操作系统,路由器,本地DNS,根域名服务器都会对DNS后果作出肯定的缓存 DNS解析过程(1)、首先搜寻浏览器本身的DNS缓存,有缓存间接返回; (2)、浏览器本身DNS不存在,浏览器就会调用一个相似gethostbyname的库函数,此函数会先去检测本地hosts文件,查看是否有对应ip。 (3)、如果本地hosts文件不存在映射关系,就会查问路由缓存,路由缓存不存在就去查找本地DNS服务器(个别TCP/IP参数里会设首选DNS服务器,通常是8.8.8.8)(客户端到本地DNS服务器是递归过程) (4)、如果本地DNS服务器还没找到就会向根服务器发出请求。(DNS服务器之间是迭代过程) 具体过程: 本地DNS服务器代咱们的浏览器发动迭代DNS解析申请,首先它会找根域的DNS的IP地址(寰球13台哟,惋惜中国没有!)。找到根域的DNS地址,就会向其发动申请(请问www.baidu.com这个域名的IP地址是多少呀?);根域发现这是一个顶级域com域的一个域名,于是通知本地DNS服务器我不晓得这个域名的IP地址,然而我晓得com域的IP地址,你去找它去吧;于是本地DNS服务器就失去了com域的IP地址,又向com域的IP地址发动了申请(请问www.baidu.com这个域名的IP地址是多少呀?),于是com域服务器通知本地DNS服务器我不晓得www.baidu.com这个域名的IP地址,然而我晓得baidu.com这个域的DNS地址,你去找它去;于是本地DNS服务器又向baidu.com这个域名的DNS地址(这个个别就是由域名注册商提供的,像万网,新网等)发动申请(请问www.baidu.com这个域名的IP地址是多少?),这个时候baidu.com域的DNS服务器一查,呀!果然在我这耶,于是就把找到的后果发送给本地DNS服务器;这个时候本地DNS服务器就拿到了www.baidu.com这个域名对应的IP地址。DNS优化DNS也是开销,通常浏览器查找一个给定域名的IP地址要花费20~120毫秒,在实现域名解析之前,浏览器不能从服务器加载到任何货色。那么如何缩小域名解析工夫,放慢页面加载速度呢? (1)、缩小DNS申请次数 (2)、DNS预获取,DOM还没开始,浏览器预解析地址,把解析好的地址放在本地缓存外面,DOM树生成完,要加载图片类的发现DNS曾经解析好了,再发送申请。<link rel='dns-prefetch'href='//dfns.tanx.com'> (次要对图片资源) (3)、DNS 查问的过程经验了很多的步骤,如果每次都如此,会消耗太多的工夫、资源。所以咱们应该尽早的返回实在的IP地址:(缩小查问过程,也就是DNS缓存。浏览器获取到IP地址后,个别都会缓存到浏览器的缓存中,本地的DNS缓存服务器,也能够去记录。另外,每天几亿网名的拜访需要,一秒钟几千万的申请域名服务器如何满足?就是DNS负载平衡。通常咱们的网站利用各种云服务,或者各种服务商提供相似的服务,由他们去帮咱们解决这些问题。 DNS零碎依据每台机器的负载量,地理位置的限度(长距离的传输效率)等等,去提供高效疾速的 DNS 解析服务。 (4)、当客户端DNS缓存(浏览器和操作系统)缓存为空时,DNS查找的数量与要加载的Web页面中惟一主机名的数量雷同,包含页面URL、脚本、样式表、图片、Flash对象等的主机名。缩小主机名的数量就能够缩小DNS查找的数量; (5)、缩小惟一主机名的数量会潜在缩小页面中并行下载的数量(HTTP1.1标准倡议从每个主机名并行下载两个组件,但实际上能够多个);然而缩小主机名和并行下载的计划会产生矛盾,须要大家本人衡量。倡议将组件放到至多两个但不多于4个主机名下,缩小DNS查找的同时也容许高度并行下载。DNS解析后会把域名的解析权交给cname()指向的内容散发(CDN)专用的DNS服务器。CDN专用的DNS服务器把CDN的全局负载平衡设施的ip地址返回给用户。 参考 前端进阶面试题具体解答 CDN举个例子:以前坐火车买票,都要到火车站买,所有人都去火车站买票,火车站售票厅的压力可想而知有多大。起初火车票代售点呈现了,散布在各个城市,城镇,咱们只须要去间隔咱们最近的火车票售卖点买票就能够了。卖火车票的代理售票点(缓存服务器),为买票者提供了不便,帮忙他们在最近的中央(最近的CDN节点),用最短的工夫(最短的申请工夫)买到票(拿到资源)。加重了售票大厅的压力(起到分流作用,加重服务器负载压力) CDN缓存:在浏览器本地缓存生效后,浏览器会像CDN边缘节点发动申请,相似浏览器缓存,CDN边缘节点也存在一套缓存机制, CDN边缘节点缓存策略因服务商不同而不同,通过http响应头中的cache-control:max-age字段设置CDN边缘节点数据缓存工夫。当浏览器向CDN节点申请数据时,CDN节点会判断缓存数据是否过期,若缓存数据过期,CDN会向服务器收回回源申请,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端,CDN服务商个别会提供基于文件后缀,目录多个维度来指定CDN缓存工夫,为用户提供更精细化的缓存治理。CDN工作形式:(1)、当你点击网站页面的url时,通过本DNS解析,DNS解析后会把域名的解析权交给cname()指向的内容散发专用的DNS服务器。内容散发专用的DNS服务器把内容散发的全局负载平衡(GSLB)设施的ip地址返回给用户。 (2)、当你向CDN的全局负载平衡设施的ip地址发动url拜访申请,CDN的全局负载平衡设施会为你抉择一台适合的缓存服务器提供服务。 抉择的根据:用户的ip地址,判断哪台服务器间隔用户最近,依据用户申请的url中携带的内容名称判断哪台服务器上有用户要的数据,查问各个服务器以后负载状况,判断哪台服务器有服务能力。调配:基于这些条件综合剖析后,区域负载平衡设施会向全局负载平衡设施申请返回一台缓存服务器的IP地址。全局负载平衡设施返回服务器IP地址,用户向缓存服务器发动申请,缓存服务器响应用户申请,将用户所需内容传送到用户终端,如果这台缓存服务器没有用户想要的内容,而区域平衡设施仍然将它调配给了用户,那么这台服务器就要向它的上一级缓存服务器申请内容,直至追溯到网站的源服务器将内容拉到本地。域名解析服务器依据用户ip地址,把域名解析成相应节点的缓存服务器ip地址,实现用户就近拜访,应用CDN服务的网站,只有将其域名解析权交给CDN的全局负载平衡设施,将须要散发的内容注入到CDN就能够实现内容减速了。CDN劣势:(1)、CDN节点解决了跨运营商和跨地区拜访的问题,拜访延时大大降低; (2)、大部分申请在CDN边缘节点实现,CDN起到分流作用,加重了源服务器的负载。CDN劣势(1)、当网站更新时,如果CDN节点上数据没有及时更新,即使用户在浏览器应用 Ctrl +F5 的形式使浏览器端的缓存生效,也会因为CDN边缘节点没有同步最新数据而导致用户拜访异样。 (2)、CDN不同的缓存工夫会对“回源率”产生间接的影响: 如果缓存工夫短,CDN边缘节点的内容常常生效,导致频繁回源。不仅减少服务器压力,也减少了用户拜访工夫。如果缓存工夫长,数据更新了,边缘节点的内容都还没更新,开发者对特定的工作做特定的数据缓存工夫治理。CDN刷新缓存CDN边缘节点对开发者是通明的,相比于浏览器Ctrl+F5的强制刷新来使浏览器本地缓存生效,开发者能够通过CDN服务商提供的“刷新缓存”接口来达到清理CDN边缘节点缓存的目标。这样开发者在更新数据后,能够应用“刷新缓存”性能来强制CDN节点上的数据缓存过期,保障客户端在拜访时,拉取到最新的数据。 |CDN优化(1)、前端须要被减速的文件大抵包含: js、css、图片、视频、和页面等文件。页面文件有动静和动态之分。这些文件和页面(比方html)最大的区别是:这些文件都是动态的,改变比拟小,这类动态文件适宜做CDN减速。咱们把这些动态文件通过CDN散发到世界各地的节点,用户能够在间隔最近的边缘节点拿到须要的内容,从而晋升内容下载速度放慢网页关上速度。页面分为动静页面和动态页面,动静页面不适宜做CDN缓存,因为页面是动静的话,内容的有效期就比拟沉闷。边缘节点的数据常常生效要回源,造成源服务器压力。(2)、缩小资源申请的等待时间 不同浏览器的并发数量不一样:IE11 、IE10 、chrome、Firefox 的并发连接数是 6个,IE9是10个。如果页面动态资源(图片等)过多(大于6个)会存在资源申请期待的状况。目前现实状况是大多用户带宽越来越大,然而咱们的动态资源并非那么大,很多文件都是几k或者几十k,6个文件加起来都小于带宽。这样就导致了资源的节约。 解决方案是:用多个不同IP的服务器来存储这些文件,并在页面中通过绝对路径的形式援用(要求同一IP的文件不超过6个)。这样就能够尽可能的缩小资源申请期待的状况。至此,你曾经获取到缓存服务器的IP地址,并且筹备向这个IP地址发送申请了。 三、建设TCP连贯TCP(1)、TCP是一种面向连贯的,牢靠的,基于字节流的传输层通信协议。 (2)、建设TCP连贯须要进行三次握手。过程如下: TCP握手过程(1)、客户端发送带有SYN标识(SYN=1,seq=x)的申请报文段,而后进入SYN_SEND状态,期待服务端确认; (2)、服务端接管到客户端SYN报文段后,须要发送ACK信息对这个SYN进行确认,同时还要发送本人的SYN信息(SYN=1,ACK=1,seq=y,ack=x+1)服务端把这些信息放在一个报文段中((SYN+ACK报文段),一并发给客户端,此时客户端进入SYN_RECV状态; (3)、客户端接管到服务端的SYN+ACK报文段后会向服务端发送ACK(ACK=1,seq=x+,ack=y+1)确认报文段,这个报文段发送后,客户端和服务端都进入ESTABLISHED状态,实现三次握手。为什么TCP建设肯定要三次呢?两次不行吗?起因: ...

January 2, 2023 · 1 min · jiezi

关于javascript:校招前端面试题集锦

JavaScript 类数组对象的定义?一个领有 length 属性和若干索引属性的对象就能够被称为类数组对象,类数组对象和数组相似,然而不能调用数组的办法。常见的类数组对象有 arguments 和 DOM 办法的返回后果,还有一个函数也能够被看作是类数组对象,因为它含有 length 属性值,代表可接管的参数个数。 常见的类数组转换为数组的办法有这样几种: (1)通过 call 调用数组的 slice 办法来实现转换 Array.prototype.slice.call(arrayLike);(2)通过 call 调用数组的 splice 办法来实现转换 Array.prototype.splice.call(arrayLike, 0);(3)通过 apply 调用数组的 concat 办法来实现转换 Array.prototype.concat.apply([], arrayLike);(4)通过 Array.from 办法来实现转换 Array.from(arrayLike);对节流与防抖的了解函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则从新计时。这能够应用在一些点击申请的事件上,防止因为用户的屡次点击向后端发送屡次申请。函数节流是指规定一个单位工夫,在这个单位工夫内,只能有一次触发事件的回调函数执行,如果在同一个单位工夫内某事件被触发屡次,只有一次能失效。节流能够应用在 scroll 函数的事件监听上,通过事件节流来升高事件调用的频率。防抖函数的利用场景: 按钮提交场景:防⽌屡次提交按钮,只执⾏最初提交的⼀次服务端验证场景:表单验证须要服务端配合,只执⾏⼀段间断的输⼊事件的最初⼀次,还有搜寻联想词性能相似⽣存环境请⽤lodash.debounce节流函数的适⽤场景: 拖拽场景:固定工夫内只执⾏⼀次,防⽌超⾼频次触发地位变动缩放场景:监控浏览器resize动画场景:防止短时间内屡次触发动画引起性能问题对浏览器的缓存机制的了解浏览器缓存的全过程: 浏览器第一次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header,以供下次加载时比照应用;下一次加载资源时,因为强制缓存优先级较高,先比拟以后工夫与上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,并命中强缓存,间接从本地读取资源。如果浏览器不反对HTTP1.1,则应用 expires 头判断是否过期;如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有 If-None-Match 和 If-Modified-Since 的申请;服务器收到申请后,优先依据 Etag 的值判断被申请的文件有没有做批改,Etag 值统一则没有批改,命中协商缓存,返回 304;如果不统一则有改变,间接返回新的资源文件带上新的 Etag 值并返回 200;如果服务器收到的申请没有 Etag 值,则将 If-Modified-Since 和被申请文件的最初批改工夫做比对,统一则命中协商缓存,返回 304;不统一则返回新的 last-modified 和文件并返回 200; ...

January 2, 2023 · 7 min · jiezi

关于javascript:从这两道题重新理解JS的this作用域闭包对象

日常开发中,咱们常常用到this。例如用Jquery绑定事件时,this指向触发事件的DOM元素;编写Vue、React组件时,this指向组件自身。对于老手来说,常会用一种意会的感觉去判断this的指向。以至于当遇到简单的函数调用时,就分不清this的真正指向。 本文将通过两道题去缓缓剖析this的指向问题,并波及到函数作用域与对象相干的点。最终给大家带来真正的实践剖析,而不是简简单单的一句话概括。 置信若是对this稍有钻研的人,都会搜到这句话:this总是指向调用该函数的对象。 然而箭头函数并不是如此,于是大家就会遇到如下各式说法: 箭头函数的this指向外层函数作用域中的this。箭头函数的this是定义函数时所在上下文中的this。箭头函数体内的this对象,就是定义时所在的对象,而不是应用时所在的对象。各式各样的说法都有,乍看下感觉说的差不多。废话不多说,凭着你之前的了解,来先做一套题吧(非严格模式下)。 /** * Question 1 */var name = 'window'var person1 = { name: 'person1', show1: function () { console.log(this.name) }, show2: () => console.log(this.name), show3: function () { return function () { console.log(this.name) } }, show4: function () { return () => console.log(this.name) }}var person2 = { name: 'person2' }person1.show1()person1.show1.call(person2)person1.show2()person1.show2.call(person2)person1.show3()()person1.show3().call(person2)person1.show3.call(person2)()person1.show4()()person1.show4().call(person2)person1.show4.call(person2)()大抵意思就是,有两个对象person1,person2,而后花式调用person1中的四个show办法,预测真正的输入。 你能够先把本人预测的答案按程序记在本子上,而后再往下拉看正确答案。 正确答案选下: person1.show1() // person1person1.show1.call(person2) // person2person1.show2() // windowperson1.show2.call(person2) // windowperson1.show3()() // windowperson1.show3().call(person2) // person2person1.show3.call(person2)() // windowperson1.show4()() // person1person1.show4().call(person2) // person1person1.show4.call(person2)() // person2比照下你刚刚记下的答案,是否有不一样呢?让咱们尝试来最开始那些实践来剖析下。 ...

January 2, 2023 · 2 min · jiezi

关于javascript:JavaScript-第一章-bindcallapply-的基本概念

call 、apply 、bind 作用是扭转函数执行时的上下文,简而言之就是扭转函数运行时的this指向。call 传入参数列表,apply 传入数组,然而都会立刻执行。bind 传入参数列表,不会立刻执行,适宜在定时器等回调函数中应用。 let fun = dog.eat.bind(cat,'fish');fun();1、例子代码中能够看到,失常状况say办法输入martin 。然而咱们把say放在setTimeout办法中,在定时器中是作为回调函数来执行的,因而回到主栈执行时是在全局执行上下文的环境中执行的,这时候this指向window,所以输入lucy const name="lucy";const obj={ name:"martin", say:function () { console.log(this.name); }};obj.say(); //martin,this指向obj对象setTimeout(obj.say,0); //lucy,this指向window对象理论须要的是this指向obj对象,这时候就须要该扭转this指向了。 setTimeout(obj.say.bind(obj),0); //martin,this指向obj对象2、区别三者都能够扭转函数的this对象指向三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window三者都能够传参,然而apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind能够分为屡次传入bind 是返回绑定this之后的函数,apply 、call 则是立刻执行1)apply 办法apply承受两个参数,第一个参数是this的指向,第二个参数是函数承受的参数,以数组的模式传入。扭转this指向后原函数会立刻执行,且此办法只是长期扭转this指向一次。 function fn(...args){ console.log(this,args);}let obj = { myname:"张三"}fn.apply(obj,[1,2]); // this会变成传入的obj,传入的参数必须是一个数组;fn(1,2) // this指向window当第一个参数为null、undefined的时候,默认指向window(在浏览器中) 。 fn.apply(null,[1,2]); // this指向windowfn.apply(undefined,[1,2]); // this指向window2)call 办法call办法的第一个参数也是this的指向,前面传入的是一个参数列表。跟apply一样,扭转this指向后原函数会立刻执行,且此办法只是长期扭转this指向一次。 function fn(...args){ console.log(this,args);}let obj = { myname:"张三"}fn.call(obj,1,2); // this会变成传入的objfn(1,2) // this指向window同样的,当第一个参数为null、undefined的时候,默认指向window(在浏览器中) 。 fn.call(null,[1,2]); // this指向windowfn.call(undefined,[1,2]); // this指向window3)bind 办法bind办法的第一参数也是this的指向,前面传入的也是一个参数列表(然而这个参数列表能够分屡次传入)。扭转this指向后不会立刻执行,而是返回一个永恒扭转this指向的函数。 function fn(...args){ console.log(this,args);}let obj = { myname:"张三"}const bindFn = fn.bind(obj); // this 也会变成传入的obj ,bind不是立刻执行须要执行一次bindFn(1,2) // this指向objfn(1,2) // this指向window3、基于call的继承能够通过 call,子类能够应用父类的办法。 ...

January 1, 2023 · 1 min · jiezi