关于javascript:js事件循环与macromicro任务队列前端面试进阶

背景一天惬意的下午。敌人给我分享了一道头条面试题,如下: async function async1(){ console.log('async1 start') await async2() console.log('async1 end')}async function async2(){ console.log('async2')}console.log('script start')setTimeout(function(){ console.log('setTimeout') },0) async1();new Promise(function(resolve){ console.log('promise1') resolve();}).then(function(){ console.log('promise2')})console.log('script end')这个题目次要是考查对同步工作、异步工作:setTimeout、promise、async/await的执行程序的了解水平。(倡议大家也本人先做一下o) 过后因为我对async、await理解的不是很分明,答案错的千奇百怪 :(),就不记录了,而后我就去看文章理了理思路。当初写在上面以供日后参考。 js事件轮询的一些概念这里首先须要明确几个概念:同步工作、异步工作、工作队列、microtask、macrotask 同步工作指的是,在主线程上排队执行的工作,只有前一个工作执行结束,能力执行后一个工作; 异步工作指的是,不进入主线程、而进入"工作队列"(task queue)的工作,期待同步工作执行结束之后,轮询执行异步工作队列中的工作 macrotask 即宏工作,宏工作队列等同于咱们常说的工作队列,macrotask是由宿主环境散发的异步工作,事件轮询的时候总是一个一个工作队列去查看执行的,"工作队列"是一个先进先出的数据结构,排在后面的事件,优先被主线程读取。 microtask 即微工作,是由js引擎散发的工作,总是增加到当前任务队列开端执行。另外在解决microtask期间,如果有新增加的microtasks,也会被增加到队列的开端并执行。留神与setTimeout(fn,0)的区别: setTimeOut(fn(),0)指定某个工作在主线程最早可得的闲暇工夫执行,也就是说,尽可能早得执行。它在"工作队列"的尾部增加一个事件,因而要等到同步工作和"工作队列"现有的事件都解决完,才会失去执行。 总结一下: task queue、microtask、macrotask An event loop has one or more task queues.(task queue is macrotask queue)Each event loop has a microtask queue.task queue = macrotask queue != microtask queuea task may be pushed into macrotask queue,or microtask queuewhen a task is pushed into a queue(micro/macro),we mean preparing work is finished,so the task can be executed now.所以咱们能够失去js执行程序是: ...

November 3, 2022 · 2 min · jiezi

关于javascript:nodejs-身份认证

请问昨天完结的早是对沉积在了明天吗,明天还来加个班更博,看在这个毅力的份上是否给亿点点举荐。 有个好消息有个坏消息,先说坏消息吧,就是在这么学上来我急需急支糖浆,来回顾回顾后面的常识,这几天学的太急了,搞得有点推着走的意思,好消息就是明天的内容是最初最初node的根底内容了,果然天不负我,整完而后有两个大案例,做完我就从上次温习那里开始始终温习过去,而后全副不欠账,就昂首挺胸的走进vue了,等等,这个学完能够进去了吧。 1. 明天的第一个内容说一下web开发模式,明天根本就是讲一个身份认证的内容,咱们的web开发模式呢分为两种,一种是服务器渲染模式,就是通过服务器进行一个字符串拼接,将html页面拼接进去,而后间接返回给客户端,这样一来就不须要咱们的ajax了,间接给客户端就能够了,他的长处呢就是前端耗时少,毕竟都给服务器做了还有前端什么事,还有他也有利于seo优化,他的毛病就是占用服务器资源,而且不利于前后端拆散开发效率低。 第二个模式:前后端拆散的模式,它是依赖于ajax的一个广泛应用,后端负责编写api接口,前端就负责调用接口就完事了。他的一个长处就是开发体验好、毕竟前后端拆散,用户体验也好,也加重了服务器的压力。 然而毛病就是不利于seo的优化。 2 而后咱们进入身份认证、 什么事身份认证? 通过肯定的伎俩对用户身份进行确认的形式。 服务器渲染开发用的就是session认证,而咱们的前后端拆散用的就是jwt认证,两者都各有各的长处谁也不让谁。 3. 先来说下session吧 首先理解一下http无状态性,就是指客户端每次的http申请都是独立的,间断多个申请间没有间接关系,服务器也不会被动保留每次http申请状态(就像收银员他能记住每个来的客户是会员吗?) 冲破无状态限度。 超市冲破这种限度的形式就是给每个会员发会员卡是吧,在咱们web畛域这种形式就是cookie。 cookie,是存储在用户浏览器一段不超过4kb的字符串,它是由name、value以及有效期。安全性,适用范围的可选属性组成,在不同的域名下,咱们的cookie是各自独立的,每当客户端发动申请,会主动把以后域名下的所有cookie发给服务器,留神只是以后域名下。 他的个性就是:主动发送、域名独立、过期时限、4kb限度 3.1 cookie在身份认证中的作用 当咱们客户端第一次申请服务器的时候,服务器会通过响应头向客户端发送一个身份认证的cookie,咱们的浏览器就会把这个cookie存储起来,当咱们下一次 申请的时候,就会间接发送这个cookie也就是后面说的会主动发送,即可证实身份。 要留神咱们的cookie是不具备安全性的,浏览器还提供了读写cookie的api,所以cookie很容易被伪造,就像咱们的会员卡也有伪造的一样。所以不要用cookie存储重要数据,包含咱们jwt也不能存前面会说到。 3.2 那么有没有办法来进步咱们cookie的安全性呢? 那就是session认证,就好比咱们的会员卡➕刷卡的机制就能破除伪造卡了。 session认证机制: 首先咱们的客户端登录账号密码发送了登录申请,服务器会开始验证,当验证胜利后,会将其存储在服务器的内存中,同时通过响应头返回一个对应的cookie字符串,咱们的浏览器就会把这个字符串保留在以后域名下,当咱们再次申请的时候,就会把域名下所有cookie一起发送服务器,服务器就会去找对只对应的cookie匹配胜利就能找到你信息了,而后就认证胜利了 3.3 说了这么多怎么来再服务器端应用咱们的sesson,首先装置导入两部曲而后还须要配置,留神配置是固定写法,secret是能够为任意字符串的。 配置过后就能够用req.session来拜访session对象了,将咱们的一些数据用sessin存储起来,而后登陆胜利又能够通过session取出来,当咱们退出登录还能够。destroy办法清空session,留神只是清空这个账户信息,不会清空他人的信息,具体代码如下: 留神看todo也就是咱们要做的 // 导入 express 模块const express = require('express')// 创立 express 的服务器实例const app = express()// TODO_01:请配置 Session 中间件const session = require('express-session')app.use(session({ secret : 'mySession', resave : 'false', saveUninitiallized: 'ture'}))// 托管动态页面app.use(express.static('./pages'))// 解析 POST 提交过去的表单数据app.use(express.urlencoded({ extended: false }))// 登录的 API 接口app.post('/api/login', (req, res) => { // 判断用户提交的登录信息是否正确 if (req.body.username !== 'admin' || req.body.password !== '000000') { return res.send({ status: 1, msg: '登录失败' }) } // TODO_02:请将登录胜利后的用户信息,保留到 Session 中 // 留神只有当下面配置了session之后才可能应用req.session这个对象 req.session.user = req.body // 用户信息 req.session.islogin = true // 用户的登录状态 res.send({ status: 0, msg: '登录胜利' })})// 获取用户姓名的接口app.get('/api/username', (req, res) => { // TODO_03:请从 Session 中获取用户的名称,响应给客户端 // 判断是否登录胜利 if(!req.session.islogin) { return res.send({status:1, msg:'fail'}) } // 登录胜利即可响应数据 return res.send({ status : 0, msg : 'success', username : [req.session.user.username] })})// 退出登录的接口app.post('/api/logout', (req, res) => { // TODO_04:清空 Session 信息 req.session.destroy() res.send({ status : 0, msg : '退出登录胜利' })})// 调用 app.listen 办法,指定端口号并启动web服务器app.listen(80, function () { console.log('Express server running at http://127.0.0.1:80')})3. ...

November 3, 2022 · 2 min · jiezi

关于javascript:一个关于D3js学习的仓库建立了

Learn-D3因为中文教程比拟少, 特定新建了一个d3相干学习(含demo)的中文仓库分享内容: D3外部模块的深刻解说 有一个零碎整体认知Analysis- examples 剖析场景的例子Observable D3团队分享示例的环境介绍第一点作为重点, 本系列会残缺涵盖 D3 概念, 比方:抉择、连贯、数据申请、缩放函数、事件处理和转换。D3-IntroductionD3.js是一个 JavaScript 库,用于在 Web 上创立定制的交互式图表。 D3全称 Data-Driven Documents 3个D结尾的单词也是它D3简写的由来。 大多数图表库(例如:Echarts)提供的都是现成的图表,而 D3 由很多根底构建块组成,能够应用这些构建块构建自定义图表或地图。 在codepen中尝试编辑下面示例应用 echarts.js 创立下面的条形图只需几行代码, 然而应用D3 创立下面的图表就会简单一些,因为它提供的办法更底层 (粒度更细一些)。并且须要有一些JavaScript, HTML, SVG和 CSS.的教训。 如果咱们的需要只是规范条形图、折线图或饼图,应该思考应用Echarts等库。然而,如果须要定制图表或有十分准确的需要,则应思考 D3js。 D3 的劣势 性能到底有哪些?十分受欢迎(上亿次的下载和上10万的star),社区沉闷 有大量开发的资源( D3团队公布为主)。超级灵便, 专一于图表组合的根底元素,例如scales,shapes。提供数据驱动批改HTML 和 SVG 元素 。各种规范数据加载 数据处理(例如 CSV 数据)。生成简单图表的助手,例如树形图、网络图。在不同图表状态之间制作动画的弱小转换成果。(十分多的内置函数)弱小的用户交互反对,包含平移、缩放和拖动。D3 外部到底有哪些模块? 下面就是D3所有的repositories(仓库), 大略分为几类: 常常应用的, 根底的(带五角星的,本系列也会解说)。例如: shapes selection工具类的 例如: time format timer废除的 很长时间不更新的。bundler request留神本系列不会波及到源码的解说。 后续如果有须要会补充。本系列contents(内容) 下面就是本系列内容的纲要, 简略拿几个开展说说: Selection & data joins Selection反对以数据驱动的形式增加、删除和批改 HTML 和 SVG 元素。。蕴含了十分多函数对元素的解决,例如:selecting Elements , modifying Elements ... ...

November 3, 2022 · 1 min · jiezi

关于javascript:nodejs-mysql

明天完结的挺早,因为明天的内容还能够不是很难,明天全程是学了一些对于mysql数据库和sql查问语句的内容包含在node终端外面怎么来连贯数据库。通过明天的一个学习,我感觉离那个境地越来越近了,就是那个本人实现一个网站,有服务器、有响应,就跟当初这些上线的网站一样一样的,越来越近了。 1. 这些内容其实上学期间就学过了,当初次要是拿来温习一下。 首先咱们先理解一下数据库的基本概念,用来组织、存储,治理数据的仓库。 咱们传统型数据库(mysql、sql、Oracle)的一个数据结构为:数据库》数据表》数据行》字段 库、表、行、字段之间的一些关系: ①每个我的项目都有独立的数据库文件 ②不同的数据要放在不同的表中,比方一个用户信息就应该放到user表中 ③每个表要寄存哪些信息是由字段来决定的 ④表中的行代表一条具体的数据 1.1 装置配置mysql,其实还是有一些步骤的,倡议baidu就不多赘述了这里。 而后装好后用workbench去创立一个数据库再去创立一个表这个时候就有一些数据类型参考了,常见的int整数型,varchar字符串型、tinyint是布尔值 包含还有一些非凡标识,pk代表主键具备惟一标识,nn是not null不能为空值,uq是值惟一,ai是值会自增 1.2 下面是通过用那个工具去写一些数据进去,然而咱们是程序员那必定是要用代码来实现的,sql结构化查询语言来了,专门搞数据库的语言。 无非就是四个增删改查,我说一下一些留神点,而后就可以看代码就行了。 首先是增这里的列名和值必须要一一对应就没有了 -- 通过 * 把 users 表中所有的数据查问进去-- select * from users-- 从 users 表中把 username 和 password 对应的数据查问进去-- select username, password from users-- 向 users 表中,插入新数据,username 的值为 tony stark password 的值为 098123-- insert into users (username, password) values ('tony stark', '098123')-- select * from users-- 将 id 为 4 的用户明码,更新成 888888-- update users set password='888888' where id=4-- select * from users-- 更新 id 为 2 的用户,把用户明码更新为 admin123 同时,把用户的状态更新为 1-- update users set password='admin123', status=1 where id=2-- select * from users-- 删除 users 表中, id 为 4 的用户-- delete from users where id=4-- select * from users-- and运算符-- select * from users where id = 1 and username = '2'-- select * from users where id = 1 or username = '2'-- oder by-- select * from users order by id desc-- countselect count(*) as total from users where status = 01.3 ...

November 3, 2022 · 3 min · jiezi

关于javascript:什么是好的错误消息

微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。错误信息是咱们在线日常生活的一部分。每次服务器故障或没有网络,或遗记在表格中增加一些信息,咱们就会收到错误信息。"出错了" 是常见的做尘。然而什么出错了?产生了什么?而且,最重要的是,我要怎么做能力修复它? 那怎么写才是一个好的提醒呢? 在介绍好的提醒之前,咱们先来看一下什么是不好的谬误提醒。 不好的谬误提醒 Inappropriate tone不失当的语气: 设想一下,一个医生在做一个手术,而后忽然说 "哎呀! 出了点问题......" ,当危险很大的时候,任何人都最不违心听到这句话。所以这时候不是安可恶的时候。咱们须要向用户表明,咱们晓得这是重大的,咱们明确这对他们很重要。 Technical jargon专业术语: 程序员喜爱把一些专业术语用在谬误提醒外面。例如:你不能获取我的数据?我的凭证被回绝了? 这些专业术语对用户来说并不重要,他们只想晓得什么中央出了问题,如何解决。 Passing the blame:甩锅:比方「无奈连贯到三方服务」。尽量把重点放在问题上,而不是导致问题的口头上。 Generic for no reason太官网的说辞:比方「稍后尝试」。晓得起因而不通知用户,是不好的。 好的谬误提醒 Say what happened and why:阐明出错的起因:让用户分明的晓得产生谬误的起因,能够通过视觉和文字的联合来实现。解释用户为什么会呈现这个谬误。即便是技术起因,也要阐明是咱们的起因,而不是用户操作谬误。比方:「因为技术上的起因,临时无奈连贯到你的账户」。 Provide reassurance提供保障:比方「你的批改已被保留到草稿」。 Be empathetic有同情心:比方用「请」。 Help them fix it帮忙他们解决:比方「理解如何解决这个问题」,并附加一篇知识库文章和链接。 Always give a way out总是给一条前途:比方「如果仍旧能解决,请分割客服」。 起源:https://wix-ux.com/when-life-... 代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。 交换有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

November 3, 2022 · 1 min · jiezi

关于javascript:如何使用Performance-API-来衡量应用性能

从历史上看,咱们对客户端性能监控形式十分无限,而且还遇到了API浏览器的限度,妨碍了咱们精确地掂量客户端性能。 侥幸的是,因为有了新的面向性能的api,这种状况正在开始扭转。当初,浏览器的Performance API给咱们提供了精确度量Web页面性能的工具。 不耐烦看的同学能够间接调到开端应用办法一览应用 Performance API 的益处这些api减少了在开发工具中使用性能剖析时的教训;Chrome开发工具和其余工具,如Lighthouse只在开发阶段有帮忙。然而应用Performance API,咱们能够在生产中取得实在的用户度量数据(RUM - real user measurement);咱们能够失去十分准确的工夫戳数据,这使得这些性能指标的剖析十分精确。Performance 接口能够获取到以后页面中与性能相干的信息。它是 High Resolution Time API 的一部分,同时也交融了 Performance Timeline API、Navigation Timing API、 User Timing API 和 Resource Timing API。—— MDNHigh resolution time高分辨率工夫的准确水平可达几分之一毫秒。相比之下,基于Date的工夫只能准确到毫秒。这种精确度使它成为精确测量工夫的现实工具。 由User-Agent (UA)测量的高分辨率工夫不会随着零碎工夫的任何更改而更改,因为它是从UA创立的全局时钟中获取的。 在Performance API中测量的每个测量值都是高分辨率工夫。这就是为什么你总是听到性能API是高分辨率工夫API的一部分。 Performance timeline APIPerformance timeline API 是Performance API的扩大。该扩大提供了基于特定筛选条件检索性能指标的接口。 Performance Timeline API提供了以下三个办法,蕴含在性能接口中: getEntries()getEntriesByName()getEntriesByType()每个办法返回从Performance API的所有其余扩大收集的entries列表。 PerformanceObserver 是API中蕴含的另一个接口。它次要用于察看性能时间轴(Performance Timeline),并在浏览器记录时告诉新的性能条目。它能够用来度量浏览器和 Node.js 应用程序中某些性能指标。 Performance entries咱们用Performance API度量的货色称为entries。以下是可供咱们应用的性能项: markmeasurenavigationresourcepaintframe应用这些条目和各自的API来度量性能。 应用 Navigation timing API 和 Resource timing API测量navigation timing API 和 resource timing API 有许多内容重叠,你能够浏览此文章具体理解他们之间的差别。 ...

November 2, 2022 · 2 min · jiezi

关于javascript:前端工程化一开篇

工程化不是简略的应用工具,所有以 降低成本 和 提高效率 或 保障稳定性 做出的措施都应该被归类为工程化的模块中 前言本文属于《前端工程化系列》的开篇,该系列次要介绍咱们一整套前端工程化解决方案。文章会由浅入深的来介绍如何实现前端工程化,以及一整套开箱即用的开源前端工程化解决方案。 文章次要面向中小型团队与老手,心愿咱们的这一整套工程化之路和解决思路能够帮忙团队与开发者提效。 前端工程化前端工程化次要指从前端我的项目开始开发到部署线上再到前期迭代保护到这一整个过程,从工程的角度治理前端开发,造成前端开发流程的一整套开发标准或解决方案,进步前端开发效率。 所以咱们要想实现前端工程化的基本目标是帮忙团队与开发者晋升效率和稳定性晋升,其本质还是帮忙业务获得收益。 研发效力鸿沟首先团队如果短期面对业务规模扩张的解决办法往往是间接加人,而随着人员规模的晋升研发效力却也在一直被团队沟通 & 重复性工作所鲸吞,此时持续减少人员规模所能带来的效力晋升的收益非常无限。 而随着业务复杂度与人员规模回升所带来的理论研发效力与期待的研发效力的落差就是研发效力鸿沟,工程化是研发效力鸿沟的无效解决方案。 通过工程化能够将团队内可复用的资产积淀来下防止反复开发浪费时间的同时,工程化所建设的对立标准和标准化流程缩小了团队之间的因为沟通和规范产生的效率降落,同时工程化通过提供本地环境与工程化平台能够在研发流程上节俭大量工夫从而晋升效率。 拆解研发流程要想晓得工程化须要在那些方面发力就须要对整体的研发流程有理解。 <div align=center>@堂主 制作的前端研发流程图</div> 如上图所示能够看到前端研发流程的整体链路,在此链路中个别中小前端团队或开发者因 工程化缺失带来困扰 的环节往往在「开发筹备阶段」与「编码&联调试阶段」和「调试优化阶段」。 其中「开发筹备阶段」制度标准的缺失往往带来团队中不同开发者的代码格调迥异,代码实现水准不一造成前期迭代保护的老本很高。 而「编码 & 联调阶段」往往会呈现像组件、工具函数等基建缺失,以及团队中前后端进度不一带来的前端等接口、后端提供接口品质差等我的项目节奏的困扰。 在整个研发流程周期中往往也是这两个阶段所耗费的工夫是最多的,那么在这两个环节中前端工程化的作用就是帮忙开发者更顺畅更疾速的实现开发。 所以咱们须要整顿出在没有工程化的时候研发在流程中会遇到什么问题。 工程化的缺失所带来的问题短少团队标准与制度 个人风格的代码使得保护老本大大晋升短少统一标准与最佳实际commit 不清晰,对紧急修复产生额定困扰新我的项目须要占用不少工夫实现各项筹备工作配置 短少 cli 来进行疾速启动大量反复的组件是在各个我的项目中复制粘贴应用 没有积淀的工具库、hooks 库高频应用的函数与代码扩散在各个我的项目中「各自实现」复制粘贴取代了团队积淀的优质解决方案接口 mocks 依赖前端本地手写模仿,或期待后端接口 大量接口申请代码一直 copy,充斥着开发者塞入的长期性能我的项目无监控,前端对线上问题无感知 埋点、监控的缺失使得前端对业务上线之后的感知变弱大量 UI 开发占用研发工夫,没有从业务中取得更高的晋升 急需「低代码」工具能够帮忙团队解决大量反复低价值的后盾 UI 开发工作团队不晓得如何切入 BFF 等服务端场景,所有环境服务端大小性能都依赖后端实现随着逐个拆前端研发流程上开发环节的问题,咱们解构了一个我的项目在开发过程中所遇各个问题的复杂度。 从上图咱们能够看进去绝大部分前端业务的研发上遇到的问题被拆解成两局部,右边是可防止的软件开发复杂度,左边则是胶水代码与业务逻辑。 可防止的软件开发复杂度: 这里是咱们依据业务划分的软件开发的根底老本,例如一些根底组件、业务组件和工具库等可复用的资产。这里的开发成本往往能够通过一次实现积淀下来在团队中一直的复用来大幅度晋升效率。 工程化在这里能够做的就是拆解成为团队可复用的根底组件、业务组件、hooks 与 utils、以及 cli 和 template,通过积淀可复用的资产达到防止反复开发,晋升研发效率实现工程化的第一步。同时须要制订团队的制度标准,欠缺代码格调的束缚与代码实现的品质,防止随着业务倒退而产生额定的保护老本。 胶水代码、业务最初一公里: 业务上咱们依据理论业务开发的过程中遇到的一些问题,例如数据源(接口)的 Mock 须要手写、后端同学 IDL、监控数据缺失等等。 工程化在这里能够做的就是提供对立的 Mocks 平台、依据文档生成 services 层代码、以及 Mocks 的能力,提供团队前端埋点、监控计划,通过低代码搭建平台解放沉重但低价值 UI 开发工作量。 ...

November 2, 2022 · 1 min · jiezi

关于javascript:canvas-垂直背景图滚动

一、效果图 想找游戏相干素材 二、间接上代码<!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>canvas 垂直背景图滚动</title></head><body> <canvas id="canvas" width="480" height="720"> 你的浏览器不反对 canvas,请降级你的浏览器。 </canvas> <script> const canvas = document.getElementById('canvas') let ctx = canvas.getContext("2d") var offSetY = 0; var image = new Image(); // 创立图片元素 image.onload = function(){ bgMove(image); } image.src = 'images/bg.jpg'; function bgMove() { // 记录状态 ctx.save(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.translate(0, offSetY); ctx.drawImage(image, 0, 0); ctx.drawImage(image, 0, -canvas.height); // 判断offSetY偏移量 offSetY += 0.2; if(offSetY >= canvas.height) { offSetY = 0; } ctx.restore(); window.requestAnimationFrame(bgMove); } </script></body></html>三、目录构造图片能够在这里找背景图片地址 ...

November 2, 2022 · 1 min · jiezi

关于javascript:js加密之扁平化

前言明天要说的扁平化和一般的不太一样,明天看到一个比拟有意思的js加密代码,我一开始剖析了很多遍没发现问题,最初才发现和一般的扁平化有什么不同。 源代码(一小部分做示例)function _0x1bcb87(_0x2ab100, _0x467715) { var _0x456db6 = { 'jentQ': function (_0x829220, _0x5590eb) { return _0x829220 + _0x5590eb; }, 'EBoOQ': function (_0x25c12c, _0x1d2a2f) { return _0x25c12c * _0x1d2a2f; }, 'ZOjgN': function (_0x37f007, _0x4ec00f) { return _0x37f007 - _0x4ec00f; } }; return _0x456db6['jentQ'](Math['floor'](_0x456db6['EBoOQ'](Math['random'](), _0x456db6['ZOjgN'](_0x467715, _0x2ab100))), _0x2ab100);}解密后function getRand(min, max) { return Math.floor(Math.random() * (max - min)) + min;}过程剖析这种将简略代码扁平化的加密办法,属于比拟高级的加密办法,利用多重表达式将一句本来简略的js复杂化,利用一个json或者数组将函数组合起来。 人工剖析还原这类扁平化的代码特地麻烦,不信的能够本人试试。 而将一般的js加密成这样模式的代码更是麻烦,不过目前曾经有成熟可用的工具站做到了这一点,并且这只是其中的一个小性能。 咱们间接将js源代码复制到www.jsjiami.com间接点击JS混同加密就能够了。一键加密。

November 2, 2022 · 1 min · jiezi

关于javascript:nodejs-路由中间件mysql

这几天天天搞到这么晚,我看明天的内容看起不多啊,不晓得为什么学着学着就到了这么晚。明天的内容还是有点多哈,有点自我矛盾了,再次一一道来。 1. 首先明天先看到路由的概念,什么叫做路由? 路由就是映射关系,在express中路由指的是客户端申请和服务器处理函数的映射关系,路由有三局部组成:申请类型、申请url和处理函数。 app.get(url,callback)其实就跟咱们后面所说的监听事件一样一一样的。 const express = require('express')const app = express()app.get('/', (req, res) => { res.send('收到get申请')})app.listen(80, () => console.log('express server running at http://127.0.0.1')) 这就是一个最简略的路由。路由的匹配过程,每当一个申请达到服务器器后,须要先通过路由匹配,当申请类型和url匹配胜利后才会调用前面的申请函数。、 用法 最简略的用法就是像咱们下面那样间接挂在实例上,这也是不举荐的,因为一个申请就要挂一个很麻烦很繁琐。 迷信的办法应该是创立路由模块。 分为五个步骤: 别离是创立路由js文件、调用express.Router创立路由对象、挂载路由、向外导出路有对象最初咱们的入口文件须要导入,在通过app.use去注册 // 1.导入expressconst express = require('express')// 2.创立路由对象const router = express.Router()// 3.挂载路由// 3.1挂载路由获取用户的信息router.get('/user/:id', (req, res) => { res.send(req.params)})// 3.2挂载路由承受用户发送的申请router.post('/post', (req, res) => { res.send('post胜利')})// 4.向外共享路由成员module.exports = { express, router }const express = require('./02模块化路由')const app = express.express()// 注册路由app.use(express.router)app.listen(80, () => console.log('express server running at http://127.0.0.1'))这里说一下app.use昨天也看到了,他其实就是一个用来注册全局中间件的。而后咱们还能够为路由挂载前缀,也是通过app.use来增加办法同昨天根本一样 ...

November 2, 2022 · 3 min · jiezi

关于javascript:后端分页每页的数量在后端定死的情况下进行后端导出所有数据递归解决接口和分页数据放到excel流

//后端每页返回的数据拼接的数组 eventsConcatResult = (events: any[]) => { let eventExcel:any[]=[] for (let j = 0; j < events.length; j++) { let array = []; array.push(events[j].camera['_id']) array.push(events[j].camera.alias) array.push((events[j].camera.parent && events[j].camera.parent['_id']) ? events[j].camera.parent['_id'] : "无") array.push((events[j].camera.parent.parent && events[j].camera.parent.parent['_id']) ? events[j].camera.parent.parent['_id'] : "无") array.push(events[j].category) switch (events[j].category) { case 0: array.push("产品") break; case 1: array.push("报警") break; case -1: array.push("未知") break; default: break; } array.push(events[j].code) switch (events[j].code) { case 1: array.push("人进入") break; case 2: array.push("人来到") break; case 3: array.push("人停留") break; case -1: array.push("未知") break; default: break; } array.push(`${this.utilsService.$server}${events[j].video_url}`) array.push(events[j].event_timeStamp) array.push(events[j].timeStamp) eventExcel.push(array) } return eventExcel; };//采纳递归的办法实现循环内异步调用接口,并且循环一页将这页拼接的数组放到excel流里。 ...

November 2, 2022 · 1 min · jiezi

关于javascript:nodejs-包express

首先,要先在这里分享一下我的喜悦,从昨天开始其实始终都在喜悦当中的,我收到了我的第一份offer,这感觉不摆了,比第一桶金都还难受,尽管我还没收到第一桶金哈哈,不过offer都得了应该也快了。 明天的内容有点小多,容我缓缓道来 1. 首先咱们看到包的治理配置文件以及下包慢的问题,在咱们多人合作下,是不是要常常把本人的代码共享进来通过git、github之类的,那么我应该发现一个问题,一个我的项目文件,有30M大小,而代码只有区区2M左右的内存,残余的都给谁了?都给了第三方包也就是node_modules外面的内容,所以为了轻量化,咱们在共享代码的时候必定是不能带node_modules这个文件夹的,把她扔进.gitignore文件外面疏忽掉,那咱们没有了第三方包的依赖怎么执行代码呢,第三方包必定还是要的,没有怎么能行,咱们有一个package.json的文件在这外面寄存了装置的所有的第三方包的内容。 1.1 疾速创立packagejson 只须要在我的项目的文件中执行node init -y 要留神一下,只能在英文目录上来创立这个文件,这里的英文是当前目录为英文,也就是上一级为中文都没的关系,而后就是当咱们运行npm i装置第三方包的时候就会把信息给到这个json文件中,所以咱们在装置前要先创立json文件。 1.2 dependencies节点 这是这个json外面的节点名,记录了npm装置了哪些包 1.3 既然咱们没有包,又晓得了所有须要的包名,那么怎么来一次性装置所有的包? npm install或者i不增加包名即可装置所有的包 1.4 卸载包 npm uninstall 包名没有简写 1.5 devDependencies节点 这个节点也是保留的装置的包,有些包是咱们在我的项目开发过程中才会用到,而有些包使咱们开发上线都会用到的包,咱们个别把前者放在devDependencies节点外面,把后者放在dependencies节点外面。 当然他也有特定的装置形式 npm i 包名 -D 2. 而后咱们看到下包会慢的一些起因,是因为咱们的npm的服务器是国外的,通过海底光缆传过来的数据当然慢,所以这个时候咱们须要把npm的镜像服务器换掉,通过npm config set registry能够查看以后npm的服务器 再通过npm config set registry='淘宝或者腾讯的镜像地址'就能够设置过去了。 之所以粗略带过,是因为咱们有简便办法,通过npm先装置一个nrm全局可用工具,全局就须要在包名前面增加一个-g 而后nrm ls 可查看以后可设置的服务器地址,再用nrm use 加这个服务器名字即可应用。 3. 包的分类 咱们把包分为两大类,一个是我的项目包,就是被装置到node_modules外面的包,这外面又有开发依赖包放在devDependencies节点外面的和外围依赖包开发上线都用失去的, 二个是全局包,放在c盘目录上面的,装置的时候通过-g参数装置的。 留神一下:只有工具性质的包才有全局装置的必要,因为他们提供了终端的一些命令 3.1 i5ting_toc 能够把md文件转换为html的小工具,留神是工具,这个其实挺不便的,后面始终用的Markdownpad2。 怎么来应用呢? i5ting_toc -f md文件门路 -o示意浏览器关上 3.2 一个标准包的构造必须要蕴含三个货色 ①每个包必须是独自目录 ②包的顶级目录下必须蕴含package.json ③packag.json必须蕴含name、version、main三个属性 接下来咱们就来做一个 属于本人的包:要实现的性能就为:能够格式化日期、能够对html中的字符本义为特殊字符又本义回来。 首先要初始化包的根本构造,创立一个包的文件夹,外面放三个文件,index.js、package.json、README.md别离示意包入口文件、包的配置文件、包阐明文档。 接下来在初始化package.json外面的内容,{name:使咱们包的名字到时候npm网站上搜寻也是这个名字,所以应用前先去网站看一下有没有重名的, version:版本号, main:入口文件,阐明了咱们的导入就为这个文件要留神一下,如果说外界导入的时候只是导入了一个目录,并不是这个js文件,那么node就会去找这个目录下的package.json外面的main再去找入口文件, ...

November 2, 2022 · 2 min · jiezi

关于javascript:令人头疼的Javascript隐式强制转换

Javascript 的隐式强制只是指 Javascript 试图将意外的值类型强制为预期的类型。因而,您能够在须要数字的中央传递一个字符串,在须要字符串的中央传递一个对象等,它会尝试将其转换为正确的类型。这是最好防止的 Javascript 性能。 3 * "3" //91 + "2" + 1 //121true + true //210 - true //9const foo = { valueOf: () => 2}3 + foo // 54 * foo // 8const bar = { toString: () => " promise is a boy :)"}1 + bar // "1 promise is a boy :)"4 * [] // 04 * [2] // 84 + [2] // "42"4 + [1, 2] // "41,2"4 * [1, 2] // NaN"string" ? 4 : 1 // 4undefined ? 4 : 1 // 1数字表达式中的非数字值字符串每当您在波及以下任一运算符的数字表达式中将字符串作为操作数传递时:-, *, /, %,数字的转换过程相似于对值调用内置Number函数。这非常简单,任何仅蕴含数字字符的字符串都将转换为其等效的数字,但蕴含非数字字符的字符串将返回NaN. 如下图, ...

November 2, 2022 · 3 min · jiezi

关于javascript:前端懒加载和预加载

懒加载和预加载的目标都是为了进步用户的体验,二者行为是相同的,一个是提早加载,另一个是提前加载。懒加载对缓解服务器压力有肯定作用,预加载则会增长服务器前端压力缓存。 懒加载 lazyload懒加载:又叫提早加载、按需加载,当咱们关上一个网页,优先展现的首屏图片就先加载,而其余的图片,等到须要去展现的时候再去申请图片资源。 目标:更好的加载页面的首屏内容,对于含有不少图片的比拟长的网页来讲,可能加载的更快,防止了首次关上时,一次性加载过多图片资源,是对网页性能的一种优化形式。 原理:浏览器解析到img标签的src有值,才会去发动申请,那么就能够让图片须要展现时,才对其src赋值真正的图片地址。 实现代码<!DOCTYPE html><html lang="en"> <head> <meta charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>图片懒加载</title> <style> * { margin: 0; padding: 0; } img { margin: 50px; width: 400px; height: 200px; } </style> </head> <body> <div class="img-container"> <img src="loading.gif" alt="" data-src="1.jpg" class="lazyload" /> </div> <div class="img-container"> <img src="loading.gif" alt="" data-src="2.jpg" class="lazyload" /> </div> <div class="img-container"> <img src="loading.gif" alt="" data-src="3.jpg" class="lazyload" /> </div> <div class="img-container"> <img src="loading.gif" alt="" data-src="4.jpg" class="lazyload" /> </div> <div class="img-container"> <img src="loading.gif" alt="" data-src="5.jpg" class="lazyload" /> </div> <script> const imgs = [...document.querySelectorAll(".lazyload")]; //img元素转换成数组 lazyload(); //初始调用一次 window.addEventListener("scroll", lazyload, false); //监听滚动时也调用lazyload函数,冒泡阶段 //懒加载 function lazyload() { for (let i = 0; i < imgs.length; i++) { const $img = imgs[i]; //每次循环拿到每一个img元素 if (isInVisibleArea($img)) { //判断img元素是否在可视区域内 $img.src = $img.dataset.src; //用data-src替换src属性 imgs.splice(i, 1); //对应该索引的元素删掉 i--; } } } // 判断DOM元素是否在可视区域内,返回true/false function isInVisibleArea($el) { const rect = $el.getBoundingClientRect(); console.log(rect); return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth; } </script> </body></html>实现细节1 如何加载图片用img的data-src属性寄存真正须要显示的图片的门路,当页面滚动直到图片呈现在可视区域时,将data-src中的图片地址值赋值给src属性值。 ...

November 2, 2022 · 3 min · jiezi

关于javascript:彻底搞懂JS原型与原型链

说到JavaScript的原型和原型链,相干文章已有不少,然而大都艰涩难懂。本文将换一个角度登程,先了解原型和原型链是什么,有什么作用,再去剖析那些令人头疼的关系。 一、援用类型皆为对象原型和原型链都是来源于对象而服务于对象的概念,所以咱们要先明确一点: JavaScript中所有援用类型都是对象,对象就是属性的汇合。 Array类型、Function类型、Object类型、Date类型、RegExp类型等都是援用类型。 也就是说 数组是对象、函数是对象、正则是对象、对象还是对象。 二、原型和原型链是什么下面咱们说到对象就是属性(property)的汇合,有人可能要问不是还有办法吗?其实办法也是一种属性,因为它也是键值对的表现形式,具体见下图。 能够看到obj上的确多了一个sayHello的属性,值为一个函数,然而问题来了,obj下面并没有hasOwnProperty这个办法,为什么咱们能够调用呢?这就引出了 原型。 每一个对象从被创立开始就和另一个对象关联,从另一个对象上继承其属性,这个另一个对象就是 原型。 当拜访一个对象的属性时,先在对象的自身找,找不到就去对象的原型上找,如果还是找不到,就去对象的原型(原型也是对象,也有它本人的原型)的原型上找,如此持续,直到找到为止,或者查找到最顶层的原型对象中也没有找到,就完结查找,返回undefined。 这条由对象及其原型组成的链就叫做原型链。 当初咱们曾经初步了解了原型和原型链,到当初大家明确为什么数组都能够应用push、slice等办法,函数能够应用call、bind等办法了吧,因为在它们的原型链上找到了对应的办法。 OK,总结一下: 原型存在的意义就是组成原型链:援用类型皆对象,每个对象都有原型,原型也是对象,也有它本人的原型,一层一层,组成原型链。原型链存在的意义就是继承:拜访对象属性时,在对象自身找不到,就在原型链上一层一层找。说白了就是一个对象能够拜访其余对象的属性。继承存在的意义就是属性共享:益处有二:一是代码重用,字面意思;二是可扩大,不同对象可能继承雷同的属性,也能够定义只属于本人的属性。三、创建对象对象的创立形式次要有两种,一种是new操作符后跟函数调用,另一种是字面量表示法。 目前咱们当初能够了解为:所有对象都是由new操作符后跟函数调用来创立的,字面量表示法只是语法糖(即实质也是new,性能不变,应用更简洁)。 // new操作符后跟函数调用let obj = new Object()let arr = new Array()// 字面量表示法let obj = { a: 1}// 等同于let obj = new Object()obj.a = 1let arr = [1,2]// 等同于let arr = new Array()arr[0] = 1arr[1] = 2Object、Array等称为构造函数,不要怕这个概念,构造函数和一般函数并没有什么不同,只是因为这些函数常被用来跟在new前面创建对象。new前面调用一个空函数也会返回一个对象,任何一个函数都能够当做构造函数。 所以构造函数更正当的了解应该是函数的结构调用。 Number、String、Boolean、Array、Object、Function、Date、RegExp、Error这些都是函数,而且是原生构造函数,在运行时会主动呈现在执行环境中。 构造函数是为了创立特定类型的对象,这些通过同一构造函数创立的对象有雷同原型,共享某些办法。举个例子,所有的数组都能够调用push办法,因为它们有雷同原型。 咱们来本人实现一个构造函数: // 常规,构造函数应以大写字母结尾function Person(name) { // 函数内this指向结构的对象 // 结构一个name属性 this.name = name // 结构一个sayName办法 this.sayName = function() { console.log(this.name) }}// 应用自定义构造函数Person创建对象let person = new Person('logan')person.sayName() // 输入:logan总结一下:构造函数用来创建对象,同一构造函数创立的对象,其原型雷同。 ...

November 2, 2022 · 3 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 ...

November 2, 2022 · 4 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咱们通过判断下一次是否传进来参数来决定函数是否运行,如果持续传进了参数,那咱们持续把参数都保存起来,等运行的时候全副一次性运行,这样咱们就初步实现了一个柯里化的函数。 ...

November 2, 2022 · 3 min · jiezi

关于javascript:前端面试那些题

对对象与数组的解构的了解解构是 ES6 提供的一种新的提取数据的模式,这种模式可能从对象或数组里有针对性地拿到想要的数值。 1)数组的解构 在解构数组时,以元素的地位为匹配条件来提取想要的数据的: const [a, b, c] = [1, 2, 3]最终,a、b、c别离被赋予了数组第0、1、2个索引位的值: 数组里的0、1、2索引位的元素值,精准地被映射到了左侧的第0、1、2个变量里去,这就是数组解构的工作模式。还能够通过给左侧变量数组设置空占位的形式,实现对数组中某几个元素的精准提取: const [a,,c] = [1,2,3]通过把两头位留空,能够顺利地把数组第一位和最初一位的值赋给 a、c 两个变量: 2)对象的解构 对象解构比数组构造略微简单一些,也更显弱小。在解构对象时,是以属性的名称为匹配条件,来提取想要的数据的。当初定义一个对象: const stu = { name: 'Bob', age: 24}如果想要解构它的两个自有属性,能够这样: const { name, age } = stu这样就失去了 name 和 age 两个和 stu 平级的变量: 留神,对象解构严格以属性名作为定位根据,所以就算调换了 name 和 age 的地位,后果也是一样的: const { age, name } = stuIterator迭代器Iterator(迭代器)是一种接口,也能够说是一种标准。为各种不同的数据结构提供对立的拜访机制。任何数据结构只有部署Iterator接口,就能够实现遍历操作(即顺次解决该数据结构的所有成员)。Iterator语法: const obj = { [Symbol.iterator]:function(){}}[Symbol.iterator] 属性名是固定的写法,只有领有了该属性的对象,就可能用迭代器的形式进行遍历。迭代器的遍历办法是首先取得一个迭代器的指针,初始时该指针指向第一条数据之前,接着通过调用 next 办法,扭转指针的指向,让其指向下一条数据每一次的 next 都会返回一个对象,该对象有两个属性 value 代表想要获取的数据done 布尔值,false示意以后指针指向的数据有值,true示意遍历曾经完结Iterator 的作用有三个: ...

November 2, 2022 · 11 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 的费用。 ...

November 2, 2022 · 6 min · jiezi

关于javascript:一年前端面试打怪升级之路

过程与线程的概念从实质上说,过程和线程都是 CPU 工作工夫片的一个形容: 过程形容了 CPU 在运行指令及加载和保留上下文所需的工夫,放在利用上来说就代表了一个程序。线程是过程中的更小单位,形容了执行一段指令所需的工夫。过程是资源分配的最小单位,线程是CPU调度的最小单位。 一个过程就是一个程序的运行实例。具体解释就是,启动一个程序的时候,操作系统会为该程序创立一块内存,用来寄存代码、运行中的数据和一个执行工作的主线程,咱们把这样的一个运行环境叫过程。过程是运行在虚拟内存上的,虚拟内存是用来解决用户对硬件资源的有限需要和无限的硬件资源之间的矛盾的。从操作系统角度来看,虚拟内存即交换文件;从处理器角度看,虚拟内存即虚拟地址空间。 如果程序很多时,内存可能会不够,操作系统为每个过程提供一套独立的虚拟地址空间,从而使得同一块物理内存在不同的过程中能够对应到不同或雷同的虚拟地址,变相的减少了程序能够应用的内存。 过程和线程之间的关系有以下四个特点: (1)过程中的任意一线程执行出错,都会导致整个过程的解体。 (2)线程之间共享过程中的数据。 (3)当一个过程敞开之后,操作系统会回收过程所占用的内存, 当一个过程退出时,操作系统会回收该过程所申请的所有资源;即便其中任意线程因为操作不当导致内存透露,当过程退出时,这些内存也会被正确回收。 (4)过程之间的内容互相隔离。 过程隔离就是为了使操作系统中的过程互不烦扰,每一个过程只能拜访本人占有的数据,也就避免出现过程 A 写入数据到过程 B 的状况。正是因为过程之间的数据是严格隔离的,所以一个过程如果解体了,或者挂起了,是不会影响到其余过程的。如果过程之间须要进行数据的通信,这时候,就须要应用用于过程间通信的机制了。 Chrome浏览器的架构图: 从图中能够看出,最新的 Chrome 浏览器包含: 1 个浏览器主过程1 个 GPU 过程1 个网络过程多个渲染过程多个插件过程这些过程的性能: 浏览器过程:次要负责界面显示、用户交互、子过程治理,同时提供存储等性能。渲染过程:外围工作是将 HTML、CSS 和 JavaScript 转换为用户能够与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该过程中,默认状况下,Chrome 会为每个 Tab 标签创立一个渲染过程。出于平安思考,渲染过程都是运行在沙箱模式下。GPU 过程:其实, GPU 的应用初衷是为了实现 3D CSS 的成果,只是随后网页、Chrome 的 UI 界面都抉择采纳 GPU 来绘制,这使得 GPU 成为浏览器广泛的需要。最初,Chrome 在其多过程架构上也引入了 GPU 过程。网络过程:次要负责页面的网络资源加载,之前是作为一个模块运行在浏览器过程外面的,直至最近才独立进去,成为一个独自的过程。插件过程:次要是负责插件的运行,因插件易解体,所以须要通过插件过程来隔离,以保障插件过程解体不会对浏览器和页面造成影响。所以,关上一个网页,起码须要四个过程:1 个网络过程、1 个浏览器过程、1 个 GPU 过程以及 1 个渲染过程。如果关上的页面有运行插件的话,还须要再加上 1 个插件过程。 尽管多过程模型晋升了浏览器的稳定性、流畅性和安全性,但同样不可避免地带来了一些问题: ...

November 2, 2022 · 4 min · jiezi

关于javascript:80的前端开发都答不上来的js异步面试题

最近面试中碰到了一道对于JS执行程序的题目,题目比拟根底,然而如果对于JS不熟的话,还是容易答不上来。再次记录和剖析此次面试题,心愿对大家有所帮忙。 async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } console.log("js start"); setTimeout(function () { console.log("timeout"); }, 0); async1(); new Promise(function (resolve) { console.log("promise"); resolve(); }).then(function () { console.log("then"); }); console.log("js end");话不多说,先上后果 // 控制台输入后果 "js start" "async1 start" "async2" "promise" "js end" "async1 end" "then" "timeout"宏工作 微工作如果看官是个老手的话,看到下面的输入后果,必定一脸懵逼的,然而没关系,看完这篇文章您就懂了。想齐全明确下面这道题目,还须要理解JS的两个概念,没错,就是宏工作和微工作。 首先看官必定晓得JS是单线程,实现异步的办法就是定时器和es6+呈现的promise/async等,那么当初问题来了,既然es6呈现的新的异步形式,那么和之前的定时器相比,那个异步先执行呢? 宏工作(macro)task,能够了解为每段代码都是一个宏工作,没错JS的主程序也是宏工作。同时两个定时器异步的局部也是宏工作。 微工作microtask,能够了解是在以后 task 执行完结后立刻执行的工作。也就是在主程序执行实现之后立刻执行的局部。es6+呈现的promise,async都是微工作。在这里要记住一句话,微工作的优先级是高于宏工作的。 程序执行程序1、主程序 因为js是单线程的,同一时间只能有一段代码在执行,所以首先执行的就是JS的主程序。之前说主程序是宏工作,微工作优先级又比宏工作高,那为什么还先执行主程序这个宏工作呢? 这是因为:没有主程序去构建微工作,微工作又怎么会呈现呢,没有微工作的呈现,当然就去找到主程序这个宏工作了,所以优先级的说法没有谬误。 2、查看是否有异步工作 当上一个工作执行实现之后,程序会去检索是否有微工作,须要执行,如果有,就会先执行微工作。没有微工作但有宏工作,执行宏工作。没有工作,代码不在执行。 3、微工作 微工作代码执行,和失常的JS代码执行没有区别,从上往下编译执行!!!执行实现之后,会跳回到第二步。 4、宏工作 ...

November 2, 2022 · 1 min · jiezi

关于javascript:JavaScript-求数组的所有子集

一、题目要求给定义一个子项不反复的数组,求此数组的所有子集。 二、思路设有一个二进制变量,其长度刚好等于数组长度。用这个变量的每一位来代表数组中的每一个子项,为 0 则无,为 1 则有,则这个变量的每一个可能的值映射的数组都是数组的一个子集(排除最大的一位数,也就是全为 1 的时候)。 三、题解代码如下: function subsets(nums){ const {length} = nums; const maximum = 2 ** length; const res = []; for(let index = 0; index < maximum; index ++){ const tempArr = []; for(let subIndex = 0; subIndex < length; subIndex++){ if(index & (1 << subIndex)){ tempArr.push(nums[subIndex]); } } res.push(tempArr); } return res}

November 2, 2022 · 1 min · jiezi

关于javascript:js数据类型闭包

js中有哪些数据类型及区别根本数据类型string / number / boolean / undefined / null / symbol(代表创立之后举世无双,且不可变的数据类型)援用数据类型Object根本数据类型与援用数据类型的区别申明变量时存储调配不同,根本数据类型存储在栈中,援用数据类型存储在堆中。不同的内存分配机制导致拜访机制也不同。根本类型能够间接被拜访的,援用数据要先拜访存储在栈中的援用地址,再依据援用地址找到堆中的实体。(不能够间接拜访堆内存的地位以及间接操作堆内存空间,只能操作对象在栈内存中的援用地址)赋值变量时不同,根本数据类型会将原始值的正本赋值给新的变量(传值),而援用类型是将援用类型的地址复制给新的变量(传址)闭包定义:1、函数中返回一个函数,2、函数申明的作用域和函数应用的作用域不同用处:获取公有作用域的变量(此处timer为公有作用域变量,这些变量能够保留到内存中)const debounce = (()=>{ let timer = null; return (callback,time)=>{ timer && clearTimeout(timer) timer = setTimeout(callback,time) }})()闭包的优缺点长处:防止全局变量的净化。变量长期贮存在内存中(缓存变量)毛病:内存泄露(耗费),常驻内存,减少内存使用量 面试真题// 一般形式var fnArr = [];for(var i=0;i<10;i++){ fnArr[i] = function(){ return i }}console.log(i) //后果为 10console.log(fnArr[7]()) // 后果为 10//闭包写法var fnArr = [];for(var i=0;i<10;i++){ fnArr[i] = (function(){ let j = i; return function(){ return j } })()}console.log(i) // 后果为10console.log(fnArr[7]()) //后果为 7

November 1, 2022 · 1 min · jiezi

关于javascript:javascript异步编程之generator生成器函数与asnycawait语法糖

Generator 异步计划相比于传统回调函数的形式解决异步调用,Promise最大的劣势就是能够链式调用解决回调嵌套的问题。然而这样写仍然会有大量的回调函数,尽管他们之间没有嵌套,然而还是没有达到传统同步代码的可读性。如果以上面的形式写异步代码,它是很简洁,也更容易浏览的。 // like sync modetry{ const value1 = ajax('/api/url1') console.log(value1) const value2 = ajax('/api/url1') console.log(value2) const value3 = ajax('/api/url1') console.log(value3) const value4 = ajax('/api/url1') console.log(value4) const value5 = ajax('/api/url1') console.log(value5)}catch(err){ console.log(err)} 在ES2015提供了生成器函数(Generator Function)它与一般函数的语法差异在于,在function语句之后和函数名之前,有一个“*”作为生成器函数的标示符。 在咱们去调用生成器函数的时候他并不会立刻去执行这个函数,而是会失去一个生成器对象,直到咱们手动调用对象的next 办法,函数体才会开始执行,咱们能够应用关键字yield去向外返回一个值,咱们能够在next办法的返回值中去拿到这个值。另外再返回的属性中还有一个done关键字来示意生成器是否执行完了, yield不会像return一样去完结函数的执行,只是暂停函数的执行,直到外接下一次调用next办法时才会持续从yield地位往下执行 function * foo () { console.log('start') yield 'foo'}const generator = foo()const result = generator.next()调用next办法的时候传入了参数的话,所传入的参数会作为yield关键字的返回值 function * foo () { console.log('start') // 我能够在这里接管next传入的参数 const res = yield 'foo' console.log(res) // 这是我传入的参数}const generator = foo()const result = generator.next('这是我传入的参数')console.log(result) // { value: 'foo', done: false }如果咱们调用了生成器函数的throw办法,这个办法会给生成器函数外部抛出一个异样 ...

November 1, 2022 · 2 min · jiezi

关于javascript:html使用canvas合并多张图片并下载

html应用canvas合并多张图片并下载html应用canvas合并多张图片并下载1. 创立canvas对象,并引入2d上下文实例const canvas = document.createElement('canvas')let ctx = canvas.getContext('2d');canvas.width = 1920 // 设定canvas的宽度、高度canvas.height = 10802. 创立图片对象let img1 = new Image();img1.src = require('../../assets/img/monitor/map-name.png');// 监听onload 事件,待图片加载结束后绘制到canvas上// 计数器,用来计数是否全副加载实现let num = 0img1.onload = function() { ctx.drawImage(img1, 10, 10); // 假如img1是必须先退出,则其余图片在其onload函数上加载并绘制到canvas let img2 = new Image(); img2.src = require('../../assets/img/monitor/map-name.png'); let img3 = new Image(); img3.src = require('../../assets/img/monitor/boundary.png'); // 别离监听img2和img3的onload事件 img1.onload = function() { ctx.drawImage(img1, 10, 10); num++ if (num === 2) { // 判断是否是最初一张,是最初一张则下载图片 // 将canvas转化成URL链接,用a标签进行下载或者预览,img标签预览都能够 href = canvas.toDataURL(); const downloadElement = document.createElement('a') downloadElement.href = href downloadElement.target = '_blank' downloadElement.download = `${name}.png` document.body.appendChild(downloadElement) downloadElement.click() document.body.removeChild(downloadElement) } } img3.onload = function() { ctx.drawImage(img3, 10, 10); num++ if (num === 2) { href = canvas.toDataURL(); const downloadElement = document.createElement('a') downloadElement.href = href downloadElement.target = '_blank' downloadElement.download = `${name}.png` document.body.appendChild(downloadElement) downloadElement.click() document.body.removeChild(downloadElement) } }})注:思路就是将图片依照你想要的程序增加到canvas的指定地位,而后待全副加载实现后采纳a标签下载下来,本地链接,内部链接,blob流都实用

November 1, 2022 · 1 min · jiezi

关于javascript:js-常用工具函数

// 防抖函数,应用场景:避免按钮屡次点击,调整浏览器大小resize过于频繁,键盘抬起const debounce = (()=>{ let timer = null; return (callback,time=800)=>{ timer && clearTimeout(timer) timer = setTimeout(callback, time); }})()//应用示例:btn.addEventListener("click",function(){ debounce(()=>{XXX逻辑代码XX},2000) })//节流函数,const throttle = (()=>{ let last = 0; return (callback,time=800)=>{ let now = +new Date() if(now-last>time){ callback(); last = now; } }})()//数组对象去重const uniqueArrayObject = (arr=[],key="id")=>{ if(arr.length == 0 ) return false; let map = {} arr.forEach(element => { if(!map[element[key]]){ map[element[key]] = element } }); return Object.values(map)}// 判断数据类型const typeOf = obj =>Object.prototype.toString.call(obj).slice(8,-1)//滚动到页面顶部const scrollTop = ()=>{ let height = document.documentElement.scrollTop || document.body.scrollTop; if(height>10){ window.requestAnimationFrame(scrollTop) window.scrollTo(height,height/8) }}//滚动到固定某一地位const scrollElement = el=>{ document.querySelector(el).scrollIntoView({behavior:'smooth'})}//获取以后工夫const getTime = (date=new Date())=>{ let y = date.getFullYear(); let m = date.getMonth()+1; m = m<10?'0'+m : m; let d = date.getDate() d = d<10? "0"+ d: d; return y+'/'+m+'/'+d}//获取月份的第一天及最初一天const getFirstLastDay =()=>{ let now = new Date() let y = now.getFullYear(); let m = now.getMonth(); let firstDay = new Date(y,m,1) let lastDay = new Date(y,m+1,0) firstDay = firstDay.getMonth + 1 + '/'+'0'+firstDay.getDate() lastDay = lastDay.getMonth+1 + '/'+lastDay.getDate(); return {firstDay,lastDay}}// 含糊查问const searchQuery = (list=[],keyword,attr='name')=>{ let reg = new RegExp(keyword) let arr = [] list.forEach(i=>{ if(reg.test(i[attr])){ arr.push(i) } }) return arr;}let commonFun = { debounce, throttle, uniqueArrayObject, typeOf, scrollTop, scrollElement, getTime, getFirstLastDay, searchQuery}window.commonFun = commonFun

November 1, 2022 · 1 min · jiezi

关于javascript:一文读懂Js中的this指向

前言this关键字是一个十分重要的语法点。毫不夸大地说,不了解它的含意,大部分开发工作都无奈实现。 简略说,this就是属性或办法“以后”所在的对象。 this.property下面代码中,this就代表property属性以后所在的对象。 上面是一个理论的例子。 var person = { name: '张三', describe: function () { return '姓名:'+ this.name; }};person.describe()// "姓名:张三"下面代码中,this.name示意name属性所在的那个对象。因为this.name是在describe办法中调用,而describe办法所在的以后对象是person,因而this指向person,this.name就是person.name。 因为对象的属性能够赋给另一个对象,所以属性所在的以后对象是可变的,即this的指向是可变的。 var A = { name: '张三', describe: function () { return '姓名:'+ this.name; }};var B = { name: '李四'};B.describe = A.describe;B.describe() // "姓名:李四"下面代码中,A.describe属性被赋给B,于是B.describe就示意describe办法所在的以后对象是B,所以this.name就指向B.name。 只有函数被赋给另一个变量,this的指向就会变。 var A = { name: '张三', describe: function () { return '姓名:'+ this.name; }};var name = '李四';var f = A.describe;f() // "姓名:李四"下面代码中,A.describe被赋值给变量f,外部的this就会指向f运行时所在的对象(本例是顶层对象,在浏览器中就是window),因而name为全局name的值。 本质JavaScript 语言之所以有 this 的设计,跟内存外面的数据结构有关系。 ...

November 1, 2022 · 6 min · jiezi

关于javascript:一比一手写迷你版vue彻底搞懂vue运行机制

前言当初前端面试Vue中都会问到响应式原理以及如何实现的,如果你还只是简略答复通过Object.defineProperty()来劫持属性可能曾经不够了。 本篇文章通过学习文档及视频教程实现手写一个繁难的Vue源码实现数据双向绑定,解析指令等。 几种实现双向绑定的做法目前几种支流的mvc(vm)框架都实现了单向数据绑定,而我所了解的双向数据绑定无非就是在单向绑定的根底上给可输出的元素(input, textare等)增加了change(input)事件,来动静批改model和view,并没有多浅近,所以无需太过介怀是实现的单向或双向绑定。 实现数据绑定的做法有大抵如下几种:发布者-订阅者模式(backbone.js) 脏值查看(angular.js) 数据劫持(Vue.js) 发布者-订阅者模式个别是通过sub, pub的形式来实现数据和试图的绑定坚听,更细数据办法通常做法是vm.set('property', value)这种形式当初毕竟太low来,咱们更心愿通过vm.property = value这种形式更新数据,同时自动更新视图,于是有来上面两种形式。 脏值查看angular.js是通过脏值检测的形式比照数据是否有变更,来决定是否更新视图,最简略的形式就是通过setInterval()定时轮询检测数据变动,当然Google不会这么low,angular只有在制订的事件触发时进入脏值检测,大抵如下 * DOM事件,臂如用户输出文本,点击按钮等(ng-click)* XHR响应事件($http)* 浏览器location变更事件($location)* Timer事件($timeout, $interval)* 执行$diaest()或¥apply()数据劫持Vue.js则是通过数据劫持联合发布者-订阅者模式的形式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时公布音讯给订阅者,触发相应的监听回调。 Vue源码实现index.html <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript" src="./compile.js"></script> <script type="text/javascript" src="./observe.js"></script> <script type="text/javascript" src="./myvue.js"></script> </head> <body> <div id="app"> <h2>{{person.name}} -- {{person.age}}</h2> <h3>{{person.sex}}</h3> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> <div v-text="msg"></div> <div>{{msg}}</div> <div v-text="person.name"></div> <div v-html="htmlStr"></div> <input type="text" v-model="msg" /> <button type="button" v-on:click="btnClick">v-on:事件</button> <button type="button" @click="btnClick">@事件</button> </div> <script type="text/javascript"> let vm = new Myvue({ el: '#app', data: { person: { name: '只会番茄炒蛋', age: 18, sex: '男' }, msg: '学习MVVM实现原理', htmlStr: '<h1>我是html指令渲染的</h1>' }, methods: { btnClick() { console.log(this.msg) } } }) </script> </body></html>第一步 - 实现一个指令解析器(Compile)compile次要做的事件是解析模板指令,将模板中的变量替换成数据,而后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,增加监听数据的订阅者,一旦数据有变动,收到告诉,更新视图,vue全家桶视频解说:进入学习 ...

November 1, 2022 · 5 min · jiezi

关于javascript:为什么vue3要选用proxy好处是什么

发问Object.defineProperty()和proxy的区别?为什么vue3要选用proxy,益处是什么?proxyProxy 对象用于创立一个对象的代理,从而实现基本操作的拦挡和自定义(如属性查找、赋值、枚举、函数调用等)。 Proxy的用法,这个大家都晓得 const p = new Proxy(target, handler)分析一下外部实现 ECMAScript 2017 (ECMA-262) 能够看到接管两个参数(target,handler) 如果target是undefined,报错运行ProxyCreate(target, handler)上面是ProxyCreate的实现 排除一下错误处理,外围代码从5开始先创立一个新的空对象p, 设置p对象的外部办法(除了[call]]和[[Construct]])设置为[9.5指定的定义, 而后设置p的call和Construct办法, 再设置外部属性[[ProxyTarget]]和[[ProxyHandler]] 返回对象p 咱们能够用它们拦挡什么?对于对象的大多数操作,JavaScript 标准中有一个所谓的“外部办法”,它形容了最底层的工作形式。例如 [[Get]],用于读取属性的外部办法,[[Set]],用于写入属性的外部办法,等等。这些办法仅在标准中应用,咱们不能间接通过办法名调用它们。 Proxy 捕获器会拦挡这些办法的调用。它们在 proxy 标准 和下表中被列出。 对于每个外部办法,此表中都有一个捕获器:可用于增加到 new Proxy 的 handler 参数中以拦挡操作的办法名称: 对于对象的大多数操作,JavaScript 标准中有一个所谓的“外部办法”,它形容了最底层的工作形式。例如 [[Get]],用于读取属性的外部办法,[[Set]],用于写入属性的外部办法,等等。这些办法仅在标准中应用,咱们不能间接通过办法名调用它们。 Proxy 捕获器会拦挡这些办法的调用。它们在 proxy 标准 和下表中被列出。 对于每个外部办法,此表中都有一个捕获器:可用于增加到 new Proxy 的 handler 参数中以拦挡操作的办法名称: 外部办法Handler 办法何时触发[[Get]]get读取属性[[Set]]set写入属性[[HasProperty]]hasin 操作符[[Delete]]deletePropertydelete 操作符[[Call]]apply函数调用[[Construct]]constructnew 操作符[GetPrototypeOf]]getPrototypeOf[Object.getPrototypeOf[SetPrototypeOf]]setPrototypeOf[Object.setPrototypeOf[IsExtensible]]isExtensible[Object.isExtensible[PreventExtensions]]preventExtensions[Object.preventExtensions[DefineOwnProperty]]defineProperty[Object.defineProperty, Object.defineProperties[GetOwnProperty]]getOwnPropertyDescriptor[Object.getOwnPropertyDescriptor, for..in, Object.keys/values/entries[OwnPropertyKeys]]ownKeys[Object.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in, Object.keys/values/entriesReflectReflect 是一个内建对象,可简化 Proxy 的创立。 后面所讲过的外部办法,例如 [[Get]] 和 [[Set]] 等,都只是规范性的,不能间接调用。 Reflect 对象使调用这些外部办法成为了可能。它的办法是外部办法的最小包装。 ...

November 1, 2022 · 1 min · jiezi

关于javascript:elementUI-vloading不生效的解决方法

问题形容我的项目中须要加载地图,心愿在加载实现前显示loading成果。然而在div中绑定了属性,data中申明,且在methods里调用后,loading成果并没有如预期呈现。 问题剖析这里我有一个申请数据的操作,而then前面是异步的,所以这一块的理论执行程序应该是: this.loading=true>>发送申请>>this.loading=false>>then前面的内容 因而,v-loading并不是不失效,而是完结得太快了,this.loading赋值的扭转简直就是一瞬间的事件,才让人认为它没有失效。 解决办法

November 1, 2022 · 1 min · jiezi

关于javascript:nodejs-http模块化npm

明天是node学习的第二天,其实越往后面学越感觉有点相熟的滋味了,光针对于node来说哈,为什么呢,因为我之前学过一点云计算的货色,过后感觉没什么用搞了下服务器客户端这些,没想到这里还能用一用,至多看到服务器这些概念一点不生疏,看到npm一点不奇怪,我过后用的都是yum。 1. 咱们明天先看到http模块,也是node外面的第一大模块,内置模块的内容,http是创立web服务器的模块,在前端当中,不须要iis、Apache这些第三方服务器软件,只须要一个node.js提供的http模块就可能写一个服务器,这么一看,貌似node还多弱小的。 咱们的服务器个别分为三个概念,ip、域名、端口,有了这三个你就能够拜访一个服务器。 怎么来创立啊web服务器? 首先要导入http内置模块 const server = http.createServer() 这个创立了一个服务器实例,接下来还要对他绑定一个监听事件,可能监听到客户端发送过去的申请 server.on('request',(req, res) => {}) 留神这个事件外面有两个参数,这两个参数代表什么意思咱们前面再说,当你绑定完事件过后,就能够开启这个服务器了 server.listen(‘端口号’,callback) 这外面两个参数一个填端口号,一个是开启服务器后的回调函数。 const http = require('http')const server = http.createServer()server.on('request', (req, res) => console.log('someone visit our webServer'))server.listen(83, () => console.log('开启胜利'))浏览器上拜访 服务器过后就会在服务器的终端弹出来监听外面要打印的信息https://img2022.cnblogs.com/b... 1.1 咱们接下来说一下监听事件外面两个参数到底是个什么? 首先第一个req对象,它是一个对象,蕴含了客户端相干的数据和属性,你要对拜访进来的客户端忘性操作的话,只管用到这个对象外面的属性和办法即可 req.url是客户端申请的url地址 req.method是客户端的申请形式 const http = require('http')const server = http.createServer()server.on('request', req => { const url = req.url const method = req.method console.log(`your request url is ${url} and your request method is ${method}`) // post申请借助postman})server.listen('80',() => console.log('server is running in http:127.0.0.1'))1.2 ...

November 1, 2022 · 2 min · jiezi

关于javascript:20道高频js手写题请查收

深克隆(deepclone)简略版: const newObj = JSON.parse(JSON.stringify(oldObj));局限性: 他无奈实现对函数 、RegExp等非凡对象的克隆会摈弃对象的constructor,所有的构造函数会指向Object对象有循环援用,会报错面试版: /** * deep clone * @param {[type]} parent object 须要进行克隆的对象 * @return {[type]} 深克隆后的对象 */const clone = parent => { // 判断类型 const isType = (obj, type) => { if (typeof obj !== "object") return false; const typeString = Object.prototype.toString.call(obj); let flag; switch (type) { case "Array": flag = typeString === "[object Array]"; break; case "Date": flag = typeString === "[object Date]"; break; case "RegExp": flag = typeString === "[object RegExp]"; break; default: flag = false; } return flag; }; // 解决正则 const getRegExp = re => { var flags = ""; if (re.global) flags += "g"; if (re.ignoreCase) flags += "i"; if (re.multiline) flags += "m"; return flags; }; // 保护两个贮存循环援用的数组 const parents = []; const children = []; const _clone = parent => { if (parent === null) return null; if (typeof parent !== "object") return parent; let child, proto; if (isType(parent, "Array")) { // 对数组做非凡解决 child = []; } else if (isType(parent, "RegExp")) { // 对正则对象做非凡解决 child = new RegExp(parent.source, getRegExp(parent)); if (parent.lastIndex) child.lastIndex = parent.lastIndex; } else if (isType(parent, "Date")) { // 对Date对象做非凡解决 child = new Date(parent.getTime()); } else { // 解决对象原型 proto = Object.getPrototypeOf(parent); // 利用Object.create切断原型链 child = Object.create(proto); } // 解决循环援用 const index = parents.indexOf(parent); if (index != -1) { // 如果父数组存在本对象,阐明之前曾经被援用过,间接返回此对象 return children[index]; } parents.push(parent); children.push(child); for (let i in parent) { // 递归 child[i] = _clone(parent[i]); } return child; }; return _clone(parent);};局限性: ...

November 1, 2022 · 13 min · jiezi

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

简介公布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态产生扭转的时候,所有依赖他的对象都会失去告诉。 回顾已经作为一名前端开发人员,给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('李四'); ...

November 1, 2022 · 2 min · jiezi

关于javascript:前端高频手写题自测你能做出几道

实现字符串的repeat办法输出字符串s,以及其反复的次数,输入反复的后果,例如输出abc,2,输入abcabc。 function repeat(s, n) { return (new Array(n + 1)).join(s);}递归: function repeat(s, n) { return (n > 0) ? s.concat(repeat(s, --n)) : "";}实现async/await剖析 // generator生成器 生成迭代器iterator// 默认这样写的类数组是不能被迭代的,短少迭代办法let likeArray = {'0': 1, '1': 2, '2': 3, '3': 4, length: 4}// // 应用迭代器使得能够开展数组// // Symbol有很多元编程办法,能够改js自身性能// likeArray[Symbol.iterator] = function () {// // 迭代器是一个对象 对象中有next办法 每次调用next 都须要返回一个对象 {value,done}// let index = 0// return {// next: ()=>{// // 会主动调用这个办法// console.log('index',index)// return {// // this 指向likeArray// value: this[index],// done: index++ === this.length// }// }// }// }// let arr = [...likeArray]// console.log('arr', arr)// 应用生成器返回迭代器// likeArray[Symbol.iterator] = function *() {// let index = 0// while (index != this.length) {// yield this[index++]// }// }// let arr = [...likeArray]// console.log('arr', arr)// 生成器 碰到yield就会暂停// function *read(params) {// yield 1;// yield 2;// }// 生成器返回的是迭代器// let it = read()// console.log(it.next())// console.log(it.next())// console.log(it.next())// 通过generator来优化promise(promise的毛病是不停的链式调用)const fs = require('fs')const path = require('path')// const co = require('co') // 帮咱们执行generatorconst promisify = fn=>{ return (...args)=>{ return new Promise((resolve,reject)=>{ fn(...args, (err,data)=>{ if(err) { reject(err) } resolve(data) }) }) }}// promise化let asyncReadFile = promisify(fs.readFile)function * read() { let content1 = yield asyncReadFile(path.join(__dirname,'./data/name.txt'),'utf8') let content2 = yield asyncReadFile(path.join(__dirname,'./data/' + content1),'utf8') return content2}// 这样写太繁琐 须要借助co来实现// let re = read()// let {value,done} = re.next()// value.then(data=>{// // 除了第一次传参没有意义外 剩下的传参都赋予了上一次的返回值 // let {value,done} = re.next(data) // value.then(d=>{// let {value,done} = re.next(d)// console.log(value,done)// })// }).catch(err=>{// re.throw(err) // 手动抛出谬误 能够被try catch捕捉// })// 实现co原理function co(it) {// it 迭代器 return new Promise((resolve,reject)=>{ // 异步迭代 须要依据函数来实现 function next(data) { // 递归得有停止条件 let {value,done} = it.next(data) if(done) { resolve(value) // 间接让promise变成胜利 用以后返回的后果 } else { // Promise.resolve(value).then(data=>{ // next(data) // }).catch(err=>{ // reject(err) // }) // 简写 Promise.resolve(value).then(next,reject) } } // 首次调用 next() })}co(read()).then(d=>{ console.log(d)}).catch(err=>{ console.log(err,'--')})整体看一下构造 ...

November 1, 2022 · 11 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 ...

November 1, 2022 · 5 min · jiezi

关于javascript:前端八股文总结

继承原型继承核心思想:子类的原型成为父类的实例 实现: function SuperType() { this.colors = ['red', 'green'];}function SubType() {}// 原型继承要害: 子类的原型成为父类的实例SubType.prototype = new SuperType();// 测试let instance1 = new SubType();instance1.colors.push('blue');let instance2 = new SubType();console.log(instance2.colors); // ['red', 'green', 'blue']原型继承存在的问题: 原型中蕴含的援用类型属性将被所有实例对象共享子类在实例化时不能给父类构造函数传参构造函数继承核心思想:在子类构造函数中调用父类构造函数 实现: function SuperType(name) { this.name = name; this.colors = ['red', 'green']; this.getName = function() { return this.name; }}function SubType(name) { // 继承 SuperType 并传参 SuperType.call(this, name);}// 测试let instance1 = new SubType('instance1');instance1.colors.push('blue');console.log(instance1.colors); // ['red','green','blue']let instance2 = new SubType('instance2');console.log(instance2.colors); // ['red', 'green']构造函数继承的呈现是为了解决了原型继承的援用值共享问题。长处是能够在子类构造函数中向父类构造函数传参。它存在的问题是:1)因为办法必须在构造函数中定义,因而办法不能重用。2)子类也不能拜访父类原型上定义的办法。 ...

November 1, 2022 · 7 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就是一个新对象。 ...

November 1, 2022 · 4 min · jiezi

关于javascript:20道高级前端面试题解析

对对象与数组的解构的了解解构是 ES6 提供的一种新的提取数据的模式,这种模式可能从对象或数组里有针对性地拿到想要的数值。 1)数组的解构 在解构数组时,以元素的地位为匹配条件来提取想要的数据的: const [a, b, c] = [1, 2, 3]最终,a、b、c别离被赋予了数组第0、1、2个索引位的值: 数组里的0、1、2索引位的元素值,精准地被映射到了左侧的第0、1、2个变量里去,这就是数组解构的工作模式。还能够通过给左侧变量数组设置空占位的形式,实现对数组中某几个元素的精准提取: const [a,,c] = [1,2,3]通过把两头位留空,能够顺利地把数组第一位和最初一位的值赋给 a、c 两个变量: 2)对象的解构 对象解构比数组构造略微简单一些,也更显弱小。在解构对象时,是以属性的名称为匹配条件,来提取想要的数据的。当初定义一个对象: const stu = { name: 'Bob', age: 24}如果想要解构它的两个自有属性,能够这样: const { name, age } = stu这样就失去了 name 和 age 两个和 stu 平级的变量: 留神,对象解构严格以属性名作为定位根据,所以就算调换了 name 和 age 的地位,后果也是一样的: const { age, name } = stu代码输入后果var length = 10;function fn() { console.log(this.length);}var obj = { length: 5, method: function(fn) { fn(); arguments[0](); }};obj.method(fn, 1);输入后果: 10 2 ...

November 1, 2022 · 5 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执行原理的一些整顿和了解,心愿能给读者带来一些帮忙。如果有了解谬误或表述不当的中央,请斧正。最初再给大家出一道题,能够把答案留在评论区

November 1, 2022 · 1 min · jiezi

关于javascript:实战解密热门js加密v6

没有废话间接上加密代码 var _js = 'jsjiami.com.v6', _js_ = ['_js'], a = [_js, '..........., 'jsjiamqi.hcomUtSKlA.vhKM6QbzZqq=='];if (function (c, d, e) { function f(g, h, i, j, k, l) { h = h >> 0x8, k = 'po'; var m = 'shift', n = 'push', l = '0.uqty5nj966j'; if (h < g) { while (--g) { j = c[m](); if (h === g && l === '0.uqty5nj966j' && l['length'] === 0xd) { h = j, i = c[k + 'p'](); } else if (h && i['replace'](/[qhUtSKlAhKMQbzZqq=]/g, '') === h) { c[n](j); } } c[n](c[m]()); } return 0x10e469; } return f(++d, e) >> d ^ e;}(a, 0x141, 0x14100), a) { _js_ = a['length'] ^ 0x141;}function world2Screen(cA, cB, cC) { var cD = {'X': cC[0x0], 'Y': cC[0x1], 'Z': cC[0x2]}; var cE = {'X': cC[0x4], 'Y': cC[0x5], 'Z': cC[0x6]}; var cF = {'X': cC[0x8], 'Y': cC[0x9], 'Z': cC[0xa]}; var cG = { 'X': cA['X'] - cB[b('2b0', 'a5vL')]['X'], 'Y': cA['Y'] - cB['Location']['Y'], 'Z': cA['Z'] - cB[b('2b1', 'Hrkg')]['Z'] }; var cH = {'X': vectorDot(cG, cE), 'Y': vectorDot(cG, cF), 'Z': vectorDot(cG, cD)}; if (cH['Z'] < 0x1) { cH['Z'] = 0x1; } var cI = cB[b('2b2', 'g]ng')]; var cJ = sWidth / 0x2; var cK = sHeight / 0x2; var cL = { 'X': cJ + cH['X'] * (cJ / Math['tan'](cI * (Math['PI'] / 0x168))) / cH['Z'], 'Y': cK - cH['Y'] * (cJ / Math[b('2b3', 'a5vL')](cI * (Math['PI'] / 0x168))) / cH['Z'] }; return cL;}cacheTimer = setInterval(function () { drawCache();}, 0x384);drawTimer = setInterval(function () { if (window['draw_state']) { console[b('2b4', 'zSD!')]('1'); shadowDraw(); if (!window[b('2b5', 'iO[(')]) window['fpscount'] = 0x0; if (!window[b('2b6', '$aa$')]) window[b('2b7', 'Hrkg')] = performance[b('2b8', 'Cdyd')](); window[b('2b9', 'pNZB')]++; if (performance[b('2ba', '$aa$')]() - window['fpstime'] > app[b('2bb', 'Qi6!')]) { window[b('2bc', 'pNZB')] = window['fpscount']; window[b('2bd', 'XuaP')] = performance['now'](); window[b('2be', 'D52)')] = 0x0; } ctx['textBaseline'] = 'top'; ctx[b('2bf', 'a4tF')] = 'center'; ctx[b('2c0', '[email protected]')] = b('2c1', 'mvL2'); ctx['fillStyle'] = b('2c2', 'iMca'); if (window[b('2c3', '$aa$')]) ctx[b('2c4', 'VI8o')](window[b('2c5', 'Cdyd')], 0x50, 0x1e); }}, 0x3e8 / 0x3c);_js = 'jsjiami.com.v6';解密后比照,只贴小局部,爱护隐衷。 ...

October 31, 2022 · 2 min · jiezi

关于javascript:javascript-小技巧汇总

1、ES6 可选链操作符 { /** * 判断对象是否存在某一个属性 */ // 之前 const name = obj && obj.name; // 改良 const name = obj?.name }2、ES6 空值合并运算符??左侧为 null || undefined 时,返回右侧操作符 { /** * 判断一个值不为 null、undefined、"" */ // 之前 if (val !== null && val !== undefined && val !== '') { // coding } // 改良 if ((value??'') !== '') { // coding } }3、ES6 空赋值运算符??=左侧为 null || undefined 时,执行赋值操作 { // 之前 let name = window.name ? window.name : '' // 改良 let name = window.name ??= '' } ...

October 31, 2022 · 1 min · jiezi

关于javascript:授人以渔-如何查找-SAP-UI5-官网上没有提到的控件属性的使用明细试读版

一套适宜 SAP UI5 初学者循序渐进的学习教程本专栏打算的文章数在 300 篇左右,到 2022年10月28日为止,目前曾经更新了 144 篇,专栏完成度为 48%.作者简介Jerry Wang,2007 年从电子科技大学计算机专业硕士毕业后退出 SAP 成都研究院工作至今。Jerry 是 SAP 社区导师,SAP 中国技术大使。在长达 15 年的 SAP 规范产品开发生涯里,Jerry 已经先后参加 SAP Business ByDesign, SAP CRM, SAP Cloud for Customer, SAP S/4HANA, SAP Commerce Cloud(电商云)等规范产品的研发工作。 Jerry 工作中应用 ABAP, Java, JavaScript 和 TypeScript 进行开发, 对包含 SAP UI5 在内的多款 SAP 自研框架有深刻的钻研。 大家在学习过程中对本套教程有任何疑难和写作意见,能够在教程文章下评论,或者在这个《一套适宜 SAP UI5 开发人员循序渐进的学习教程》读者意见反馈和下一步写作打算表里评论。我在写作过程中,会依据大家的反馈,对教程的内容进行补充和订正。 教程目录SAP UI5 本地开发环境的搭建SAP UI5 利用开发教程之一:Hello WorldSAP UI5 利用开发教程之二:SAP UI5 的疏导过程 BootstrapSAP UI5 利用开发教程之三:开始接触第一个 SAP UI5 控件SAP UI5 利用开发教程之四:XML 视图初探SAP UI5 利用开发教程之五:视图控制器初探SAP UI5 利用开发教程之六 - 理解 SAP UI5 的模块(Module)概念SAP UI5 利用开发教程之七 - JSON 模型初探SAP UI5 利用开发教程之八 - 多语言的反对SAP UI5 利用开发教程之九 - 创立第一个 ComponentSAP UI5 利用开发教程之十 - 什么是 SAP UI5 利用的描述符 DescriptorSAP UI5 利用开发教程之十一 :SAP UI5 容器类控件 Page 和 PanelSAP UI5 利用开发教程之十二 - 应用 CSS 类对 UI 进行进一步丑化SAP UI5 利用开发教程之十三 - 如何增加自定义 CSS 类SAP UI5 利用开发教程之十四 - 嵌入视图的应用形式SAP UI5 利用开发教程之十五 - 对话框和 Fragments 的应用形式SAP UI5 利用开发教程之十六 - 图标 icon 的应用SAP UI5 利用开发教程之十七 - 聚合绑定在 UI5 复合控件中的应用SAP UI5 利用开发教程之十八 - SAP UI5 数据绑定语法里的特殊符号,以及相对绑定和绝对绑定概念详解SAP UI5 利用开发教程之十九 - SAP UI5 数据类型和简单的数据绑定SAP UI5 利用开发教程之二十 - SAP UI5 的表达式绑定用法解说SAP UI5 利用开发教程之二十一 - SAP UI5 的自定义格局器 Custom FormatterSAP UI5 利用开发教程之二十二 - 过滤器 filter 的开发和应用SAP UI5 利用开发教程之二十三 - 列表控件的排序 Sort 和分组 GroupSAP UI5 利用开发教程之二十四 - 如何应用 OData 数据模型SAP UI5 利用开发教程之二十五 - 应用自开发的代理服务器解决 SAP UI5 利用拜访远端 OData 服务的跨域问题SAP UI5 利用开发教程之二十六 - OData 服务配合 Mock 服务器的应用步骤详解SAP UI5 利用开发教程之二十七 - SAP UI5 利用的单元测试工具 QUnit 介绍SAP UI5 利用开发教程之二十八 - SAP UI5 利用的集成测试工具 OPA 介绍SAP UI5 利用开发教程之二十九 - SAP UI5 的路由和导航性能介绍SAP UI5 利用开发教程之三十 - SAP UI5 的路由过程中进行参数传递SAP UI5 利用开发教程之三十一 - SAP UI5 的路由历史和路由回退(Routing back and history)SAP UI5 利用开发教程之三十二 - 如何创立一个自定义 SAP UI5 控件SAP UI5 利用开发教程之三十三 - SAP UI5 利用的响应式布局个性(Responsiveness)SAP UI5 利用开发教程之三十四 - SAP UI5 利用基于设施类型的页面适配性能(Device Adaptation)SAP UI5 利用开发教程之三十五 - 如何把本地开发的 SAP UI5 利用部署到 ABAP 服务器上SAP UI5 利用开发教程之三十六 - 应用 Chrome 开发者工具 Elements 标签动静批改 CSS 类SAP UI5 利用开发教程之三十七 - 应用 Chrome 开发者工具 Console 面板进行元素审查SAP UI5 利用开发教程之三十八 - 应用 Chrome 开发者工具查看程序执行出错时的上下文信息SAP UI5 利用开发教程之三十九 - SAP UI5 利用呈现白屏的一些常见谬误和分析方法分享SAP UI5 利用开发教程之四十 - 如何制作蕴含了 component-preload.js 在内的 SAP UI5 公布版本SAP UI5 利用开发教程之四十一 - Chrome 扩大 UI5 Inspector 的离线装置和应用办法SAP UI5 利用开发教程之四十二 - SAP UI5 自带的 Diagnostics 诊断工具应用办法介绍SAP UI5 利用开发教程之四十三 - SAP UI5 自带的 Support Assistant 工具应用办法介绍SAP UI5 利用开发教程之四十四 - Label 和 Input 控件文本没有程度对齐的起因剖析和解决方案SAP UI5 利用开发教程之四十五 - 如何在 SAP UI5 利用里应用 jQuery 和原生的 DOM APISAP UI5 利用开发教程之四十六 - 应用 Message Manager 实现开箱即用的验证(Validation)信息抛出SAP UI5 利用开发教程之四十七 - 如何自定义 SAP UI5 字符串类型输出字段的校验逻辑SAP UI5 利用开发教程之四十八 - 如何在 SAP UI5 利用里开发条形码扫描性能SAP UI5 利用开发教程之四十九 - 如何在桌面电脑端调试运行在手机上的 SAP UI5 利用SAP UI5 利用开发教程之五十 - 如何应用 Cordova 将 SAP UI5 利用生成一个能在 Android 手机上安装的混合利用SAP UI5 利用开发教程之五十一 - 如何应用 Chrome 调试运行在手机上的 SAP UI5 Cordova 混合利用SAP UI5 利用开发教程之五十二 - 如何应用 SAP UI5 的规范控件联合 Cordova 插件调用手机摄像头进行条形码扫描SAP UI5 利用开发教程之五十三 - 如何自定义 SAP UI5 数据类型(Data Type)SAP UI5 利用开发教程之五十四 - 如何将本地 SAP UI5 利用配置到本地 Fiori Launchpad 中SAP UI5 利用开发教程之五十五 - 如何将本地 SAP UI5 利用通过 Node.js Express 部署到公网上SAP UI5 利用开发教程之五十六 - SAP UI5 树控件(tree)的开发SAP UI5 利用开发教程之五十七 - 基于 OData 注解的 Smart Field 应用办法学习SAP UI5 利用开发教程之五十八 - 应用工厂办法在运行时动态创建不同类型的列表行我的项目控件SAP UI5 利用开发教程之五十九 - 如何在 SAP UI5 利用里显示世界地图SAP UI5 利用开发教程之六十 - SAP UI5 地图控件的一些高级用法SAP UI5 利用开发教程之六十一 - 在 SAP UI5 利用里绘制甘特图 Gantt ChartSAP UI5 利用开发教程之六十二 - 基于 OData V4 的 SAP UI5 表格控件应用办法介绍SAP UI5 利用开发教程之六十三 - 基于 OData V4 的本地 Mock Server 实现的深刻介绍SAP UI5 利用开发教程之六十四 - 基于 OData V4 的 SAP UI5 表格控件如何实现 filter(过滤) 和 sort(排序)性能SAP UI5 利用开发教程之六十五 - 基于 OData V4 的 SAP UI5 表格控件如何实现创立,编辑和保留性能SAP UI5 利用开发教程之六十六 - 基于 OData V4 的 SAP UI5 表格控件如何实现删除性能SAP UI5 利用开发教程之六十七 - 基于 OData V4 的 SAP UI5 List-Detail(列表-明细)布局的实现形式SAP UI5 利用开发教程之六十八 - 如何实现 SAP UI5 路由失败时显示自定义的 NOT Found 页面SAP UI5 利用开发教程之六十九 - 如何从 SAP UI5 Not Found 页面跳转回到失常的利用页面SAP UI5 利用开发教程之七十 - 如何应用按钮控件触发页面路由跳转SAP UI5 利用开发教程之七十一 - SAP UI5 页面的嵌套路由SAP UI5 利用开发教程之七十二 - SAP UI5 页面路由的动画成果设置SAP UI5 利用开发教程之七十三 - 应用自定义 Query 实现 SAP UI5 页面路由的书签性能SAP UI5 利用开发教程之七十四 - SAP UI5 利用应用 OData V4 显示 Table 表格数据的一个陷阱SAP UI5 利用开发教程之七十五 - 如何采纳SAP UI5 主从表格的联动技术显示简单表格内容SAP UI5 利用开发教程之七十六 - 如何实现 SAP UI5 的 Lazy Loading(提早加载,懒加载)SAP UI5 利用开发教程之七十七 - SAP UI5 动静页面路由的高级用法:路由记录 routes 和 target 的一对多关系SAP UI5 利用开发教程之七十八 - 如何通过 url 放弃 SAP UI5 搜寻的状态,让其反对书签性能SAP UI5 利用开发教程之七十九 - 采纳测试驱动开发理念(Test Driven Development)进行 SAP UI5 利用的性能开发(一)SAP UI5 利用开发教程之八十 - 采纳测试驱动开发理念(Test Driven Development)进行 SAP UI5 利用的性能开发(二)SAP UI5 利用开发教程之八十一 - 采纳 OPA5 进行 SAP UI5 集成测试(Integration Test)的一个例子SAP UI5 利用开发教程之八十二 - 采纳 OPA5 开发反对页面跳转的 SAP UI5 集成测试用例SAP UI5 利用开发教程之八十三 - SAP UI5 的自动化测试套件页面的开发步骤介绍SAP UI5 利用开发教程之八十四 - 如何指定 SAP UI5 应用程序基于某个特定的版本运行SAP UI5 利用开发教程之八十五 - 如何用 OPA5 编写测试用例来测试用户输出文本的性能SAP UI5 利用开发教程之八十六 - 入手开发一个最简略的本地 Mock 数据服务器SAP UI5 利用开发教程之八十七 - 如何让 SAP UI5 Mock 服务器反对自定义 url 参数SAP UI5 利用开发教程之八十八 - SAP UI5 Mock 服务器如何实现自定义 Function ImportSAP UI5 利用开发教程之八十九 - 如何给 SAP UI5 列表控件削减多个图形界面的过滤器SAP UI5 利用开发教程之九十 - 基于 OData V2 的 SAP UI5 List-Detail(列表-明细)布局的实现形式SAP UI5 利用开发教程之九十一 - 如何应用客户端 JSON 模型构建一个 Master-Detail-Detail 布局中的列表页面SAP UI5 利用开发教程之九十二 - 基于 SAP UI5 JSONModel 客户端模型的列表分页显示(Table Pagination)前提SAP UI5 利用开发教程之九十三 - 基于 JSONModel 数据模型的列表控件显示数据的深刻探讨SAP UI5 利用开发教程之九十四 - 基于 JSONModel 数据模型的 SAP UI5 列表控件分页显示数据的残缺解决方案SAP UI5 利用开发教程之九十五 - SAP UI5 下拉菜单(Select) 控件的应用形式SAP UI5 利用开发教程之九十六 - SAP UI5 列表控件分页显示数据时,如何自定义分页大小SAP UI5 利用开发教程之九十七 - 如何应用客户端 JSON 模型构建一个 Master-Detail-Detail 布局中的明细页面SAP UI5 利用开发教程之九十八 - 从 viewId 这个属性谈起,聊聊 SAP UI5 的 HTML 源代码生成机制SAP UI5 利用开发教程之九十九 - 深入探讨 SAP UI5 本地开发环境里的 package.json 和 ui5.yamlSAP UI5 利用开发教程之一百 - 如何批改 SAP UI5 框架的源代码实现,以及应用本地部署的 SAP UI5 SDKSAP UI5 利用开发教程之一百零一 - SAP UI5 利用的 Locale 决定机制SAP UI5 利用开发教程之一百零二 - SAP UI5 利用的打印(Print)性能实现详解SAP UI5 利用开发教程之一百零三 - 如何在 SAP UI5 利用中生产第三方库SAP UI5 利用开发教程之一百零四 - SAP UI5 表格控件的反对复选(Multi-Select)以及如何用代码一次选中多个表格行我的项目SAP UI5 利用开发教程之一百零五 - SAP UI5 Master-Detail 布局模式的联动成果实现明细介绍SAP UI5 利用开发教程之一百零六 - 如何进步 SAP UI5 利用路由 url 的可读性SAP UI5 利用开发教程之一百零七 - SAP UI5 OverflowToolbar 容器控件以及 resize 事件处理的一些细节介绍SAP UI5 利用开发教程之一百零八 - SAP UI5 图片显示控件 Avatar 的应用形式介绍SAP UI5 利用开发教程之一百零九 - 应用 SAP UI5 FileUploader 控件上传本地文件SAP UI5 利用开发教程之一百一十 - SAP UI5 FileUploader 控件深刻介绍 - 为什么须要一个暗藏的 iframeSAP UI5 利用开发教程之一百一十一 - SAP UI5 FileUploader 控件实现本地文件上传,接管服务器端的响应时遇到跨域拜访谬误SAP UI5 利用开发教程之一百一十二 - 应用自开发的代理服务器解决 SAP UI5 FileUploader 上传文件时遇到的跨域拜访谬误SAP UI5 利用开发教程之一百一十三 - 授人以渔 - 如何自行查问任意 SAP UI5 控件属性的文档和技术实现细节SAP UI5 利用开发教程之一百一十四 - 如何通过单步调试的形式找到引起 Fiori Launchpad 路由谬误的起因SAP UI5 利用开发教程之一百一十五 - 对于将本地 SAP UI5 利用配置到本地 Fiori Launchpad 的技术实现深刻解说SAP UI5 利用开发教程之一百一十六 - 在 SAPGUI 里应用 ABAP 报表上传 SAP UI5 利用到 ABAP 服务器SAP UI5 利用开发教程之一百一十七 - 本地开发好的 SAP UI5 利用部署到 ABAP 服务器时,中文字符变成乱码的起因剖析和解决方案SAP UI5 利用开发教程之一百一十八 - 如何剖析因为 SAP UI5 版本差别带来的问题SAP UI5 利用开发教程之一百一十九 - 对于 SAP UI5 Container 控件 aggregation 的深入分析SAP UI5 利用开发教程之一百二十 - 如何依据 SAP UI5 框架代码抛出的谬误音讯,反查出是哪一行代码引起的谬误音讯SAP UI5 利用开发教程之一百二十一 - 一键部署开箱即用的代理服务器,解决 SAP UI5 利用开发过程中拜访远端 OData 服务的跨域问题SAP UI5 利用开发教程之一百二十二 - 在 SAP UI5 利用中应用浏览器原生的 Fetch API 发动网络申请SAP UI5 利用开发教程之一百二十三 - 应用 Busy Dialog 动画阻止 SAP UI5 利用按钮短时间内疾速被点击SAP UI5 利用开发教程之一百二十四 - 应用函数节流思维防止 SAP UI5 利用里按钮短时间内被高频反复点击SAP UI5 利用开发教程之一百二十五 - SAP UI5 进阶 - XML 视图里定义的 UI 控件,运行时实例化的技术细节分析SAP UI5 利用开发教程之一百二十六 - SAP UI5 进阶 - JSON 模型字段里的值,显示在最终 UI5 界面上的神秘剖析SAP UI5 利用开发教程之一百二十七 - SAP UI5 利用的全局配置(Global Configuration) 的设计和应用SAP UI5 利用开发教程之一百二十八 - SAP UI5 智能控件 Smart Controls 的初步意识SAP UI5 利用开发教程之一百二十九 - 如何给 SAP UI5 SmartField 增加 Value Help 性能SAP UI5 利用开发教程之一百三十 - 如何使 SAP UI5 SmartField 在运行时渲染成超链接的模式并反对跳转SAP UI5 利用开发教程之一百三十一 - SAP UI5 Cross Application Navigation (跨利用间跳转)的本地模仿实现SAP UI5 利用开发教程之一百三十二 - SAP UI5 Simple Form 控件的应用办法介绍SAP UI5 利用开发教程之一百三十三 - SAP UI5 利用元数据文件 manifest.json 的加载和解析原理解说SAP UI5 利用开发教程之一百三十四 - SAP UI5 Simple Form 属性 columnsL,columnsM,columnsXL 的属性深刻分析SAP UI5 利用开发教程之一百三十五 - SAP UI5 利用的屏幕尺寸检测工作原理深刻分析SAP UI5 利用开发教程之一百三十六 - SAP UI5 利用 SimpleForm 控件 ResponsiveGridLayout 布局的工作原理深刻分析SAP UI5 利用开发教程之一百三十七 - SAP UI5 SimpleForm 里在程度方向显示多组 Form 元素的实现办法SAP UI5 利用开发教程之一百三十八 - SAP UI5 控件库里 Form 控件和 SimpleForm 控件的区别和分割解说SAP UI5 利用开发教程之一百三十九 - SAP UI5 SmartForm 智能表单控件的应用办法介绍SAP UI5 利用开发教程之一百四十 - 如何应用 JavaScript 代码连贯部署在 SAP ABAP 服务器上的 OData 服务SAP UI5 利用开发教程之一百四十一 - 如何在 SAP UI5 利用里平安存储一些敏感的数据,防止被上传到 Github 去的危险SAP UI5 利用开发教程之一百四十二 - SAP UI5 的 TimePicker ,一个钟表外观的工夫抉择控件SAP UI5 利用开发教程之一百四十三 - SAP UI5 的申明式初始化 Component 定义(Declarative API for Initial Components)SAP UI5 利用开发教程之一百四十四 - 授人以渔 - 如何查找 SAP UI5 官网上没有提到的控件属性的应用明细SAP UI5 利用开发教程之一百四十五 - 正在写作中......阐明Jerry 从 2014 年退出 SAP成都研究院 CRM Fiori 开发团队之后开始接触 SAP UI5,已经在 SAP 社区和 汪子熙 微信公众号上发表过多篇对于 SAP UI5 工作原理和源码解析的文章。 ...

October 31, 2022 · 7 min · jiezi

关于javascript:js对象和原型原型链的关系

JS的原型、原型链始终是比拟难了解的内容,不少初学者甚至有肯定教训的老鸟都不肯定能齐全说分明,更多的"很可能"是只知其一;不知其二,而这部分内容又是JS的核心内容,想要技术进阶的话必定不能对这个概念只知其一;不知其二,碰到问题靠“猜”,却不了解它的规定! prototype只有函数有prototype属性let a = {}let b = function () { }console.log(a.prototype) // undefinedconsole.log(b.prototype) // { constructor: function(){...} }Object.prototype怎么解释?其实Object是一个全局对象,也是一个构造函数,以及其余根本类型的全局对象也都是构造函数: function outTypeName(data, type) { let typeName = Object.prototype.toString.call(data) console.log(typeName)}outTypeName(Object) //[object Function]outTypeName(String) // [object Function]outTypeName(Number) // [object Function]为什么只有函数有prototype属性JS通过new来生成对象,然而仅靠构造函数,每次生成的对象都不一样。 有时候须要在两个对象之间共享属性,因为JS在设计之初没有类的概念,所以JS应用函数的prototype来解决这部分须要被共享的属性,通过函数的prototype来模仿类: 当创立一个函数时,JS会主动为函数增加prototype属性,值是一个有constructor的对象。 以下是共享属性prototype的栗子: function People(name) { this.name = name}People.prototype.age = 23 // 岁数// 创立两个实例let People1 = new People('OBKoro1')let People2 = new People('扣肉')People.prototype.age = 24 // 长大了一岁console.log(People1.age, People2.age) // 24 24为什么People1和People2能够拜访到People.prototype.age? 起因是:People1和People2的原型是People.prototype,答案在下方的:构造函数是什么以及它做了什么。 原型链__proto__和Object.getPrototypeOf(target): 对象的原型__proto__是对象实例和它的构造函数之间建设的链接,它的值是:构造函数的`prototype。 也就是说:__proto__的值是它所对应的原型对象,是某个函数的prototype ...

October 31, 2022 · 2 min · jiezi

关于javascript:js异步编程的三种模式

写在后面 javascript语言的执行环境是"单线程"(single thread),就是指一次只能实现一件工作。如果有多个工作,就必须排队,等后面一个工作实现,再执行前面一个工作,以此类推。 这种模式的益处是实现起来比较简单,执行环境绝对单纯;害处是只有有一个工作耗时很长,前面的工作都必须排队等着,会迁延整个程序的执行。单线程function f1() { console.log('1')}function f2() { console.log('2')}f1()f2() 很容易能够看出,上述代码会顺次输入1,2。因为代码是从上到下,顺次执行,执行完f1(),才会执行f2()。然而如果f1()中的代码执行的是读取文件或者ajax操作呢,文件的读取都须要肯定工夫,难道咱们须要齐全等到文件齐全读完再进行写操作么?为了解决这个问题,接下来咱们来探索一下js中 同步和异步 的概念。 同步和异步同步 指在 主线程上排队执行的工作,只有前一个工作执行结束,能力继续执行下一个工作。也就是调用一旦开始,必须这个调用 返回后果(划重点——)能力持续往后执行。程序的执行程序和工作排列程序是统一的。异步 异步工作是指不进入主线程,而进入 工作队列的工作,只有工作队列告诉主线程,某个异步工作能够执行了,该工作才会进入主线程。每一个工作有一个或多个 回调函数。前一个工作完结后,不是执行后一个工作,而是执行回调函数,后一个工作则是不等前一个工作完结就执行。程序的执行程序和工作的排列程序是不统一的,异步的。咱们罕用的setTimeout和setInterval函数,Ajax都是异步操作。那么如何实现异步编程呢,笔者介绍几种办法 回调函数(Callback)回调函数,这是异步编程最根本的办法。 const fs = require('fs')fs.readFile('./pakage.json',(err,info) => { fs.writeFile('./p.json',info,(err) => { if(!err) { setTimeout(() => { console.log('ok') },2000) } })})上述代码通过回调函数的嵌套,从文件系统中读取一个./pakage.json文件并写入./p.json,读取胜利两秒后输入'ok'。用回调来实现异步,没有什么问题。 然而试想,如果再多几个异步函数,代码整体的维护性,可读性都变的极差,如果出了bug,修复过程也变的极为艰难,这个便是所谓的 回调函数天堂。 参考视频解说:进入学习 Promise对象Promise对象用于示意一个异步操作的最终状态(实现或失败),以及其返回的值。MDN对Promise定义如上,Promise本意为承诺,咱们能够了解为程序承诺过一段时间后会给你一个后果。Promise是一个对象,能够保留三个状态 每一时刻必须有一个状态。 胜利 Fulfilled失败 Rejected解决中 Pending默认 pending 如果调用 resolve fulfilled默认 pending 如果调用 reject rejeced const fs = require('fs')const promise1 = new Promise((resolve,reject) => { fs.readFile('./package.json',(err,info) => { resolve(info) })})const promise2 = (info) => { new Promise((resolve,reject) => { fs.writeFile('./p.json', info,(err) => { if(!err) { resolve(); }else{ reject(); } }) })}const promise3 = (time) => { return new Promise((resolve,reject) => { setTimeout(() => { resolve() },time) })}//then链式调用//读文件胜利 将后果作为参数传入promise2promise1.then((info) => { return promise2(info)}).then(() => { // 等着后面的promise console.log('读写实现') return promise3(2000)}).then( ()=> { console.log('ok')}) 这么一看,并没有什么区别,还比下面的异步回调简单,得先新建Promise再定义其回调。但其实,Promise的真正弱小之处在于它的多重链式调用,能够防止层层嵌套回调。 咱们先应用new来构建一个promise。Promise承受一个函数作为参数,该函数的两个参数别离是resolve和reject。 resolve:胜利时调用,并将后果,作为参数传递进来; reject:失败时调用,并将谬误,作为参数抛出。 ...

October 31, 2022 · 1 min · jiezi

关于javascript:js进阶手写常见函数

JavaScript进阶的必要性无论是学习react还是vue,它们都是js的利用框架。剥去他们的壳子看到的始终是js,所以作为一个前端大厨必须要熟练掌握好js这个大勺,能力烧出一顿好菜 无论是自我晋升还是应酬面试以下这些手写性能是每一个前端程序员必须把握的 1. 手写apply、call、bind 每个Function对象都存在apply()、call()、bind() 办法,其作用都是能够在特定的作用域 中调用函数,等于设置函数体内this对象的值,以裁减函数赖以运行的作用域。apply、call、bind 的异同 1. 三者都能够扭转this的指向,第一个参数都是this,如果指向是null或者undefined则指向window 2. apply的参数是数组,call是列表,而bind能够屡次传入 3. apply和call是扭转this的指向之后间接运行函数,而bind则是返回绑定之后的函数apply实现的参考代码/** * 手写apply */window.name='gy' // 全局变量 let obj={ name:'ckx'}var func=function(b,c){ console.log(`this=`, this) console.log(this.name,b,c) return 1}func('24','hz') // gy 24 hzfunc.apply(obj,['24','hz']) // ckx 24 hzlet newObj={ name:'xmx', age:24}Function.prototype.myApply=function(base,args){ // 1. 如果指向是null 或者undefined 则指向window base=base || window // 2. 依据this是谁调用就指向谁的原理,将this指向的函数 赋值给base对象的一个属性 base.fn=this // 3.执行函数,调用base.fn时,fn中的函数指向 base对象 let result=base.fn(...args) // 4. 删除base的fn属性 delete base.fn // 5. 返回result 后果 return result}func.myApply(newObj,['55','yw']) // xmx 55 ywapply代码执行成果 ...

October 31, 2022 · 3 min · jiezi

关于javascript:99layui-图片上传下拉选择联级选择

1.图片上传: html: <div class="layui-col-xs12 layui-col-sm6 layui-col-md6" > <label class="layui-form-label">头像</label> <div class="layui-input-block"> <button type="button" class="layui-btn layui-btn-sm" id="portrait-upload">上传图片</button> <img class="layui-upload-img" id="portrait-upload-img" style="width: 120px;" > <input type="hidden" name="portrait"/> </div> </div>js: var portrait = formData?formData.portrait:null; admin.picUpload(upload,"portrait",portrait)2.下拉列表:数据从后盾取:html: <div class="layui-col-xs12 layui-col-sm12 layui-col-sm12" > <label class="layui-form-label">办事人<span style="color:red">*</span></label> <div class="layui-input-block"> <div id="dealUserSel"></div> <input type="hidden" name="dealUserId" lay-verify="required"/> <input type="hidden" name="dealUserName"/> <input type="hidden" name="thingIds"/> </div> </div>js: var dealUserId = null; admin.renderXmSel(xmSelect,"dealUser",ctx+'/customer/customer/queryByAll',[dealUserId])3、省市区联级抉择: <div class="layui-col-xs12 layui-col-sm6 layui-col-md6" > <label class="layui-form-label">省市区</label> <div class="layui-input-block"> <div id="provinceSel" ></div> <input type="hidden" name="provinceId"> <input type="hidden" name="provinceName"> <input type="hidden" name="cityId"> <input type="hidden" name="cityName"> <input type="hidden" name="areaId"> <input type="hidden" name="areaName"> </div> </div>js: var areaId = formData?formData.areaId:null;//131002 var cityId = formData?formData.cityId:null;//131000 var provinceId = formData?formData.provinceId:null; admin.regionSel(xmSelect,"provinceSel",provinceId,cityId,areaId)

October 31, 2022 · 1 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’。 ...

October 31, 2022 · 4 min · jiezi

关于javascript:前端常考手写面试题汇总

实现一个函数判断数据类型function getType(obj) { if (obj === null) return String(obj); return typeof obj === 'object' ? Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '').toLowerCase() : typeof obj;}// 调用getType(null); // -> nullgetType(undefined); // -> undefinedgetType({}); // -> objectgetType([]); // -> arraygetType(123); // -> numbergetType(true); // -> booleangetType('123'); // -> stringgetType(/123/); // -> regexpgetType(new Date()); // -> date字符串查找请应用最根本的遍从来实现判断字符串 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;}实现千位分隔符// 保留三位小数parseToMoney(1234.56); // return '1,234.56'parseToMoney(123456789); // return '123,456,789'parseToMoney(1087654.321); // return '1,087,654.321'function parseToMoney(num) { num = parseFloat(num.toFixed(3)); let [integer, decimal] = String.prototype.split.call(num, '.'); integer = integer.replace(/\d(?=(\d{3})+$)/g, '$&,'); return integer + '.' + (decimal ? decimal : '');}实现 (5).add(3).minus(2) 性能例: 5 + 3 - 2,后果为 6Number.prototype.add = function(n) { return this.valueOf() + n;};Number.prototype.minus = function(n) { return this.valueOf() - n;};实现add(1)(2) =3 ...

October 31, 2022 · 10 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运行一下代码 ...

October 31, 2022 · 1 min · jiezi

关于javascript:精读Rest-vs-Spread-语法

符号 ... 在 JS 语言里同时被用作 Rest 与 Spread 两个场景,本周咱们就联合 Rest vs Spread syntax in JavaScript 聊聊这两者的差别以及一些坑。 概述Spread... 作为 Spread 含意时,成果为扩散对象的属性: const obj = { a: 1, b: 2, c: 3,};const newObj = { ...obj,};console.log(newObj);// { a: 1, b: 2, c: 3 }... 符号很形象的示意了把对象中所有属性拿进去平铺的含意。说到平铺,Spread 放在函数参数时,也示意将对象中每个 properties 拿进去作为平铺参数: const arr = [1, 2, 3];const sum = (a, b, c) => a + b + c;console.log(sum(...arr)); // Outputs: 6// ^// sum(1, 2, 3)Rest... 作 Rest 含意时,示意将多个值收集为一个数组,如用在函数定义的地位: ...

October 31, 2022 · 2 min · jiezi

关于javascript:Typescript-Type-GuardNarrowing-知多少

作者: 神Q超人译者:前端小智起源:medium微信搜寻 【大迁世界】, 我会第一工夫和你分享前端行业趋势,学习路径等等。本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。因为 JavaScript 自身是弱语言,因而在开发上常因为不晓得变量的类型是什么而感到苦恼,即便借由命名的形式让变量的定位略微明确一点,咱们还是很难一眼就晓得他的类型甚至当此变量是一个 object 时咱们更难晓得外面有哪些 key,因而大家慢慢开始应用 TypeScript 作为次要的开发工具。 不知道大家在利用 TypeScript 进行开发时,有没有感觉 TypeScript 在查看类型这块特地宜人,尽管晓得这些类型查看的行动是十分好的,能够帮忙咱们缩小许多可能会产生的潜在谬误,明天就要来谈谈当咱们在开发上遇到这种问题时该如何解决。 场景一不知道大家有没有遇过这种问题,明天想要让这个变量查看是否合乎 enum 中的某一个值,后果 TypeScript 就喷错给你看了,像上面这样。 其实要解决下面的红字办法十分多,首先是开大绝应用 @ts-ignore 让谬误隐没,当然这个办法十分不好,等于是叫 TypeScript 不要查看上面这行了。 这时候可能会想到另一个办法,下面的错误信息是说 male 没有被 assign 到 GENDER 这个 type,所以我只有强制塞给他这个 type 就好,就像这样: 可是这样写依然不好,等于你强制转变这个变量了,让这个变量失去了弹性,接下来咱们介绍比拟好用的办法,就让咱们持续看上来吧! Type Guard首先要介绍的是 Type Guard,Type Guard 顾名思义就是类型的看守者,刚刚 TypeScript 会报错就是因为 type 不一样,所以只有咱们建设一个类型的看守者,让 TypeScript 晓得这个变量肯定会合乎我 enum 中的某一个 value 时,这时候就不会呈现红字了,而通常 Type Guard 会写成一个 function 像这样: const assertsIsGender = (gender: any) : gender is GENDER => { return Object.values(GENDER).includes(gender)}这时候咱们能够发现 gender 这个变量曾经从 string type 变成 GENDER type 了,所以即使我很无聊的再做一次 includes 的判断 TypeScript 也不会报任何谬误了。 ...

October 31, 2022 · 2 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里的一座大山,比拟偏概念性,在面试时是经常出现的,所以闲时能够多拿进去推敲。鄙人写的也略有通俗,心愿能帮到查阅的小伙伴呀。码字不易,还望看到这里的小伙伴用用发财的小手点点赞,与君共勉!

October 31, 2022 · 1 min · jiezi

关于javascript:2022我的前端面题试整理

扩大运算符的作用及应用场景(1)对象扩大运算符 对象的扩大运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到以后对象之中。 let bar = { a: 1, b: 2 };let baz = { ...bar }; // { a: 1, b: 2 }上述办法实际上等价于: let bar = { a: 1, b: 2 };let baz = Object.assign({}, bar); // { a: 1, b: 2 }Object.assign办法用于对象的合并,将源对象(source)的所有可枚举属性,复制到指标对象(target)。Object.assign办法的第一个参数是指标对象,前面的参数都是源对象。(如果指标对象与源对象有同名属性,或多个源对象有同名属性,则前面的属性会笼罩后面的属性)。 同样,如果用户自定义的属性,放在扩大运算符前面,则扩大运算符外部的同名属性会被笼罩掉。 let bar = {a: 1, b: 2};let baz = {...bar, ...{a:2, b: 4}}; // {a: 2, b: 4}利用上述个性就能够很不便的批改对象的局部属性。在redux中的reducer函数规定必须是一个纯函数,reducer中的state对象要求不能间接批改,能够通过扩大运算符把批改门路的对象都复制一遍,而后产生一个新的对象返回。 须要留神:扩大运算符对对象实例的拷贝属于浅拷贝。 (2)数组扩大运算符 数组的扩大运算符能够将一个数组转为用逗号分隔的参数序列,且每次只能开展一层数组。 console.log(...[1, 2, 3])// 1 2 3console.log(...[1, [2, 3, 4], 5])// 1 [2, 3, 4] 5上面是数组的扩大运算符的利用: ...

October 31, 2022 · 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格局: 同一张图片jpg格局和webp格局压缩率有着显著的差别: ...

October 31, 2022 · 3 min · jiezi

关于javascript:JavaScript简单实现图片缩略图自动滚动

这周做了一个看似很简略的需要(就是给页面新增图片这么简略.....)过后我很开心刷刷刷把新图链接加上去就提测了。然而当需要处于测试阶段时发现事件没有那么简略!!因为需要我的项目较老,发现我的项目内的成果全都是用原生JS实现的。而后本来的图片缩略图组件竟然不兼容切换图片时缩略图主动定位,所以又另外花了工夫对本来的图片缩略图组件进行改进。 先来看一下最终要实现的成果: 整体思路:要害变量变量currentIndex示意以后将切换图片的index数组变量currentShowItem示意以后缩略图区域展现进去的图片index大体思路所有用户交互时都须要从新计算currentIndex与currentShowItem所有用户交互时都须要判断currentIndex是否存在于currentShowItem中:若不在,则须要将缩略图区域滚动到将要切换的图片地位;若存在,则无需滚动缩略图区域计算缩略图要滚动的地位以下是逐步欠缺组件的过程(待欠缺)

October 30, 2022 · 1 min · jiezi

关于javascript:Python接入微信公众号Token验证

留神点官网示例是Pthon2 版本的,如果是Python3 版本须要有改变验证胜利返回 echostr 要是 数字格局的公众号侧配置 (公众号后盾 - 根本配置) 服务器侧配置代码局部官网示例(python2) # -*- coding: utf-8 -*-# filename: handle.pyimport hashlibimport webclass Handle(object): def GET(self): try: data = web.input() if len(data) == 0: return "hello, this is handle view" signature = data.signature timestamp = data.timestamp nonce = data.nonce echostr = data.echostr token = "xxxx" #请依照公众平台官网\根本配置中信息填写 list = [token, timestamp, nonce] list.sort() sha1 = hashlib.sha1() map(sha1.update, list) hashcode = sha1.hexdigest() print "handle/GET func: hashcode, signature: ", hashcode, signature if hashcode == signature: return echostr else: return "" except Exception, Argument: return Argumentpython3 版本 (Django) ...

October 30, 2022 · 1 min · jiezi

关于javascript:Nodejs-fspath模块

首先我有话说,是谁说的学完ajax就能够去vue了,太天真了我,学会js钻出来个ajax,学完ajax钻出来个node.js这一步步的,当然node不会学到太深刻把外表的认识一下就能够了,这之后可能更新速度要慢一点了,因为这几天会把工夫花在论文上,马上要进入问难了,尽管我当初那是有十分的浓重的趣味想见识一下node的姿势啊。进入正题吧 1. 明天首先介绍一下什么是node.js? node.js是一个基于Chrome V8引擎的js运行环境,留神是一个运行环境,浏览器是js前端的运行环境,而咱们node就是js后端的运行环境,并且在node.js中无奈调用DOM、BOM以及ajax的一些api。 怎么来学习node.js呢? 就跟咱们js学习一样,先根底语法再webapi。node是先js根底语法,而后再node.js内置api(fs、path、http等)再去第三方的api(express、mysql等) 怎么用node来执行js? 通过终端来实现,win+r关上cmd而后cd进入js文件所在的目录在执行node js文件名.js 更简便办法,间接进入这个目录而后按住shift+右键鼠标找到关上shellpower间接可运行node。当然我切实vscode上能够间接运行终端还多不便的 2. 进入咱们明天第一个学习指标,fs文件系统模块,这是一个操作文件的模块。想要应用它必须先得导入,当然在这些node内置的api都是装置node的时候就有的你只须要导入即可 在这个模块外面有两个办法第一个是读取指定文件内容 fs.readFile(path【,options】,callback)path:文件的门路 options: 以什么样的编码来读取文件callback:读取后的回调函数const fs = require('fs')fs.readFile('./file/read.txt', 'utf-8', function(err, dataStr) { console.log(err); console.log(dataStr);}) const fs = require('fs')fs.readFile('./file/errread.txt', 'utf8', (err, dataStr) => { if (!err) { return console.log('读取胜利' + dataStr); } return console.log('读取失败' + err.message);})其中在这外面err=null示意读取胜利且此时dataStr就为外面的内容,否则就读取失败 既然有读取那就有写入,写入文件内容 fs.writeFile(path,data[,options],callback)path:写入文件的地址 留神 :这个地址能够拿来创立文件但不能创立目录data:写入的数据const fs = require('fs')fs.writeFile('./file/write.txt', 'hello fswrite', err => console.log(err))const fs = require('fs')fs.writeFile('./fileerr/write1.txt', '写入胜利',err => { if(!err) { return console.log('写入胜利' + err); } return console.log('写入失败' + err.message);})在这外面其实是有问题的,因为node是采取的动静拼接地址,也就是如果你的地址是以./或者../结尾的绝对地址的话,那么到时候执行它是以你执行node的地址拼接上你写入的这个地址,你想想是不是会有bug产生,而且这个时候你就算补全执行也是没得用的。 ...

October 29, 2022 · 3 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);函数节流throttle 策略的电梯。保障如果电梯第一个人进来后,50毫秒后准时运送一次,不期待。如果没有人,则待机。let throttle = (fn, delay = 50) => { // 节流 管制执行间隔时间 避免频繁触发 scroll resize mousemove let stattime = 0; returnfunction (...args) { let curTime = new Date(); if (curTime - stattime >= delay) { fn.apply(this, args); stattime = curTime; } } }防抖动debounce 策略的电梯。如果电梯里有人进来,期待50毫秒。如果又人进来,50毫秒期待从新计时,直到50毫秒超时,开始运送。参考 前端手写面试题具体解答let debounce = (fn, time = 50) => { // 防抖动 管制闲暇工夫 用户输出频繁 let timer; returnfunction (...args) { let that = this; clearTimeout(timer); timer = setTimeout(fn.bind(that, ...args), time); } }深度拷贝兼容写法(不包含原型属性)function deepCopy(obj) { if (typeof obj !== 'object') return obj; if (typeof window !== 'undefined' && window.JSON) { // 浏览器环境下 并反对window.JSON 则应用 JSON return JSON.parse(JSON.stringify(obj)); } else { let newObj = obj.constructor === Array ? [] : {}; for(let key in obj) { newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } return newObj; }}let obj = {a: 1, b: [12]};let newObj = deepCopy(obj);newObj.b[1] = 100;console.log(obj);console.log(newObj);Function的bind实现Function.prototype._bind = function(context) { let func = this; let params = [].slice.call(arguments, 1); returnfunction() { params = params.concat([].slice.call(arguments, 0)); func.apply(context, params); }}let obj = {id: 24}function fn1(a) { console.log(this, arguments);}let foo = fn1._bind(obj, obj.id);函数组合串联compose(koa reduce中间件)// 组合串联let fn1 = (a) => a + 1;let fn2 = (b) => b + 2;let fn3 = (c) => c + 3;let funs = [fn1, fn2, fn3];let compose = (func) => { return arg => func.reduceRight((composed, fn) => fn(composed), arg);}console.log(compose(funs)(100)); // 相当于fn1(fn2(fn3(100)))co函数function* fn(a) { a = yield a; let b = yield 2; let c = yield 3; return a + b + c;}function co(fn, ...args) { let g = fn(...args); return new Promise((resolve, reject) => { function next(lastValue) { let { value, done } = g.next(lastValue); if (done) { resolve(value); } else { if (value instanceof Promise) { value.then(next, (val) => reject(val)); } else { next(value) } } } next(); });}co(fn, 100).then(value => { console.log(value); // 105});如何被动停止Promise调用链const p1 = new Promise((resolve, reject) => { setTimeout(() => { // 异步操作 resolve('start') }, 1000);});p1.then((result) => { console.log('a', result); return Promise.reject('中断后续调用'); // 此时rejected的状态将间接跳到catch里,剩下的调用不会再持续}).then(result => { console.log('b', result);}).then(result => { console.log('c', result);}).catch(err => { console.log(err);});// a start// 中断后续调用bluebird.promisify实现(将异步回调函数api 转换为promise模式)// promisify.jsmodule.exports = { promisify(fn){ returnfunction () { var args = Array.from(arguments); return new Promise(function (resolve, reject) { fn.apply(null, args.concat(function (err) { if (err) { reject(err); } else { resolve(arguments[1]) } })); }) } }}// main.jsconst fs = require('fs');const {promisify} = require('./promisify.js');const readFile = promisify('fs.readFile'); // 转换异步读取// 异步文件 由回调函数模式变成promise模式readFile('./1.txt', 'utf8').then(data => { console.log(data);}).catch(err => { console.log(err);});window.requestAnimationFrame兼容性解决window._requestAnimationFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000 / 60); };})();字符串是否合乎回文规定let str = 'My age is 0, 0 si ega ym.';办法一function palindrome(params) { params = params.replace(/[\W\s_]/ig, ''); return params.toLowerCase() === params.split('').reverse().join('').toLowerCase();}console.log(palindrome(str));办法二function palindrome(params) { params = params.replace(/[\W\s_]/ig, '').toLowerCase(); for (var i = 0, j = params.length-1; i<j; i++, j--) { if (params[i] !== params[j]) { returnfalse; } } returntrue;}解构// 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4}const targetArray = [1, [2, 3], 4];const formater = "[a, [b], c]";const destructuringArray = (values, keys) => { try { const obj = {}; if (typeof keys === 'string') { keys = JSON.parse(keys.replace(/\w+/g, '"$&"')); } const iterate = (values, keys) => keys.forEach((key, i) => { if(Array.isArray(key)) iterate(values[i], key) else obj[key] = values[i] }) iterate(values, keys) return obj; } catch (e) { console.error(e.message); }}数组展平将[[1, 2], 3, [[[4], 5]]] 展平为 [1, 2, 3, 4, 5]let arr = [[1, 2], 3, [[[4], 5]]]; // 数组展平function flatten(arr) { return [].concat( ...arr.map(x => Array.isArray(x) ? flatten(x) : x) )}二分查找const arr = [1, 2, 3, 4, 5, 6, 7, 8];// 二分查找 递归 由两头开始往两边查找 前提是有序的数组 返回对应的索引地位function binarySearch1(arr, dest, start = 0, end = data.length) { if (start > end) { return -1 } let midIndex = Math.floor((start + end) / 2); // 两头地位索引 let mid = arr[midIndex]; // 两头值 if (mid == dest) { return midIndex; } if (dest < mid) { // 要找的比两头值小 就从两头往结尾找 始终到0 return binarySearch1(arr, dest, 0, midIndex - 1); } if (dest > mid) { // 要找的比两头值大 就从两头往后找 始终到end完结 return binarySearch1(arr, dest, midIndex + 1, end); } return -1; // 找不到返回-1}console.log(binarySearch1(arr, 7, 3, 6)); // 6// 非递归 arr前提有序数组 (从小到大)返回对应的索引地位 function binarySearch2(arr, dest) { let max = arr.length - 1; let min = 0; while (min <= max) { let mid = Math.floor((max + min) / 2); // mid两头地位索引 if (dest < arr[mid]) { // 如果要找的这项比两头项还要小 阐明应该在mid两头地位后面 批改最大边界值max=mid-1 max = mid - 1; } elseif (dest > arr[mid]) { // 如果要找的这项比两头项还要大 阐明应该在mid两头地位的前面 批改最小边界值min=mid+1 min = mid + 1; } else { return mid; } } return -1; // 找不到返回-1}console.log(binarySearch2(arr, 3)); // 2找出数组中反复呈现过的元素// 例如:[1,2,4,4,3,3,1,5,3]// 输入:[1,3,4]let arr = [1, 2, 4, 4, 3, 3, 1, 5, 3];// 办法一function repeat1(arr){ var result = [], map = {}; arr.map(function(num){ if(map[num] === 1) result.push(num); // 等于1阐明之前呈现过一次 这次反复呈现了 map[num] = (map[num] || 0) + 1; // 奥妙之处 开始第一次呈现无值 记为 0 + 1 = 1 下一次从1开始累加 }); return result;}console.log(repeat1(arr));// 办法二function repeat(arr) { let result = arr.filter((x, i, self) => { return self.indexOf(x) === i && self.lastIndexOf(x) !== i }); // return result;}console.log(repeat(arr));数组中依照数字反复呈现的次数进行排序// 如果次数雷同 则依照值排序 比方 2, 2, 2和 1, 1, 1 应排序为 [1, 1, 1, 2, 2, 2]// 比方 [1,2,1,2,1,3,4,5,4,5,5,2,2] => [3, 4, 4, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2]let arr = [9, 7, 7, 1, 2, 1, 2, 1, 3, 4, 5, 4, 5, 5, 2, 2];function sortArray(arr) { let obj = {}; let newArr = []; for(let i = 0; i < arr.length; i++) { let cur = arr[i]; if(obj[cur]){ obj[cur].push(cur); continue; } obj[cur] = [cur]; } for(let k in obj) { if(obj.hasOwnProperty(k)) { newArr.push(obj[k]) } } newArr.sort((a, b) => { if(a.length === b.length){ return a[0] - b[0]; } return a.length - b.length; }); newArr = newArr.reduce((prev, cur) => prev.concat(cur)); return newArr; } console.log(sortArray(arr)); // [ 3, 9, 4, 4, 7, 7, 1, 1, 1, 5, 5, 5, 2, 2, 2, 2 ]不必循环,创立一个长度为 100 的数组,并且每个元素的值等于它的下标。// 办法一 递归写法function createArray(len, arr = []) { if (len > 0) { arr[--len] = len; createArray(len, arr); } return arr;}console.log(createArray(100)); // 办法二// 上面评论中@MaDivH 提供的实现办法 长度为 100 的数组 Array(100).fill().map((_,i)=>i+1);// 办法三[...Array(100).keys()]依据关键词找出 所在对象idvar docs = [ { id: 1, words: ['hello', "world"] }, { id: 2, words: ['hello', "hihi"] }, { id: 3, words: ['haha', "hello"] }, { id: 4, words: ['world', "nihao"] }];findDocList(docs, ['hello']) // 文档id1,文档id2,文档id3findDocList(docs, ['hello', 'world']) // 文档id1function findDocList(docs, word = []) { if (word.constructor !== Array) return; let ids = []; for (let i = 0; i < docs.length; i++) { let {id, words} = docs[i]; let flag = word.every((item) => { return words.indexOf(item) > -1; }); flag && ids.push(id); } return ids;}findDocList(docs, ['hello', 'world']);getElementsByClassName 兼容写法function getByClass(cName) { if ('getElementsByClassName'in this) { return this.getElementsByClassName(cName); } cName = cName.replace(/(^\s+|\s+$)/g, '').split(/\s+/g); let eles = this.getElementsByTagName('*'); for (let i = 0; i < cName.length; i++) { let reg = new RegExp(`(^| )${cName[i]}( |$)`); let temp = []; for (let j = 0; j < eles.length; j++) { let cur = eles[j]; let {className} = cur; if (reg.test(className)) { temp.push(cur); } } eles = temp; } return eles; } console.log(content.getByClass('c1 c2 '));插入排序插入排序 从后往前比拟 直到碰到比以后项 还要小的前一项时 将这一项插入到前一项的前面function insertSort(arr) { let len = arr.length; let preIndex, current; for (let i = 1; i < len; i++) { preIndex = i - 1; current = arr[i]; // 以后项 while (preIndex >= 0 && arr[preIndex] > current) { arr[preIndex + 1] = arr[preIndex]; // 如果前一项大于以后项 则把前一项往后挪一位 preIndex-- // 用以后项持续和后面值进行比拟 } arr[preIndex + 1] = current; // 如果前一项小于以后项则 循环完结 则将以后项放到 前一项的前面 } return arr;}抉择排序抉择排序 每次拿以后项与前面其余项进行比拟 失去最小值的索引地位 而后把最小值和以后项替换地位function selectSort(arr) { let len = arr.length; let temp = null; let minIndex = null; for (let i = 0; i < len - 1; i++) { // 把以后值的索引作为最小值的索引一次去比拟 minIndex = i; // 假如以后项索引 为最小值索引 for (let j = i + 1; j < len; j++) { // 以后项前面向一次比小 if (arr[j] < arr[minIndex]) { // 比假如的值还要小 则保留最小值索引 minIndex = j; // 找到最小值的索引地位 } } // 将以后值和比拟出的最小值替换地位 if (i !== minIndex) { temp = arr[i] arr[i] = arr[minIndex]; arr[minIndex] = temp; } } return arr;}冒泡排序冒泡排序 相邻两项进行比拟 如果以后值大于后一项 则替换地位function bubleSort(arr) { let length = arr.length; let temp = null; for (let i = 0; i < length - 1; i++) { // 管制轮数 let flag = false; // 以后这轮是否替换过标识 for (let l = 0; l < length - i - 1; l++) { // 管制每轮比拟次数 if (arr[l] > arr[l + 1]) { temp = arr[l]; arr[l] = arr[l + 1]; arr[l + 1] = temp; flag = true; // 如果产生过替换flag则为true } } if (!flag) { // 优化 如果从头到尾比拟一轮后 flag仍然为false阐明 曾经排好序了 没必要在继续下去 temp = null; return arr; } }}疾速排序(递归)function quickSort(arr) { if (arr.length <= 1) return arr; let midIndex = Math.floor(arr.length / 2); let midNum = arr.splice(midIndex, 1)[0]; let left = []; let right = []; for(let i = 0; i < arr.length; i++) { let cur = arr[i]; if (cur <= midNum) { left.push(cur); } else { right.push(cur); } } return quickSort(left).concat(midNum, quickSort(right));}let arr = [2, 4, 12, 9, 22, 10, 18, 6];quickSort(arr);数组去重几种办法const arr = [1, 2, 1, 2, 3, 4, 2, 1, 3];// 1 ES6let newArr = [...new Set(arr)];// 2const arr = [1, 2, 1, 2, 3, 4, 'l', 2, 1, 3, 'l'];const newArr = arr.filter(function(ele, index, array) { return index === array.indexOf(ele)});console.log(newArr); // [ 1, 2, 3, 4, 'l' ]// 3Array.prototype.unique2 = function() { let newArr = []; let len = this.length; for(let i = 0; i < len; i++) { let cur = this[i]; if(newArr.indexOf(cur) === -1) { newArr[newArr.length] = cur; } } return newArr;}console.log(arr.unique1());// 4Array.prototype.unique3 = function() { let newArr = this.slice(0); let len = this.length; let obj = {}; for(let i = 0; i < len; i++) { let cur = newArr[i]; if(obj[cur]) { newArr[i] = newArr[newArr.length - 1]; newArr.length--; i--; continue; } obj[cur] = cur; } return newArr;}console.log(arr.unique3());// 5Array.prototype.unique4 = function() { let json = {}, newArr = [], len = this.length; for(var i = 0; i < len; i++) { let cur = this[i]; if (typeof json[cur] == "undefined") { json[cur] = true; newArr.push(cur) } } return newArr;}console.log(arr.unique4());千分符办法一// 解决数字let str1 = 2123456789;let str2 = 2123456789.12;console.log(str1.toLocaleString()); // 2,123,456,789console.log(str2.toLocaleString()); // 2,123,456,789.12办法二 // 解决字符串 let str1 = '2123456789'; let str2 = '2123456789.12'; // 利用正向预查 匹配 结尾一个数字\d 前面匹配这个数字前面必须是三个数字为一组为结尾或小数为结尾 function thousandth(str) { let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g; return str.replace(reg, '$&,'); } console.log(thousandth(str1)); // 2,123,456,789 console.log(thousandth(str2)); // 2,123,456,789.12在一个数组中 如a、b两项, 要保障a和b两项的差 与 a和b两项索引的差 的相加后的后果max 是数组中其余两项max 中的最大值 找出符合条件两项a, b的值 (不能够排序 或扭转数组地位) 如:let max = (a - b) + (a的索引- b的索引);求a b ...

October 29, 2022 · 12 min · jiezi

关于javascript:美团前端一面必会手写面试题汇总

手写 Promiseconst PENDING = "pending";const RESOLVED = "resolved";const REJECTED = "rejected";function MyPromise(fn) { // 保留初始化状态 var self = this; // 初始化状态 this.state = PENDING; // 用于保留 resolve 或者 rejected 传入的值 this.value = null; // 用于保留 resolve 的回调函数 this.resolvedCallbacks = []; // 用于保留 reject 的回调函数 this.rejectedCallbacks = []; // 状态转变为 resolved 办法 function resolve(value) { // 判断传入元素是否为 Promise 值,如果是,则状态扭转必须期待前一个状态扭转后再进行扭转 if (value instanceof MyPromise) { return value.then(resolve, reject); } // 保障代码的执行程序为本轮事件循环的开端 setTimeout(() => { // 只有状态为 pending 时能力转变, if (self.state === PENDING) { // 批改状态 self.state = RESOLVED; // 设置传入的值 self.value = value; // 执行回调函数 self.resolvedCallbacks.forEach(callback => { callback(value); }); } }, 0); } // 状态转变为 rejected 办法 function reject(value) { // 保障代码的执行程序为本轮事件循环的开端 setTimeout(() => { // 只有状态为 pending 时能力转变 if (self.state === PENDING) { // 批改状态 self.state = REJECTED; // 设置传入的值 self.value = value; // 执行回调函数 self.rejectedCallbacks.forEach(callback => { callback(value); }); } }, 0); } // 将两个办法传入函数执行 try { fn(resolve, reject); } catch (e) { // 遇到谬误时,捕捉谬误,执行 reject 函数 reject(e); }}MyPromise.prototype.then = function(onResolved, onRejected) { // 首先判断两个参数是否为函数类型,因为这两个参数是可选参数 onResolved = typeof onResolved === "function" ? onResolved : function(value) { return value; }; onRejected = typeof onRejected === "function" ? onRejected : function(error) { throw error; }; // 如果是期待状态,则将函数退出对应列表中 if (this.state === PENDING) { this.resolvedCallbacks.push(onResolved); this.rejectedCallbacks.push(onRejected); } // 如果状态曾经凝固,则间接执行对应状态的函数 if (this.state === RESOLVED) { onResolved(this.value); } if (this.state === REJECTED) { onRejected(this.value); }};二叉树档次遍历// 二叉树档次遍历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++ } // 档次遍历 队列 levelOrderTraversal(visitor) { if(this.root == null) { return } let stack = [this.root] let index = 0 // 指针 指向0 let currentNode while (currentNode = stack[index++]) { // 反转二叉树 let tmp = currentNode.left currentNode.left = currentNode.right currentNode.right = tmp visitor.visit(currentNode.element) if(currentNode.left) { stack.push(currentNode.left) } if(currentNode.right) { stack.push(currentNode.right) } } }}// 测试var bst = new BST((a,b)=>a.age-b.age) // 模仿sort办法// ![](http://img-repo.poetries.top/images/20210522203619.png)// ![](http://img-repo.poetries.top/images/20210522211809.png)bst.add({age: 10})bst.add({age: 8})bst.add({age:19})bst.add({age:6})bst.add({age: 15})bst.add({age: 22})bst.add({age: 20})// 应用访问者模式class Visitor { constructor() { this.visit = function (elem) { elem.age = elem.age*2 } }}// ![](http://img-repo.poetries.top/images/20210523095515.png)console.log(bst.levelOrderTraversal(new Visitor()))模板引擎实现let template = '我是{{name}},年龄{{age}},性别{{sex}}';let data = { name: '姓名', age: 18}render(template, data); // 我是姓名,年龄18,性别undefinedfunction render(template, data) { const reg = /\{\{(\w+)\}\}/; // 模板字符串正则 if (reg.test(template)) { // 判断模板里是否有模板字符串 const name = reg.exec(template)[1]; // 查找以后模板里第一个模板字符串的字段 template = template.replace(reg, data[name]); // 将第一个模板字符串渲染 return render(template, data); // 递归的渲染并返回渲染后的构造 } return template; // 如果模板没有模板字符串间接返回}实现数组去重给定某无序数组,要求去除数组中的反复数字并且返回新的无反复数组。 ...

October 29, 2022 · 8 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) 这两个函数,别离是对依赖的收集和触发。 ...

October 29, 2022 · 5 min · jiezi

关于javascript:JavaScript的异步编程之Promise

Promise一种更优的异步编程对立 办法,如果间接应用传统的回调函数去实现简单操作就会造成回调深渊 // 回调深渊$.get('/url1'() => { $.get('/url2'() => { $.get('/url3'() => { $.get('/url4'() => { $.get('/url5'() => { // 大略就是这样子的 }) }) }) })})CommonJS 社区提出了 Promise 标准,在ES2015中被标准化,成为语言标准。当期待状态改编程胜利或者失败之后就再也不能再被扭转了,胜利的时候触发onFulfilled 回调,失败的时候触发onRejected 回调 Promise 简略应用new Promise 传入一个回调函数,这个回调函数两个参数,第一个把Promise 改成为胜利的状态,第二个参数把Promise扭转成失败的状态,捕捉胜利和异样能够应用.then和.catch办法,这两个办法返回的也是一个Promise对象 // 演示const promsie = new Promise((resolve, reject) => { reject(1)})promsie.then((value) => { console.log(value)}, (err) => { // end 执行完之后才会执行这个 console.log(err)})// end 会先执行console.log('end')不论Promise中有没有异步操作,then办法中的回调函数仍然会进入回调队列中排队,会等同步代码执行完之后才会执行 用Promise写一个申请函数 function ajax (url) { return new Promise((resove, reject) => { var xhr = new XMLHttpRequest() xhr.open('GET', url) // 新办法能够间接承受一个j对象 xhr.responseType = 'json' xhr.onload = function () { if (this.status === 200) { resove(this.response) } else { reject(new Error(this.statusText)) } } xhr.send() })}ajax('/json1.json').then(ret => { console.log(ret)}).catch(err => { console.log(err)})如果须要多个间断的申请能够应用链式调用 ...

October 28, 2022 · 3 min · jiezi

关于javascript:深入理解函数式编程下

函数式编程是一种历史悠久的编程范式。作为演算法,它的历史能够追溯到古代计算机诞生之前的演算,本文心愿带大家疾速理解函数式编程的历史、根底技术、重要个性和实际法令。在内容层面,次要应用JavaScript语言来形容函数式编程的个性,并以演算规定、语言个性、范式个性、副作用解决等方面作为切入点,通过大量演示示例来解说这种编程范式。同时,文末列举比拟一些此范式的优缺点,供读者参考。因为文章涵盖一些领域论常识,可能须要其余参考资料一起辅助浏览。1. 前文回顾在上篇中,咱们剖析了函数式编程的起源和根本个性,并通过每一个个性的示例来演示这种个性的实际效果。首先,函数式编程起源于数理逻辑,起源于演算,这是一种演算法,它定义一些根底的数据结构,而后通过归约和代换来实现更简单的数据结构,而函数自身也是它的一种数据。其次,咱们探讨了很多函数式编程的个性,比方: First Class纯函数援用通明表达式高阶函数柯里化函数组合point-free...但咱们也指出了一个理论问题:不能解决副作用的程序是毫无意义的。咱们的计算机程序随时都在产生副作用。咱们程序外面有大量的网络申请、多媒体输入输出、外部状态、全局状态等,甚至在提倡“碳中和”的明天,电脑的发热量也是一个不容小觑的副作用。那么咱们应该如何解决这些问题呢? 2. 本文简介本文通过深刻函数式编程的副作用解决及理论利用场景,提供一个学习和应用函数式编程的视角给读者。一方面,这种副作用治理形式是一种高级的形象模式,不易了解;另一方面,咱们在学习和应用函数式编程的过程中,简直都会遇到相似的副作用问题须要解决,是否解决这个问题也决定了一门函数式编程语言最终是否能走上胜利。 本文次要分为三个局部: 副作用解决形式函数式编程的利用函数式编程的优缺点比拟3. 副作用解决:单子Monad,一种不可避免的形象下面说的,都是最根底的JavaScript概念+函数式编程概念。但咱们还留了一个“坑”。 如何去解决IO操作? 咱们的代码常常在和副作用打交道,如果要满足纯函数的要求,简直连一个需要都实现不了。不必急,咱们来看一下React Hooks。React Hooks的设计是很奇妙的,以useEffect为例: 在函数组件中,useState用来产生状态,在应用useEffect的时候,咱们须要挂载这个state到第二个参数,而第一个参数给到的运行函数在state变更的时候被调用,被调用时失去最新的state。 这外面有一个状态转换: React Hooks给咱们的启发是,副作用都被放到一个状态节点外面去被动触发,行程一个单向的数据流动。而实际上,函数式编程语言的确也是这么做的,把副作用包裹到一个非凡的函数外面。 如果一个函数既蕴含了咱们的值,又封装了值的对立操作,使得咱们能够在它限定的范畴内进行任意运算,那么,咱们称这种函数类型为Monad。Monad是一种高级别的思维形象。 3.1 什么是Monad?先思考一个问题,上面两个定义有什么区别? num1是数字类型,而num2是对象类型,这是一个直观的区别。 不过,不仅仅如此。利用类型,咱们能够做更多的事。因为作为数字的num1是反对加减乘除运算的,而num2却不行,必须要把它视为一个对象{val: 2},并通过属性拜访符num2.val能力进行计算num2.val + 2。但咱们晓得,函数式编程是不能扭转状态的,当初为了计算num2.val被扭转了,这不是咱们冀望的,并且咱们应用属性操作符去读数据,更像是在操作对象,而不是操作函数,这与咱们的初衷有所背离。 当初咱们把num2当作一个独立的数据,并假如存在一个办法fmap能够操作这个数据,可能是这样的。 失去的还是对象,但操作通过一个纯函数addOne去实现了。 下面这个例子外面的Num,实际上就是一个最简略的Monad,而fmap是属于Functor(函子)的概念。咱们说函数就是从一个数据到另一个数据的映射,这里的fmap就是一个映射函数,在领域论外面叫做态射(前面解说)。 因为有一个包裹的过程,很多人会把Monad看作是一个盒子类型。但Monad不仅是一个盒子的概念,它还须要满足一些特定的运算法则(前面波及)。 然而咱们间接应用数字的加减乘除不行吗?为什么肯定要Monad类型? 首先,fmap的目标是把数据从一个类型映射到另一个类型,而JavaScript外面的map函数实际上就是这个性能。 咱们能够认为Array就是一个Monad实现,map<T, K>把Array< T >类型映射到Array< K >类型,操作依然在数组领域,数组的值被映射为新的值。 如果用TypeScript来示意,会不会更清晰一点? 看起来Monad只是一个实现了fmap的对象(Functor类型,mappable接口)而已。但Monad类型不仅是一个Functor,它还有很多其余的工具函数,比方: bind函数flatMap函数liftM函数这些概念在学习Haskell时能够遇到,本文不作过多提及。这些额定的函数能够帮忙咱们操作被封装起来的值。 3.2 领域、群、幺半群领域论是一种钻研形象数学模式的迷信,它把咱们的数学世界形象为两个概念: 对象态射为什么说这是一种模式上的形象呢?因为很多数学的概念都能够被这种模式所形容,比方汇合,对汇合领域来说,一个汇合就是一个领域对象,从汇合A到汇合B的映射就是汇合的态射,再细化一点,整数汇合到整数汇合的加减乘操作形成了整数汇合的态射(除法会产生整数汇合无奈示意的数字,因而这里排除了除法)。又比方,三角形能够被代数示意,也能够用几何示意、向量示意,从代数示意到几何示意的运算就能够视为三角形领域的一种态射。 总之,对象形容了一个领域中的元素,而态射形容了针对这些元素的操作。领域论不仅能够利用到数学迷信外面,在其余迷信外面也有一些利用,实际上,领域论就是咱们形容主观世界的一种形式(形象模式)。 绝对应的,函子就是形容一个领域对象和另一个领域对象间关系的态射,具体到编程语言中,函子是一个帮忙咱们映射一个领域元素(比方Monad)到另一个领域元素的函数。 群论(Group)钻研的是群这种代数构造,怎么去了解群呢?比方一个三角形有三个顶点A/B/C,那么咱们能够示意一个三角形为ABC或者ACB,三角形还是这个三角形,然而从ABC到ACB肯定是通过了某种变换。这就像领域论,三角形的示意是领域对象,而一个三角形的示意变换到另一个模式,就是领域的态射。而咱们说这些三角形示意形式的汇合为一个群。群论次要是钻研变换关系,群又能够分为很多品种,也有很多法则个性,这不在本文钻研范畴之内,读者能够自行学习相干内容。 迷信解释一个Monad为自函子领域上的幺半群。如果没有学习群论和领域论的话,咱们是很难了解这个解释的。 简略来说先固定一个正方形abcd,它和它的几何变换形式(旋转/逆时针旋转/对称/中心对称等)造成的其余正方形一起形成一个群。从这个角度来说,群钻研的事物是同一类,只是性质稍有不一样(态射后)。 另外一个了解群的概念就是自然数(形成一个群)和加法(群的二元运算,且满足结合律,半群)。 到此,咱们能够了解Monad为: 满足自函子运算(从A领域态射到A领域,fmap是在本人空间做映射)。满足含幺半群的结合律。很多函数式编程外面都会实现一个Identity函数,理论就是一个幺元素。比方JavaScript中对Just满足二元结合律能够这么操作: 3.3 Monad领域:定律、折叠和链咱们要在一个更大的空间上探讨这个领域对象(Monad)。就像Number封装了数字类型,Monad也封装了一些类型。 Monad须要满足一些定律: 结合律:比方a · b · c = a · (b · c)。幺元:比方a · e = e · a = a。一旦定义了Monad为一类对象,fmap为针对这种对象的操作,那么定律咱们能够很容易证实: ...

October 28, 2022 · 1 min · jiezi

关于javascript:介绍几个不太常用的打包分析工具

webpack官网提供了剖析打包的一些工具,咱们在开发打包后,咱们能够利用webpack给咱们提供的一些工具去剖析包的大小,从而对打包输入文件进行优化,通常咱们都会用webpack-bundle-analyzer这个插件去剖析,除了这种,咱们看下官网提供的另外几种工具。 注释开始... 在开始本文之前,首先会从以下几点去利用工具剖析打包dist,参考官网文档bundle-analysis webpack-chart: webpack stats 交互饼图,次要是利用命令行webpack --profile --json=stats.json 本地生成json,而后依据生成的json显示包的信息webpack-bundle-analyzer是一个插件,只有打包胜利后,会主动关上一个界面剖析dist包webpack bundle optimize helper 剖析打包后的bundle.js,缩小bundle大小bundle-stats生成一个bundle报告,比拟不同构建之间的后果webpack-chart咱们关上webpack-chart而后在咱们的我的项目命令行里输出 npx webpack --profile --json=stats.json或者在package.json "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "server": "webpack server", "async": "webpack --profile --json=stats.json" },将生成的stats.json在指定关上的那个网站上上传上去 然而这个图貌似并没有那么显著 webpack-visualizer关上webpack-visualizer将生成的stats.json上传后能剖析哪个文件蕴含的一些依赖包的关系 webpack-bundle-analyzer间接装置webpack-bundle-analyzer插件 npm i webpack-bundle-analyzer --save-dev// webpack.config.jsconst { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')...module.exports = { plugins: [ ... new BundleAnalyzerPlugin() ]}当咱们运行npx webpack时,就会主动关上本地8888端口了通常来说,这种形式成果最好,能够十分分明的看到文件包之间的依赖关系 另外还有一种形式,就是能够用命令行形式,前提是学生成stats.json npx webpack-bundle-analyzer stats.json webpack bundle optimize helper关上地址helper,上传生成的stats.json 在这之前咱们webpack.config.js的mode:development此时咱们改成mode:production ...

October 28, 2022 · 1 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: ...

October 28, 2022 · 3 min · jiezi

关于javascript:前端面试中小型公司都考些什么

什么是 XSS 攻打?(1)概念XSS 攻打指的是跨站脚本攻打,是一种代码注入攻打。攻击者通过在网站注入歹意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。 XSS 的实质是因为网站没有对恶意代码进行过滤,与失常的代码混合在一起了,浏览器没有方法分辨哪些脚本是可信的,从而导致了恶意代码的执行。 攻击者能够通过这种攻击方式能够进行以下操作: 获取页面的数据,如DOM、cookie、localStorage;DOS攻打,发送正当申请,占用服务器资源,从而使用户无法访问服务器;毁坏页面构造;流量劫持(将链接指向某网站);(2)攻打类型XSS 能够分为存储型、反射型和 DOM 型: 存储型指的是歹意脚本会存储在指标服务器上,当浏览器申请数据时,脚本从服务器传回并执行。反射型指的是攻击者诱导用户拜访一个带有恶意代码的 URL 后,服务器端接收数据后处理,而后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终实现 XSS 攻打。DOM 型指的通过批改页面的 DOM 节点造成的 XSS。1)存储型 XSS 的攻打步骤: 攻击者将恶意代码提交到⽬标⽹站的数据库中。⽤户关上⽬标⽹站时,⽹站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。⽤户浏览器接管到响应后解析执⾏,混在其中的恶意代码也被执⾏。恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者假冒⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。这种攻打常⻅于带有⽤户保留数据的⽹站性能,如论坛发帖、商品评论、⽤户私信等。 2)反射型 XSS 的攻打步骤: 攻击者结构出非凡的 URL,其中蕴含恶意代码。⽤户关上带有恶意代码的 URL 时,⽹站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。⽤户浏览器接管到响应后解析执⾏,混在其中的恶意代码也被执⾏。恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者假冒⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库⾥,反射型 XSS 的恶意代码存在 URL ⾥。 反射型 XSS 破绽常⻅于通过 URL 传递参数的性能,如⽹站搜寻、跳转等。 因为须要⽤户被动关上歹意的 URL 能力⽣效,攻击者往往会联合多种⼿段诱导⽤户点击。 3)DOM 型 XSS 的攻打步骤: 攻击者结构出非凡的 URL,其中蕴含恶意代码。⽤户关上带有恶意代码的 URL。⽤户浏览器接管到响应后解析执⾏,前端 JavaScript 取出 URL 中的恶意代码并执⾏。恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者假冒⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻打中,取出和执⾏恶意代码由浏览器端实现,属于前端JavaScript ⾃身的安全漏洞,⽽其余两种 XSS 都属于服务端的安全漏洞。 ...

October 28, 2022 · 4 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>当初失去了,咱们想要的,报错:未定义。 ...

October 28, 2022 · 3 min · jiezi

关于javascript:js数组对象模糊查询

上效果图 上代码<!DOCTYPE html><html><head> <meta charset="UTF-8"> <!-- 引入款式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <style type="text/css"> .flex { display: flex; } .flex .item{ width: 300px; } </style></head><body> <div id="app"> <el-form :inline="true"> <el-form-item> <el-input v-model="input" placeholder="请输出内容"></el-input> </el-form-item> <el-form-item> <el-button @click="search">搜寻</el-button> </el-form-item> </el-form> <div class="flex"> <div class="item"> <h2>源数组对象</h2> <pre v-html="arr"></pre> </div> <div class="item"> <h2>搜寻后果:</h2> <pre v-html="result"></pre> </div> </div> </div></body><!-- 先引入 Vue --><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script><!-- 引入组件库 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><script> new Vue({ el: '#app', data() { return { input: '', result: '', arr: [ { title: 'JavaScript', children: [ { title: '来开黑啦', children: [] }, { title: '那个区', children: [ { title: '无畏先锋', children: [] } ] } ] }, { title: '费雷尔卓德怎么样', children: [ { title: '能够的', children: [] } ] }, { title: '好点卡', children: [ { title: '卡啦', children: [] } ] }, { title: '电脑配置不行', children: [] }, { title: '换一个', children: [ { title: '已上线', children: [] } ] } ] } }, mounted() { }, methods: { handleData(arr, val){ let newArr =[] arr.forEach(item => { if (item.children && item.children.length) { let children = this.handleData(item.children, val) let obj = { ...item, children } if (children && children.length) { newArr.push(obj) } else if (item.title.includes(val)) { newArr.push({ ...item }) } } else { if (item.title.includes(val)) { newArr.push(item) } } }) return newArr }, search() { this.result = this.handleData(this.arr, this.input) }, } })</script></html>

October 27, 2022 · 2 min · jiezi

关于javascript:React-Fiber架构不就是个链表么

看了React源码之后置信大家都会对Fiber有本人不同的见解,而我对Fiber最大的见解就是这玩意儿就是个链表。如果把整个Fiber树当成一个整体的确有点难了解源码,然而如果把它拆开了,将每个节点都看成一个独立单元却能失去一个很清晰的思路,接下来我就简略几点讲讲,我所认为的为什么React要用链表这种数据结构来构建Fiber架构 什么是Fiber可能理解过React的靓仔就要说了,Fiber就是一个虚构dom树;的确如此,然而16版本之前的React也存在虚构dom树,为什么要用Fiber代替呢? 家喻户晓(可能有靓仔不晓得),16.8之前React还没引入Fiber概念,Reconciler(协调器)会在mount阶段与update阶段循环递归mountComponent与updateComponent,此时数据存储在调用栈当中,因为是递归执行,所以一当开始便无奈进行直到递归执行完结;如果此时页面中的节点十分多咱们要等到递归完结可能要消耗大量的工夫,而且在此之间用户会感觉卡顿,这对用户来说相对称不上是好的体验; 因而在16版本之后React有了异步可中断更新与双缓存的概念,也就是咱们熟知的同步并发模式Concurrent模式,那么这些跟Fiber有什么关系呢? 首先咱们来看一段对于Fiber节点的React源码 function FiberNode(tag, pendingProps, key, mode) { // Instance //动态属性 this.tag = tag;// this.key = key; this.elementType = null;// this.type = null;//类型 this.stateNode = null; // Fiber //关联属性 this.return = null; this.child = null; this.sibling = null this.index = 0; this.ref = null; //工作属性 this.pendingProps = pendingProps; this.memoizedProps = null; this.updateQueue = null; this.memoizedState = null; this.dependencies = null; this.mode = mode; // Effects this.flags = NoFlags; this.subtreeFlags = NoFlags; this.deletions = null; this.lanes = NoLanes; this.childLanes = NoLanes; this.alternate = null; { // Note: The following is done to avoid a v8 performance cliff. // // Initializing the fields below to smis and later updating them with // double values will cause Fibers to end up having separate shapes. // This behavior/bug has something to do with Object.preventExtension(). // Fortunately this only impacts DEV builds. // Unfortunately it makes React unusably slow for some applications. // To work around this, initialize the fields below with doubles. // // Learn more about this here: // https://github.com/facebook/react/issues/14365 // https://bugs.chromium.org/p/v8/issues/detail?id=8538 this.actualDuration = Number.NaN; this.actualStartTime = Number.NaN; this.selfBaseDuration = Number.NaN; this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization. // This won't trigger the performance cliff mentioned above, // and it simplifies other profiler code (including DevTools). this.actualDuration = 0; this.actualStartTime = -1; this.selfBaseDuration = 0; this.treeBaseDuration = 0; } { // This isn't directly used but is handy for debugging internals: this._debugSource = null; this._debugOwner = null; this._debugNeedsRemount = false; this._debugHookTypes = null; if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') { Object.preventExtensions(this); } }}能够看到在一个FiberNode当中存在很多属性,咱们大体将他们分为三类: ...

October 27, 2022 · 2 min · jiezi

关于javascript:js作用域作用域链和它的一些优化

前言作用域和作用域链是所有JavaScript开发人员每天都要接触和利用的内容。不论是面试中的作用域链的面试考查,还是日常代码研发中变量与作用域链的构建,它的身影简直无处不在。它就像一顶优良厨师的厨师帽,只有咱们走进厨房,咱们就要将它整顿好,套在头上。没有它整洁洁净的戴在头上,你就不是一名好的JavaScript工程师。 其实,作为一名前端工程师,我也已经纳闷过:基本上所有的计算机语言都具备作用域的概念,然而为何JavaScript开发人员总是对作用域这个概念执着不已?直到,我屡次在编写代码过程中遇到波及到作用域的问题后,我才慢慢理解这个问题并去认真钻研。 而这篇文章,就是想要和大家聊聊无关JavaScript作用域以及作用域链的那些事件,以及针对它们的一些咱们在代码中优化小技巧。 内容对于简直所有的编程语言来说,最根本的性能之一,就是贮存变量当中的值并且能在之后对这个值进行拜访和批改。这种能力的引入,是程序的状态存在的根底。然而,能力的引入须要咱们解决几个问题,例如:变量存储在哪里?以何种模式存储?须要读取和批改变量的时候,以什么形式获取到这个变量? 很显著,为了解决这些问题,咱们须要一套设计良好的规定来存储变量,并且之后能够不便的找到这些变量。与此同时,整套残缺规定的设计就会衍生出额定规定概念。而作用域,就是这套规定下衍生进去的概念。 作用域咱们能够把作用域了解为下面讲到的这套规定下的限定范畴。作用域的职责是,在这段限定范畴中依据这套设计好的规定存储所申明的变量,并且提供批改该变量的反对。在变量的拜访权限平安上,作用域还承当着爱护以后作用域内的变量不被内部作用域拜访的权限爱护作用。 通过类比,咱们能够把作用域设想成一个气泡。在这个气泡里所申明的变量成员被蕴含在其中。每个气泡都装备有一位有准则的管家,将所有的成员治理起来,并针对他们申明的地位和要求对它们提供爱护。当气泡中代码语句想要拜访和批改变量成员时,管家会联合变量成员的要求关联对应拜访和批改操作。 随着ECMAScript规范的一直倒退和欠缺,JavaScript目前存在着四种作用域类型: 全局作用域(Global Scope): JavaScript语言环境的最顶级作用域,在语言环境初始化时创立。模块作用域(Module Scope): 由ECMAScript模块规范(ES Module)引入,在解析ECMAScript模块时创立。函数作用域(Function Scope): 在函数申明function() {}或者() => {}时创立。块级作用域(Block Scope): 由ECMAScript2015的变量申明标识符let和const引入,在应用这两者进行变量申明时,依据最近的一对花括号{}创立。/* 全局作用域 start,JavaScript语言环境初始化时就被创立 *//* 模块作用域 start,作为ES Module解析和执行时被创立 */let name = 'Wu';{ /* 块级作用域 start,const进行变量申明在最近的花括号{}内创立 */ const prefix = Hardy; name = prefix + name; /* 块级作用域 end */}export function sayMyName(myName) { /* 函数作用域 start,函数申明时主动创立,初始化默认蕴含函数的形参变量 */ if (!myName) { /* 块级作用域 start */ const noNameAnswer = 'Sorry!'; console.log(noNameAnswer); return; /* 块级作用域 end */ } const wordPrifix = 'Hi! My Name is '; const answer = wordPrifix + myName + '.'; console.log(answer); /* 函数作用域 end */}/* 模块作用域 end *//* 全局作用域 end */作用域的嵌套作用域在应用上具备嵌套特色。一个作用域可能在本身外部创立一个新作用域从而造成外部和内部作用域的嵌套关系。 ...

October 27, 2022 · 2 min · jiezi

关于javascript:js函数式编程讲解

什么是函数式编程是一种编程范型,它将电脑运算视为数学上的函数计算,并且防止应用程序状态以及易变对象。函数式编程更加强调程序执行的后果而非执行的过程,提倡利用若干简略的执行单元让计算结果一直渐进,逐层推导简单的运算,而不是设计一个简单的执行过程。函数式编程的思维过程是齐全不同的,它的着眼点是函数,而不是过程,它强调的是如何通过函数的组合变换去解决问题,而不是我通过写什么样的语句去解决问题为什么叫函数式编程依据学术上函数的定义,函数即是一种形容汇合和汇合之间的转换关系,输出通过函数都会返回有且只有一个输入值。函数实际上是一个关系,或者说是一种映射,而这种映射关系是能够组合的。 在咱们的编程世界中,咱们须要解决的其实也只有“数据”和“关系”,而关系就是函数。咱们所谓的编程工作也不过就是在找一种映射关系,一旦关系找到了,问题就解决了,剩下的事件,就是让数据流过这种关系,而后转换成另一个数据。 函数式编程的特点函数是一等公民。你能够像看待任何其余数据类型一样看待它们——把它们存在数组里,当作参数传递,赋值给变量...等等。应用总有返回值的表达式而不是语句 // 函数式编程-函数作为返回参数const add = (x) => { return plus = (y) => { return x + y; }};let plus1 = add(1);let plus2 = add(2);console.log(plus1(1)); // 2console.log(plus2(1)); // 3申明式编程 (Declarative Programming)不再批示计算机如何工作,而是指出咱们明确心愿失去的后果。与命令式不同,申明式意味着咱们要写表达式,而不是一步一步的批示。 以 SQL 为例,它就没有“先做这个,再做那个”的命令,有的只是一个指明咱们想要从数据库取什么数据的表达式。至于如何取数据则是由它本人决定的。当前数据库降级也好,SQL 引擎优化也好,基本不须要更改查问语句。 无状态和数据不可变 (Statelessness and Immutable data)这是函数式编程的外围概念: 数据不可变: 它要求你所有的数据都是不可变的,这意味着如果你想批改一个对象,那你应该创立一个新的对象用来批改,而不是批改已有的对象。无状态: 次要是强调对于一个函数,不论你何时运行,它都应该像第一次运行一样,给定雷同的输出,给出雷同的输入,齐全不依赖内部状态的变动。// 比拟 Array 中的 slice 和 splicelet test = [1, 2, 3, 4, 5];// slice 为纯函数,返回一个新的数组console.log(test.slice(0, 3)); // [1, 2, 3]console.log(test); // [1, 2, 3, 4, 5]// splice则会批改参数数组console.log(test.splice(0, 3)); // [1, 2, 3]console.log(test); // [4, 5]函数应该纯天然,无副作用纯函数是这样一种函数,即雷同的输出,永远会失去雷同的输入,而且没有任何可察看的副作用。 ...

October 27, 2022 · 2 min · jiezi

关于javascript:千锋1024程序员节大咖讲师技术直播火力全开

千锋1024程序员节举办多年以来,为宽广技术学习者带来了数十场先进技术直播和丰富多彩的助力数字技术学习的流动。2022年精彩持续,以“程载数字经济 码动技术将来”为主题的千锋1024程序员节隆重启幕,其中技术直播流动广受期待,千锋大咖级讲师将在流动中为大家瞻望技术趋势,探讨技术倒退,为有志于投身技术行业的敌人提供职业倒退的指导性倡议。往年千锋1024程序员节的直播流动,从10月20日开始至26日完结,通过抖音平台为大家带来15场笼罩Java、前端、Python、UI设计、影视剪辑等热门技术方向的大咖讲师直播。直播中,大咖讲师从以后技术倒退、企业技术利用、企业技术人才招聘要求、技术能力晋升等角度进行分享,为了激励宽广粉丝踊跃学习技术,直播流动还设置了互动抽奖、问答抽奖等环节,感兴趣的敌人能够关注千锋动静。(千锋1024程序员节直播火力全开)千锋1024程序员节直播,为老手、零根底、职场转行的敌人们提供了轻松的学习气氛,讲师们通过轻松风趣和通俗易懂的表达方式,将粉丝们带入技术情景,帮忙大家理解数字技术在各行各业的利用,使大家感触到数字技术是经济微小的推动力,学习数字技术是将来职业继续向好倒退的重要门路,受到了宽广粉丝的宽泛认同和积极响应,直播互动更加热烈。本届千锋1024程序员节,被学员称为“陆神”的千锋前端学科大咖陆荣涛老师,分两场为大家带来前端学科直播,具体为粉丝们解说前端面试题,从企业技术利用角度、HR招聘角度、技术问题答复形式等方面解析前端工程师面试攻略。授课学员达上万名的Python学科大咖宋如宁老师,将分3场为大家带来“5天小白入门Python根底”,讲授“轻松入门Python语言根底”“玩转Python函数”“彻底搞懂Python面向对象”“回绝繁琐Python文件批量操作”“编程正则表达式”等干货内容。泛滥千锋硬核技术讲师在千锋1024程序员节期间,会为大家带来更多精彩内容,欢送收看。(千锋1024程序员节陆荣涛老师与宋如宁老师直播)千锋1024程序员节每年为程序员和准程序员筹备了丰富多彩的流动,心愿通过千锋的致力,能为万千年轻人提供长足发展的职业门路,造就更多的高素质数字技术人才助力企业和区域经济的倒退。

October 27, 2022 · 1 min · jiezi

关于javascript:手写JavaScript常见5种设计模式

想分享的几种设计模式目前模式:工厂模式,单例模式,适配器模式,装璜者模式,建造者模式 建造者模式 简介:建造者模式(builder pattern)比较简单,它属于创立型模式的一种。 文言:4个局部:有个产品,有个工厂能够造产品,有个设计师指挥造多少,有集体想买产品。 买产品的用户不介意产品制作流程,只须要产品! function Cola() { this.sugar = '50g', this.water = '100g'}function Packing() { // 第一种打包形式 this.createPkg = function(){ console.log('创立可乐外皮') } this.pushCola = function() { console.log('可乐倒进瓶子') } this.complete = function() { var cola = new Cola() cola.complete = true return cola } this.init = function() { this.createPkg() // 创立外皮 this.pushCola() // 倒进瓶子 //还能够减少其余步骤 return this.complete() // 制作实现 }}function greenPacking() { //绿皮可乐打包形式 this.createPkg = function(){ console.log('创立green可乐外皮') } this.pushCola = function() { console.log('可乐倒进green瓶子') } this.complete = function() { var cola = new Cola() cola.complete = true return cola } this.init = function() { this.createPkg() // 创立外皮 this.pushCola() // 倒进瓶子 //还能够减少其余步骤 return this.complete() // 制作实现 }}function Boss() { this.createCola = function(packType) { const pack = new window[packType] this.product = pack.init() //残缺产品产出 } this.getCola = function(packType) { this.createCola(packType); return this.product }}const boss = new Boss()var UserCola = boss.getCola('greenPacking') // UserCola.complete === true其余货色都不要,只有最初生产好的Cola,有sugar,有water。 ...

October 27, 2022 · 3 min · jiezi

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

给定两个数组,写一个办法来计算它们的交加例如:给定 nums1 = [1, 2, 2, 1],nums2 = [2, 2],返回 [2, 2]。function union (arr1, arr2) { return arr1.filter(item => { return arr2.indexOf(item) > - 1; })} const a = [1, 2, 2, 1]; const b = [2, 3, 2]; console.log(union(a, b)); // [2, 2]手写 Promise.thenthen 办法返回一个新的 promise 实例,为了在 promise 状态发生变化时(resolve / reject 被调用时)再执行 then 里的函数,咱们应用一个 callbacks 数组先把传给then的函数暂存起来,等状态扭转时再调用。 那么,怎么保障后一个 **then** 里的办法在前一个 **then**(可能是异步)完结之后再执行呢? 咱们能够将传给 then 的函数和新 promise 的 resolve 一起 push 到前一个 promise 的 callbacks 数组中,达到承前启后的成果: ...

October 27, 2022 · 19 min · jiezi

关于javascript:手写现代前端框架diff算法前端面试进阶

前言在前端工程上,日益简单的明天,性能优化曾经成为必不可少的环境。前端须要从每一个细节的问题去优化。那么如何更优,当然与他的如何怎么实现的无关。比方key为什么不能应用index呢?为什么不应用随机数呢?答案当然是影响性能,那为什么?置信你看完本文的diff算法就能略懂一些。 diff算法的概念diff算法, 是 Virtual DOM 产生的一个概念, 作用是用来计算出 Virtual DOM 中被扭转的局部,而后依据算法算出dom的后果进行原生DOM操作,而不必从新渲染整个页面,从而进步了页面渲染效率,曾经成为当今框架(vue,react)必不可少的局部。 手写diff算法的过程背景:dom对性能的耗费特地高,因而前辈们提出用js对象模仿dom的操作,计算出最初须要更新的局部。而dom自身的算法的工夫复杂度是O(n ^ 3)。这时react团队,提出了diff算法!(本案例提供外围代码,以及残缺案例)简略了解版本的思路的外围,可分为三个步骤: 1.模仿"dom树",将dom转换为js数组。定义js构造函数,可同步dom对象。通常对象可由下边组成: tag('string'):标签的名称 props('object'):属性与属性的值{ class: 'a', type: 'hidden'} children('array'):子属性 key('string'):示意元素的惟一标识 'nowKeys'2.获取两个dom数之间的差别(diff算法)比照两个dom对应的实体,获取他们的不同点,依据程序数组。以后demo解决了以下办法: Change: 'Change',//示意元素有变动 Move: 'Move',//示意挪动了地位 Add: 'Add',//示意元素是新增的 Del: 'Del',//示意元素给删除了 DiffPropsList: 'DiffPropsList',//示意元素对应的属性列表有变动 DelProps: 'DelProps',//示意该属性给删除 ChangeProps: 'ChangeProps',//示意该属性有变动 AddProps: 'AddProps',//示意该属性是新增的3.将“差别”进行“渲染”依据步骤2),将差别进行对应的解决实例办法如下: var a1 =new WzElement('div', { class: 'a1Class' }, ['a1'], "a1");var a2 =new WzElement('div', { class: 'a2Class' }, ['a2'], "a2")let root = a1.render();//js模仿dom生成步骤2)let pathchs = diff(a1, a2); //获取以后的两个dom的差别步骤3)reloadDom(root, pathchs);//依据差别从新渲染外围的代码(步骤1): _createDom( tag, props, children, key ){ let dom = document.createElement( tag ); for( let propKey in props ){ dom.setAttribute( propKey, props[propKey] ); } if( !key ){ dom.setAttribute( "key", key ); } children.forEach( item => { if( item instanceof WzElement ){// var root = this._createDom( item.tag, item.props, item.children, item.key ) dom.appendChild( root ); }else{ var childNode = document.createTextNode( item ); dom.appendChild( childNode ); } }); return dom; }外围的代码(步骤2):参考:前端手写面试题具体解答 ...

October 27, 2022 · 3 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相干常识,你应该事后就理解了 ...

October 27, 2022 · 7 min · jiezi

关于javascript:熬夜整理前端高频面试题已拿offer

TCP的三次握手和四次挥手(1)三次握手三次握手(Three-way Handshake)其实就是指建设一个TCP连贯时,须要客户端和服务器总共发送3个包。进行三次握手的次要作用就是为了确认单方的接管能力和发送能力是否失常、指定本人的初始化序列号为前面的可靠性传送做筹备。本质上其实就是连贯服务器指定端口,建设TCP连贯,并同步连贯单方的序列号和确认号,替换TCP窗口大小信息。 刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN,此时客户端处于 SYN_SEND 状态。首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。第二次握手:服务器收到客户端的 SYN 报文之后,会以本人的 SYN 报文作为应答,并且也是指定了本人的初始化序列号 ISN。同时会把客户端的 ISN + 1 作为ACK 的值,示意本人曾经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,示意曾经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,单方已建设起了连贯。确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段能够携带数据,不携带数据则不耗费序号。那为什么要三次握手呢?两次不行吗? 为了确认单方的接管能力和发送能力都失常如果是用两次握手,则会呈现上面这种状况:如客户端收回连贯申请,但因连贯申请报文失落而未收到确认,于是客户端再重传一次连贯申请。起初收到了确认,建设了连贯。数据传输结束后,就开释了连贯,客户端共收回了两个连贯申请报文段,其中第一个失落,第二个达到了服务端,然而第一个失落的报文段只是在某些网络结点长时间滞留了,延误到连贯开释当前的某个工夫才达到服务端,此时服务端误认为客户端又收回一次新的连贯申请,于是就向客户端收回确认报文段,批准建设连贯,不采纳三次握手,只有服务端收回确认,就建设新的连贯了,此时客户端疏忽服务端发来的确认,也不发送数据,则服务端统一期待客户端发送数据,浪费资源。简略来说就是以下三步: 第一次握手: 客户端向服务端发送连贯申请报文段。该报文段中蕴含本身的数据通讯初始序号。申请发送后,客户端便进入 SYN-SENT 状态。第二次握手: 服务端收到连贯申请报文段后,如果批准连贯,则会发送一个应答,该应答中也会蕴含本身的数据通讯初始序号,发送实现后便进入 SYN-RECEIVED 状态。第三次握手: 当客户端收到连贯批准的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连贯建设胜利。TCP 三次握手的建设连贯的过程就是互相确认初始序号的过程,通知对方,什么样序号的报文段可能被正确接管。 第三次握手的作用是客户端对服务器端的初始序号的确认。如果只应用两次握手,那么服务器就没有方法晓得本人的序号是否 已被确认。同时这样也是为了避免生效的申请报文段被服务器接管,而呈现谬误的状况。 (2)四次挥手刚开始单方都处于 ESTABLISHED 状态,如果是客户端先发动敞开申请。四次挥手的过程如下: 第一次挥手: 客户端会发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。即收回连贯开释报文段(FIN=1,序号seq=u),并进行再发送数据,被动敞开TCP连贯,进入FIN_WAIT1(终止期待1)状态,期待服务端的确认。第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明曾经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。即服务端收到连贯开释报文段后即收回确认报文段(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(敞开期待)状态,此时的TCP处于半敞开状态,客户端到服务端的连贯开释。客户端收到服务端的确认后,进入FIN_WAIT2(终止期待2)状态,期待服务端收回的连贯开释报文段。第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。即服务端没有要向客户端收回的数据,服务端收回连贯开释报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最初确认)状态,期待客户端的确认。第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为本人 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。须要过一阵子以确保服务端收到本人的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于敞开连贯了,处于 CLOSED 状态。即客户端收到服务端的连贯开释报文段后,对此收回确认报文段(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(工夫期待)状态。此时TCP未开释掉,须要通过工夫期待计时器设置的工夫2MSL后,客户端才进入CLOSED状态。那为什么须要四次挥手呢? ...

October 27, 2022 · 5 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值 注:以上总结的可能不残缺,能够在评论区补充,我后续补充上,谢谢~

October 27, 2022 · 1 min · jiezi

关于javascript:在-Openlayer-中添加-mark并添加-hover-效果

add mark办法一如果有多个点的话,能够生成多个 feature(循环调用 addFeature) const iconStyle = () => new Style({ image: new Icon({ scale: 0.2, src: image }) });const addFeature = (point: Coordinate) => new Feature({ geometry: new Point(Proj.fromLonLat(point)), properties, name: "以后地位", population: 4000, rainfall: 500, });const pointSource = new VectorSource({ features: [addFeature(point)],});const clusterSourceForLayer = new Cluster({ source: pointSource, distance: 50,});const pointLayer = new VectorLayer({ source: clusterSourceForLayer, zIndex: 3, style: iconStyle,});map.addLayer(pointLayer);pointLayer.set("baseMap", "iconLayer");办法二用 geojson 去渲染 mark const iconStyle = () => new Style({ image: new Icon({ scale: 0.2, src: image }) });const pointSource = new VectorSource({ features: new GeoJSON().readFeatures(geojson, { dataProjection: "EPSG:4326", featureProjection: "EPSG:3857", }),});const clusterSourceForLayer = new Cluster({ source: pointSource, distance: 50,});const pointLayer = new VectorLayer({ source: clusterSourceForLayer, zIndex: 3, style: iconStyle,});map?.addLayer(pointLayer);pointLayer.set("baseMap", "iconLayer");geojson 格局生成 geojson 的形式: ...

October 27, 2022 · 2 min · jiezi

关于javascript:javascript编程单线程之异步模式Asynchronous

异步模式Asynchronous不会期待这个工作完结才开始执行下一个工作,开启之后立刻执行下一个工作,后续逻辑个别会通过回调函数的形式定义,异步模式对js 十分重要,没有异步工作单线程的 js 语言就无奈同时解决大量耗时工作,单线程上面的异步最大的难点就是 代码的执行程序凌乱,Queue是音讯队列队列也叫回调队列 打印消息给同步一样执行压栈弹栈,接下来就是倒计时器,setTimeOut 就是调用了web api,web api独自运行不会阻塞js的执行, 开启倒计时器之后 setTimeOut的调用就曾经完结,会持续往下调用,同理压栈开启倒计时器弹栈,最初打印消息之后对于这个匿名函数就曾经调用完了,这个时候咱们的调用栈就会被清空掉,当调用栈执行完之后,Evevt loop就会从音讯队列中取出第一个回调函数压入到调用栈,当倒计时器达到工夫之后就会把回调函数放入到回调队列中。timer2倒计时先完结所以会先放入音讯队列中的第一位, Evevt loop监听到音讯队列发生变化,就会把timer2 放入到执行栈中去执行,这个时候对于调用栈来说就是开启了新一轮的执行,如果执行栈中的函数又开启了定时器,这个时候给后面的步骤是一样的,一直的去退出音讯队列,一直的去提取音讯队列中的函数来执行,直到调用栈和音讯队列中都没有须要执行的函数整体的代码就完结了,javascript执行引擎就是先去执行调用栈中的工作,而后再通过事件循环从音讯队列中再取一个工作执行,顺次类推。咱们随时都能够往音讯队列放入工作,这些工作会排队执行。javascript异步实现原理外部就是通过音讯队列和工夫循环实现的 回调函数所有异步编程计划根基都是回调函数,由调用者定义,交给执行者去执行的函数叫做回调函数 function foo (callback) { setTimeOut(() => { callback() }, 3000)}foo(() => { console.log("恰饭饭")})原文地址: https://kspf.xyz/archives/19更多内容微信公众号搜寻充饥的泡饭小程序搜一搜开水泡饭的博客

October 26, 2022 · 1 min · jiezi

关于javascript:千锋HTML5大前端全网首发Web30面授课程助力个人入局热门赛道

互联网诞生至今已有53年,从Web1.0以读为主的信息互联网,到Web2.0“可读+可写”的社交网络,再到近年来备受关注的Web3.0,互联网行将迈入“可读+可写+可领有”的“价值互联网”“契约互联网”。围绕Web 3.0的技术提高已开始为元宇宙的布局奠基,从各路风投狂奔入场、科技公司策略一直加码来看,Web 3.0这个“新世界”的大门曾经开启。行业倒退离不开人才的撑持,目前Web 3.0正在成为寰球人才追捧的热门待业方向,前端工程师、测试工程师、明码逻辑技术专家、合规分析师、设计师和反对分析师等,成为行业紧缺的人才,技术从业者的薪资更是30k到50k不等。为助力集体把握先机入局下一代互联网,千锋教育作为职业教育机构和前端培训界“扛把子”,积极探索Web3.0前沿人才需求,重磅推出了全网第一个线下Web3.0课程,从0开始手把手教你Dapp开发,助力宽广技术从业者和爱好者成为第一批Web3前端工程师!降级后的千锋HTML5大前端Web3.0面授课程,在内容上涵盖了Web3生态概念详解、Solidity 智能合约根底与实际、Web3.js 助飞你的DApp上以太坊、智能合约Solidity + 以太坊实际、IPFS 星际文件系统实际、利用Solidity开发以太坊在线钱包Web3我的项目等内容,从核心技术传授到实战利用,充沛赋能学员把握Web3.0前沿的技术需要。在Web3.0浪潮到来之际,千锋教育率先进行了学科内容降级,疾速的课程迭代速度,离不开其本身弱小的教研实力为依靠。据悉千锋教育在2011年成立之初便成立了千锋教研院,历经十年倒退,目前已在全国领有21个教研核心,100余人教研团队,300余人教学团队,每年千万教研投入,始终保持高度的教研翻新,以匠心打磨更优质的教学产品和服务,全方位赋能学员倒退。依靠深厚的教研实力,丰盛的教学资源和弱小的师资力量,将来,千锋教育将持续以行业趋势为引领,从教学内容和教学模式等层面,全面夯实千锋教育培训的教研根基,欠缺千锋教育培训的产品体系,为宽广学员带去更高品质的教学服务,将助力宽广从业者把握先机,晋升技能和职业竞争力。

October 26, 2022 · 1 min · jiezi

关于javascript:全国联动千锋教育1024程序员节线下狂欢活动火热开展

2022年度千锋教育“程载数字经济,码动技术将来”——1024程序员节,面向宽广从业者和千锋在校学员发展系列主题狂欢流动,线上线下发展了钜惠福利、名师和大厂技术大咖线上直播分享、线下技术沙龙、转盘抽奖、技术类书籍优惠活动等多重福利流动。近日,千锋教育在全国校区为在读学员们举办的“1024程序员节线下狂欢”精彩闭幕,各校区发展了我为程序员“代言”拍摄、转盘抽奖、积攒领礼品等模式丰盛的互动流动,让学员们在缓和的学习生存之余,放松身心,以更好的状态投入到新的“征程”。值此1024程序员节到来之际,千锋教育北京、上海、广州、深圳、南京、成都、郑州、杭州、长沙、大连、沈阳、青岛等多个校区冷落十分,在各校区老师的踊跃筹备下,校区拉起了“1024”节日横幅,彩旗、易拉宝、摆满礼品的奖品区、手举牌、平面相框和大转盘,让校区的节日气味分内浓重。流动一开始,学员们纷纷走出教室参加到丰盛的流动中来,大转盘前排起了“长龙”,学员们纷纷来此试手气,转盘上的礼品盲盒卡通U盘、鼠标垫、数据线等学习中罕用的工具取得了大家的青睐;手举牌和平面相框的拍摄区域,也汇集了泛滥学员,大家纷纷拿起标语,为“程序员节”打call,摄影师为将来的技术“大咖”定格了精彩霎时,流动现场欢畅十分,学员脸上笑容弥漫。 千锋教育“1024程序员节线下狂欢”炽热举办 千锋教育学员踊跃加入“1024程序员节线下狂欢”为程序员打call 千锋教育“1024程序员节线下狂欢”炽热进行此次流动取得了学员的极大好评,北京校区在读学员赵同学示意:“明天手气十分好,博得了‘1024程序员节’主题鼠标垫,还跟同学们拍摄了好多照片,让始终紧绷的学习神经有了放松,其余学员们也是欢笑一直,度过了第一个属于咱们的‘程序员节’。也非常感谢各位老师的精心安排,流动的每一个细节都能感触到老师们的用心和巧思,短暂的‘充电’上面我将更全身心的投入到学习中!”教育最重要的目标是促成人本身的成长,一是学术上的提高,一是精力上的富足。千锋教育在为学员提供高品质培训课程的同时,一直关注学员们的精力需要,继续发展内容丰盛的校园流动。通过夏令营、运动会、大赛、节日庆典、1024主题节日狂欢、论坛交换、校友讲座等丰富多彩文化流动的发展,为学员和校友们提供继续的关心,让学员们沐浴着人文关心成长,在千锋教育的平台上取得归属感、幸福感。接下来,千锋教育“1024程序员节”还有继续的线上直播、技术沙龙和钜惠福利流动,欢送技术爱好者和从业者前来关注,支付专属福利,取得职业晋升!

October 26, 2022 · 1 min · jiezi

关于javascript:千锋郑州第八届千锋杯联合项目大赛圆满落幕

职业教育培训机构千锋教育,深耕职教畛域十一年来,始终专一数字技术人才培养,累计造就了20余万复合型技术人才。在育人过程中,千锋严抓教学生命线,造就的技术人才广受企业认可,这与千锋我的项目驱动教学的特色教学设计分不开,跨学科联结我的项目大赛是其中之一,大赛为千锋学员提供了欠缺的全流程我的项目开发教训,充沛晋升了学员的技术水平和团队合作能力。 9月29日至10月24日,千锋郑州校区举办了第八届“千锋杯”程锋破浪联结我的项目较量,千锋郑州整体学员参加我的项目大赛,较量笼罩金融、智能家居、生存、社区、学习、二手、电商、汽车、游览、医疗等18个方向APP我的项目。通过强烈的角逐,最终8个我的项目小组进入决赛。依照疫情防控要求,决赛及颁奖典礼于线上举办,每个项目组别离进行我的项目演示与解说,评委老师现场点评和打分,最终依据打分和投票后果评比出一等奖1组,二等奖2组,三等奖3组,优秀奖2组,人气奖1组,获奖小组将取得现金、荣誉证书、背包等处分。 (file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml77176\wps16.jpg) (第八届“千锋杯”程锋破浪联结我的项目较量)在决赛中,每个小组展现了本人的我的项目,从组成人员、成员工作、我的项目框架构思、页面幅员、页面实现及接口、统计业务逻辑、和前端联调、组件打包、部署到服务器等等方面进行了粗疏的介绍,学员们在分享播种的同时也对我的项目中存在的问题进行了反思,例如,沟通协调不到位,前期呈现比拟多的小问题,虽不影响大局,然而不够完满。在我的项目演示阶段,每组都展现出了联合以后用户应用习惯的翻新点,例如,“邻里圈”我的项目,学员们在APP中设计了“一键开门”性能,十分合乎当下年轻人不喜爱带钥匙的特点,APP设计为用户生存提供了很大的便当,十分大的晋升了用户应用体验感。这个翻新设计在评委点评时候受到了极高的评估与必定。  (千锋第八届联结我的项目大赛参赛作品“邻里圈”) (千锋第八届联结我的项目大赛参赛项目组分享经验与播种) 千锋郑州第八届联结我的项目大赛,连续了千锋多年来的教学特色,不止整体学员参加,而且每个人都从头至尾的全流程参加了我的项目开发,充沛锤炼了学员技术利用能力和协同工作能力,并且开发成绩能够作为求职简历的重要实战经验,也是开启程序员生涯浓墨重彩的一笔。 此次联结我的项目大赛圆满闭幕,千锋指导老师和评委老师感触到千锋学员的翻新与拼搏,每个团队都尽最大致力将完满的作品出现给大家,这份致力与拼搏是年轻人难能可贵的,千锋学员体现得十分好。千锋始终秉持“初心至善 匠心育人”的外围价值观,将教好技术、育坏蛋作为教育者不懈谋求的指标,践行帮忙年轻人实现技术幻想的使命,将来,千锋将持续砥砺前行,将高水平的数字技术课程带给更多的年轻人。

October 26, 2022 · 1 min · jiezi

关于javascript:请谨慎选择JS加密工具站

前言JS加密本来是一个造福于宽广群主的产品,它能够很好的爱护你的前端JS代码,为您的前端代码保驾护航,还能够保障您的接口参数签名计算代码不泄露进来,避免居心叵测的人随便的去利用你的接口。 事件最近解密了一个JS代码,在里边发现了比拟奇葩的事件,几乎是业界羞耻。 它做了如下事件,它在每一次你的js执行的时候,去申请了一下它本人的连贯,如果你的网站页面加载资源和连贯足够多的话,你是齐全发现不了的。也就是说,你的流量被他利用了,并且可能盗取你的用户的材料等敏感信息,毕竟js文件在你的域下,例如ck等这些什么都能够拿的。齐全能够拿到敏感信息发送一封邮件进来到本人账户。 示例// js加密后的代码// 申请它接口的代码// js加密后的代码像这种,加密后基本剖析不进去,除非请厉害的大佬解密后查看才能够看进去。所以抉择加密工具肯定要审慎,JS代码会间接影响到你的财产平安。 结语感触代码敏感就不贴了,心愿大家抉择JS加密站的时候审慎抉择,尽量选正规化经营,ICP备案号齐全,域名注册信息有通过权威平台认证的、工商登记信息残缺,业务资质齐备,有本人的知识产权的,身份证信息清晰的、网站荣誉信息有保障的,公安备案号都齐全的工具站。 抉择JS加密工具站,肯定要谨慎抉择,一个公开通明好用,正规化,有法律保障您权利的JS加密工具站才是最合适的抉择。 在这里推一下咱们公司本人的产品,经营多年,能够说是国内业界第一的程度,马上也要更新加密算法降级到V7了。 jsjiami.com

October 26, 2022 · 1 min · jiezi

关于javascript:javascript-高级编程-之-Array-用法总结

援用类型是一种数据结构,用于将数据和性能分割起来。 创建对象的形式: 1.new操作符 var array=new Array();2.字面量表示法创立 var array=[];Array检测数组:检测数组是根本类型还是援用类型转换方法:将数组转换成字符串或数组对象栈办法:后进先出的操作数组的办法队列办法:先进先出的操作数组的办法操作方法:数组的拼接、截取、插入、删除、替换地位办法:查找数组项、返回索引值迭代办法:对每个数组项进行操作的办法放大办法:操作数组的每一项,构建最终的返回值1 检测数组检测数组的办法;instanceof操作符的问题是当开发环境引入多个框架存在多个全局环境的时候,会呈现不同的Array构造函数,进而呈现不同的后果。 Array.isArray()这个办法很好的解决了这个问题。arrName instanceof Array var array=[1,2,3];console.log(array instanceof Array) //trueArray.isArray(arrName) console.log(Array.isArray(array)) //true2 转换方法toString():返回以逗号分隔拼接而成的字符串valueOf():返回对象toLocaleString():区别很小,如果是数组调用这个办法,那么数组的每一项都会调用这个办法alert(value)==alert(value.toString()) var array=[1,2,3];var arrayToString=array.toString();var arrayValueOf=array.valueOf();var arrayToLocalString=array.toLocaleString(); console.log(arrayToString);// 1,2,3console.log(arrayValueOf);//[1, 2, 3]console.log(arrayToLocalString);//1,2,33 栈办法 (LIFO:last in first out)ES数组相似于数据结构的办法 栈是一种限度插入和删除项的数据结构push():接管任意数量的参数增加至数组尾部,返回数组长度值pop():从数组开端移除最初一项,缩小数组的length值,返回该数组被删除的最初一项4 队列办法 (FIFO:first in first out)联合push()和shift()办法能够实现像队列一样应用数组 应用unshift()和pop()能够从相同的方向模仿队列shift()移除并返回该数组的第一项;unshift()从数组前端增加任意个参数,并返回新数组的长度5 操作方法concat()复制原数组连贯新数组造成新正本; var arr1=['q','w','e'];var arr2=['h','u','o'];document.write(arr1.concat(arr2)); //q,w,e,h,u,oslice() 有一个参数时,复制参数为起始地位到开端的正本;有两个参数时,复制两个数字两头局部的数组项;如果参数是正数,复制用数组的长度加上负数值失去的两个参数之间的数组项; var arr3=['h','e','l','l','o'];console.log(arr3.slice(1));//e,l,l,oconsole.log(arr3.slice(-4));//e,l,l,oarr3.slice(-4)===arr3.slice(1);//truesplice() 三个参数:别离对应起始地位,删除项的个数,替换项;通过对这三个参数的正当使用能够实现删除、插入、替换等操作。 //从第一项开始删除两项var splice_arr1=['h','e','l','l','o']; console.log(splice_arr1.splice(1,2))//返回的是被删除的项组成的数组["e", "l"] //从第二项后插入三项old var splice_arr2=['h','e','l','l','o']; var removed=splice_arr2.splice(2,0,"K","K"); console.log(splice_arr2);//["h", "e", "K", "K", "l", "l", "o"] console.log(removed)//返回的是一个空数组 //替换 var removed=splice_arr3.splice(2,2,"P","P");console.log(splice_arr3);//["h", "e", "P", "P", "o"]console.log(removed)//返回的是被替换的值["l", "l"]6 地位办法返回索引值indexOf() 从前往后找lastIndexOf() 从后往前找 ...

October 26, 2022 · 1 min · jiezi

关于javascript:javascript尾递归优化

JS中的递归咱们来看一个阶乘的代码function foo( n ){ if(n <= 1){ return 1; } return n * foo( n - 1 );}foo(5); // 120上面剖析一下,代码运行过程中,执行上下文栈是怎么变动的这个代码是在全局作用域中执行的,所以在foo函数失去执行之前,上下文栈中就曾经被放入了一个全局上下文。之后执行一个函数,生成一个新的执行上下文时,JS引擎都会将新的上下文push到该栈中。如果函数执行实现,JS引擎会将对应的上下文从上下文栈中弹出一开始执行foo函数的时候,JS引擎会创立foo的执行上下文,将该执行上下文push进上下文栈。而后开始执行foo中的代码。 当初上下文栈中曾经有了两个执行上下文了在执行到foo中代码快完结时,return表达式中,又调用了foo函数。所以又会创立一个新的执行上下文。并且JS引擎会把这新的执行上下文push到上下文栈中。 当初上下文栈中曾经有了三个执行上下文了开始反复第3步的执行。始终到n<=1,才不会有新的执行上下文产生。此刻上下文栈中,曾经有了6个上下文了(蕴含了全局上下文) 构想一下如果刚开始调用的时候,传入n的初始值为100,到n<=1时,上下文栈中会有几个上下文。101个。如果初始值为1000呢?到n<=1时,会有1001个执行上下文也就是说,传入的初始值越大,执行上下文栈中,就会有越多的执行上下文对于高低栈,它的空间是无限的,一旦寄存的上下文占用内存产出了它的最大内存,就会呈现栈溢出。RangeError: Maximum call stack size exceeded而在chrome中,不仅会对栈的空间有限度,还会对函数的递归次数有限度递归优化咱们来看一个样例代码function outer() { return inner();}outer();剖析一下,这里的上下文栈是怎么变动的 调用outer函数的时候,第二个栈帧被推到了栈上。第一个栈帧是全局上下文 把上下文栈中的一个上下文称作一个栈帧 执行到了return语句,必须要计算inner调用后果,能力返回值调用inner函数,第三个栈帧被推入到栈上。 执行inner函数,将返回值传回到outer函数。inner执行结束。第三个栈帧被弹出栈 outer函数再返回值。outer函数执行结束,第二个栈帧被弹出栈 等等,状况不是一样的么?优化在哪里在执行到outer中的return语句的时候,要先计算inner函数的值。这时候JS引擎发现,把第二个栈帧弹出去也没有关系。因为到时候,间接拿inner的返回值返回进来就好了,第二个栈帧就没有必要保留了。参考视频解说:进入学习将第二个栈帧弹出这个时候,栈中只有一个栈帧了--全局上下文执行到inner函数,inner函数的上下文被push到栈中 这个时候,栈中有两个栈帧了开始执行inner函数,计算返回值后,inner函数执行结束。inner的上下文栈帧被弹出栈。 栈中又只剩一个栈帧了--全局上下文综上,咱们能够看出:如果没有优化,没多调用一次嵌套函数,就会多减少一个栈帧;有了优化之后,无论调用多少次嵌套,栈中只会有两个栈帧。这就是ES6尾调用优化的要害 递归优化的条件代码在严格模式下执行内部函数的返回值,是对尾调用函数的调用尾调用函数返回后,不须要执行额定的逻辑尾调用函数不是内部函数作用域中自在变量的闭包上面是《高程》外面的示例,帮忙大家了解// 无优化: 尾调用没有返回function outer(){ inner();}// 无优化: 尾调用没有间接返回function outer(){ let innerResult = inner(); return innerResult;}//无优化: 尾调用返回值后,必须要转型为字符串function outer(){ return inner().toString(); }// 无优化: 尾调用是一个闭包function outer(){ let foo = 'bar'; function inner(){ return foo; } return inner();}其实我感觉下面的倒数第二个,它是齐全能够尾调用优化的。因为这个计算是不须要内部函数的上下文外面内容反对的。可能是这样的计算必须要在内部函数的上下文中实现吧,咱也不懂。记一下吧。 ...

October 26, 2022 · 1 min · jiezi

关于javascript:怎样徒手写一个React

本文次要通过手写一个简略的 React,旨在理解 Facebook 团队应用两年多工夫重构的 Fiber 架构到底做了些什么?从而对 React 基本原理有一个直观的意识。尬不多说,搭建开始~青铜 – React、JSX、DOM elements 如何工作的?本文次要根本 React 16.8 版本进行实现。 上面先实现一个最简略的页面渲染,疾速理解 JSX、React、DOM 元素的分割。 import React from "react";import ReactDOM from "react-dom";const element = ( <div id="foo"> <a>bar</a> <b /> </div>);const container = document.getElementById("root");ReactDOM.render(element, container);实现一个最简略的 React 利用,只须要下面的三行代码就够了 ,上面咱们也将拆分三步进行剖析, 创立 React 元素(React Element)获取根节点 root将 React 元素渲染到页面上1. JSX 是如何被解析的 - Babelconst element = ( <div id="foo"> <a>bar</a> <b /> </div>);用 JSX 创立了一个 react 元素,它不是无效的 JS,其实它是被 babel 解析为如下代码: "use strict";const element = /*#__PURE__*/ React.createElement( "div", { id: "foo", }, /*#__PURE__*/ React.createElement("a", null, "bar"), /*#__PURE__*/ React.createElement("b", null));能够看到 Babel 会将 JSX 转换成 React.createElement() 办法,其中 createElement() 办法接管三个参数,别离是元素类型 type、元素属性 props、和子元素 children,前面咱们会实现这个办法。 ...

October 26, 2022 · 6 min · jiezi

关于javascript:前端常见手写面试题持续更新中

实现简略路由// hash路由class Route{ constructor(){ // 路由存储对象 this.routes = {} // 以后hash this.currentHash = '' // 绑定this,防止监听时this指向扭转 this.freshRoute = this.freshRoute.bind(this) // 监听 window.addEventListener('load', this.freshRoute, false) window.addEventListener('hashchange', this.freshRoute, false) } // 存储 storeRoute (path, cb) { this.routes[path] = cb || function () {} } // 更新 freshRoute () { this.currentHash = location.hash.slice(1) || '/' this.routes[this.currentHash]() }}实现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) }}实现观察者模式观察者模式(基于公布订阅模式) 有观察者,也有被观察者观察者须要放到被观察者中,被观察者的状态变动须要告诉观察者 我变动了 外部也是基于公布订阅模式,收集观察者,状态变动后要被动告诉观察者 ...

October 26, 2022 · 7 min · jiezi

关于javascript:手写JS函数的callapplybind

之所以要写这篇,是因为已经面试被要求在白纸上手写bind实现 后果跟代码一样清晰明确,一阵懵逼,没写进去! 上面,撸起袖子就是干!~ 把call、apply、bind一条龙都整一遍!~~ call定义与应用Function.prototype.call(): developer.mozilla.org/zh-CN/docs/…// Function.prototype.call()样例function fun(arg1, arg2) { console.log(this.name) console.log(arg1 + arg2)}const _this = { name: 'YIYING' }// 承受的是一个参数列表;办法立刻执行fun.call(_this, 1, 2)// 输入:YIYING3手写实现/** * 自定义call实现 * @param context 上下文this对象 * @param args 动静参数 */Function.prototype.ownCall = function(context, ...args) { context = (typeof context === 'object' ? context : window) // 避免笼罩掉原有属性 const key = Symbol() // 这里的this为须要执行的办法 context[key] = this // 办法执行 const result = context[key](...args) delete context[key] return result}// 验证样例function fun(arg1, arg2) { console.log(this.name) console.log(arg1 + arg2)}const _this = { name: 'YIYING' }// 承受的是一个参数列表;办法立刻执行fun.ownCall(_this, 1, 2)// 输入:YIYING3apply定义与应用Function.prototype.apply(): developer.mozilla.org/zh-CN/docs/…// Function.prototype.apply()样例function fun(arg1, arg2) { console.log(this.name) console.log(arg1 + arg2)}const _this = { name: 'YIYING' }// 参数为数组;办法立刻执行fun.apply(_this, [1, 2])// 输入:YIYING3手写实现/** * 自定义Apply实现 * @param context 上下文this对象 * @param args 参数数组 */Function.prototype.ownApply = function(context, args) { context = (typeof context === 'object' ? context : window) // 避免笼罩掉原有属性 const key = Symbol() // 这里的this为须要执行的办法 context[key] = this // 办法执行 const result = context[key](...args) delete context[key] return result}// 验证样例function fun(arg1, arg2) { console.log(this.name) console.log(arg1 + arg2)}const _this = { name: 'YIYING' }// 参数为数组;办法立刻执行fun.ownApply(_this, [1, 2])// 输入:YIYING3参考:前端手写面试题具体解答 ...

October 26, 2022 · 2 min · jiezi

关于javascript:Monorepo工程国际化最佳实践

在开发我的项目时越来越多采纳了Monorepo来组织工程代码,这样就面临着一个问题,引入国际化时如何无效地进行多语言联动。即当主程序切换语言时,Monorepo工程中所有包均须要切换到对应的语言。 为了解决Monorepo工程中多语言切换问题,应该做到: 主程序切换语言时,Monorepo工程中所有包均须要切换到对应的语言,整个切换过程是通明的。。开发阶段,每个包能够独立开发不须要额定的配置voerkai18n是目前所有javascript国际化解决方案中,针对Monorepo工程提供的最佳解决方案。 voerkai18n反对多个库国际化的联动和合作,即当主程序切换语言时,所有援用依赖库也会追随主程序进行语言切换,整个切换过程对所有库开发都是通明的。 库开发者不须要非凡配置,只须要像一般利用一样进行开发即可。 整体原理框架如下: voerkai18n官方网站

October 26, 2022 · 1 min · jiezi

关于javascript:模块联邦sdk-helmicro教程2本地联调远程js库

hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块计划 ,欢送关注与理解 hel-micro 教学视频来了hel-micro 教学视频来了,为了帮忙更多小伙伴疾速上手sdk化模块联邦 hel-micro ,会继续推出一系列教学视频,期待大家观看后可能学到有用的常识并提出相干改良意见,本期为第二期视频教程。 本地联调近程js库本期主讲内容为:学会 本地联调基于hel-micro开发的近程js库 (点击左侧链接关上视频教程) 附:视频演示我的项目往期视频: 公布和应用近程js库 理解更多欢送入群理解更多,因为微信探讨群号 200 人已满,需加作者微信号或 qq 群号,再邀请你如hel-micro探讨群(加号时记得备注 hel 哦)

October 26, 2022 · 1 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比照下你刚刚记下的答案,是否有不一样呢?让咱们尝试来最开始那些实践来剖析下。 ...

October 26, 2022 · 2 min · jiezi

关于javascript:最近美团前端面试题目整理

代码输入后果const promise = new Promise((resolve, reject) => { console.log(1); console.log(2);});promise.then(() => { console.log(3);});console.log(4);输入后果如下: 1 2 4promise.then 是微工作,它会在所有的宏工作执行完之后才会执行,同时须要promise外部的状态发生变化,因为这里外部没有发生变化,始终处于pending状态,所以不输入3。 Nginx的概念及其工作原理Nginx 是一款轻量级的 Web 服务器,也能够用于反向代理、负载平衡和 HTTP 缓存等。Nginx 应用异步事件驱动的办法来解决申请,是一款面向性能设计的 HTTP 服务器。 传统的 Web 服务器如 Apache 是 process-based 模型的,而 Nginx 是基于event-driven模型的。正是这个次要的区别带给了 Nginx 在性能上的劣势。 Nginx 架构的最顶层是一个 master process,这个 master process 用于产生其余的 worker process,这一点和Apache 十分像,然而 Nginx 的 worker process 能够同时解决大量的HTTP申请,而每个 Apache process 只能解决一个。 类组件与函数组件有什么区别呢?作为组件而言,类组件与函数组件在应用与出现上没有任何不同,性能上在古代浏览器中也不会有显著差别它们在开发时的心智模型上却存在微小的差别。类组件是基于面向对象编程的,它主打的是继承、生命周期等外围概念;而函数组件内核是函数式编程,主打的是 immutable、没有副作用、援用通明等特点。之前,在应用场景上,如果存在须要应用生命周期的组件,那么主推类组件;设计模式上,如果须要应用继承,那么主推类组件。但当初因为 React Hooks 的推出,生命周期概念的淡出,函数组件能够齐全取代类组件。其次继承并不是组件最佳的设计模式,官网更推崇“组合优于继承”的设计概念,所以类组件在这方面的劣势也在淡出。性能优化上,类组件次要依附 shouldComponentUpdate 阻断渲染来晋升性能,而函数组件依附 React.memo 缓存渲染后果来晋升性能。从上手水平而言,类组件更容易上手,从将来趋势上看,因为React Hooks 的推出,函数组件成了社区将来主推的计划。类组件在将来工夫切片与并发模式中,因为生命周期带来的复杂度,并不易于优化。而函数组件自身轻量简略,且在 Hooks 的根底上提供了比原先更细粒度的逻辑组织与复用,更能适应 React 的将来倒退。 ...

October 26, 2022 · 18 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。 ...

October 26, 2022 · 3 min · jiezi

关于javascript:ajax-终结篇jsonp防抖节流

明天是咱们最初一天ajax的学习,这次学完总能够去vue了吧,我不信还有什么拦路石,先不说其余的先看看明天的内容。 1. 首先是同源策略,什么叫做同源? 如果两个页面的协定、域名、端口都雷同的话,咱们将这两个页面为同源。 那么什么同源策略呢? 是浏览器提供的一个平安性能,如果说两个页面不同源,那么A网站就无奈读取B网站的cookie、localstorage、indexdb等;无奈接触B网站的DOM;无奈向B网站发送ajax申请 理解了同源与他相同的就是跨域,也就是下面说的协定。域名、端口只有有一个不满足那么他们就是跨域。 浏览器对跨域申请的拦挡,咱们是可能失常发动对服务器的申请的,服务器也可能感应到申请并将数据返回回来,然而就在邻近城门的时候,在浏览器门口就被一个同源策略的门卫拦挡住了,毕生之敌。 那么既然如此如何来实现跨域的申请呢?有两个形式CORS和JSONP。 cors是w3c规范反对get和post JSONP 原理:因为浏览器同源策略的限度,网页无奈通过ajax申请非同源,然而script这个标签是不受限制的,所以能够通过src这个属性申请到非同源的script 实现::本人定义一个回调函数,而后通过另一个script标签的src属性来调用服务器和一些参数在这个参数外面callback=这个函数的名字就是你本人回调函数的名字而后前面跟上你本人的参数 <!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>Document</title></head><body> <script> function fn(data) { console.log('调用胜利'); console.log(data); } </script> <script src="http://www.liulongbin.top:3006/api/jsonp?callback=fn&name=张三&age=29&sex=男"></script></body></html>JSONP的毛病就是他只反对get申请 2. jQuery中的JSONP,具体的格局如下 <!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>Document</title></head><body> <button>点击查看jsonp</button> <script src="../day01/lib/jquery.js"></script> <script> $('button').on('click', () => { $.ajax({ url : 'http://www.liulongbin.top:3006/api/jsonp?name=张三&age=29&sex=男', dataType : 'jsonp', jsonpCallback : 'fn', success : res => console.log(res) }) }) </script></body></html>在这外面datatype必须制订,而后url中没有了callback,因为他会本人随机生成一个callback,你也能够本人批改,jsonpCallback是批改回调函数名字的,jsonp是批改callback的。 在jq中jsonp的一个运行过程也要晓得一下,他其实也是依附script标签来实现的,在申请的时候他会动静生成一个script标签在header,而后申请实现又会移出这个标签。 3. 这些都学完了就能够看到一个案例,模拟淘宝的搜寻关键字案例 <!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <!-- 导入页面的根本款式 --> <link rel="stylesheet" href="./css/search.css" /> <!-- 导入 jQuery --> <script src="./lib/jquery.js"></script> <!-- 3.1插入template 筹备用到模板引擎 --> <script src="./lib/template-web.js"></script> <!-- 3.2定义ui构造 --> <script type="text/html" id="suggestList"> {{each result}} <div class="suggest-item">{{$value[0]}}</div> {{/each}} </script> <style> .suggest-list { display: none; border: 1px solid #ccc; } .suggest-item { padding-left: 5px; line-height: 30px; } .suggest-item:hover { cursor: pointer; background-color: #eee; } </style> </head> <body> <div class="container"> <!-- Logo --> <img src="./images/taobao_logo.png" alt="" class="logo" /> <div class="box"> <!-- tab 栏 --> <div class="tabs"> <div class="tab-active">宝贝</div> <div>店铺</div> </div> <!-- 搜寻区域(搜寻框和搜寻按钮) --> <div class="search-box"> <input type="text" class="ipt" placeholder="请输出要搜寻的内容" /><button class="btnSearch"> 搜寻 </button> </div> <!-- 3.在搜寻框上面增加一个盒子拿来装关键字列表 --> <div class="suggest-list"> </div> </div> </div> <script src="./lib/jquery.js"></script> <script src="./lib/index.js"></script> </body></html>通过jsonp和后面说到的模板引擎来实现 ...

October 25, 2022 · 3 min · jiezi

关于javascript:elementui开发-选择赠品弹层中的数据并展示在页面上弹层展示选中状态

最近在开发一个性能:有一个赠品弹层,外面能够抉择赠品,点击确定,可将选中的赠品展现在页面上。页面上的赠品列表有删除按钮,能够删除对应的数据,并且赠品弹层对应的那条数据勾销选中。上面是代码: <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>element-ui开发: 选中赠品弹层中的数据并展现在页面上,弹层展现选中状态</title> <!--引入 element-ui 的款式,--> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script> <!-- 引入element 的组件库--> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <style> * { margin: 0; padding: 0; } </style></head><body> <div id="app"> <el-button type="primary" @click="addGiftFun">增加赠品</el-button> <div v-if="livGiftList.length > 0"> <el-table :data="livGiftList" border style="width: 500px"> <el-table-column label="赠品名称" align="center" min-width="80"> <template slot-scope="{ row }"> <span>{{ row.name }}</span> </template> </el-table-column> <el-table-column label="操作" align="center" min-width="60"> <template slot-scope="scope"> <el-button @click="delGiftFun(scope.$index, livGiftList)">删除</el-button> </template> </el-table-column> </el-table> </div> <el-dialog title="请抉择赠品" :close-on-click-modal="false" :visible.sync="isShow" width="500px"> <el-table :data="giftProdctList" border style="width: 500px"> <el-table-column label="赠品名称" align="center" min-width="80"> <template slot-scope="{ row }"> <span>{{ row.name }}</span> </template> </el-table-column> <el-table-column label="赠品价格" align="center" min-width="80"> <template slot-scope="{ row }"> <span>{{ row.price }}</span> </template> </el-table-column> <el-table-column label="操作" align="center" min-width="60"> <template slot-scope="{ row }"> <el-checkbox v-model="row.checked">{{ row.checked ? "已抉择" : "抉择" }}</el-checkbox> </template> </el-table-column> </el-table> <div slot="footer" class="footer"> <el-button class="cancel-style" size="small" @click="isShow = false">取 消</el-button> <el-button type="primary" @click="submitFun">确 认</el-button> </div> </el-dialog> </div> <script> new Vue({ el: '#app', data() { return { // 管制弹层显示和暗藏 isShow: false, // 页面上展现的赠品列表 livGiftList: [], // 模仿赠品列表ajax数据 giftProdctListCopy: [ { name: "测试1", price: 1, id: 1 }, { name: "测试2", price: 10, id: 2 }, { name: "测试3", price: 9, id: 3 }, { name: "测试4", price: 3, id: 4 }, ], // 赠品弹层 giftProdctList: [] } }, methods: { // 增加赠品按钮 addGiftFun() { this.isShow = true; let checkedList = this.livGiftList; // 获取到页面展现的赠品列表,拿到赠品id汇合 checkedId = checkedList.map((item) => { return item.id }) // 模仿ajax申请: JSON.parse(JSON.stringify(this.giftProdctListCopy)) // 渲染赠品弹层数据并且高亮被选中的赠品 this.giftProdctList = JSON.parse(JSON.stringify(this.giftProdctListCopy)).map((item) => ({ ...item, // 高亮被选中的赠品 checked: checkedId.includes(item.id) })); console.log(this.giftProdctList, 'giftProdctList') }, // 赠品弹层点击确认 submitFun() { this.isShow = false; this.livGiftList = this.giftProdctList.filter((item) => { return item.checked; }) console.log(this.livGiftList, 'this.livGiftList') }, // 删除赠品 delGiftFun(index, row) { row.splice(index, 1) }, } }) </script></body></html>

October 25, 2022 · 2 min · jiezi

关于javascript:新一波-JavaScript-Web-框架

本文来自InfoQ中文站,原作者FrontEndMastery,译者Sambodhi,策动Tina太过激进很难在 Javascript 生态系统中放弃与时俱进。对于那些刚进入这个行业的人来说,要在新的库、框架、概念和无力的意见中关注正在产生的事件,很有挑战性。这是个很好的揭示,默认状况下,应用“无聊”的技术,你所相熟的技术,并且成为早期采纳者,通常是个不错的抉择。闲话少叙,本文将带读者理解 Javascript 中生态系统中的最新进展,通过钻研过来在构建大规模 Web 利用时的痛点来理解以后的状况。不要把注意力集中在快速增长的解决方案上,而是从潜在问题动手。每一种架构都会有不同的答案,并且会有不同的衡量。到本文完结时,咱们会列出风行框架的高级模型,如 React、Svelte、Vue、Solid、Astro、Marko、Fresh、Next、Remix、Qwik,以及适宜当今环境的“元框架” 。鉴往知来。让咱们回首来时路,再看看将来的趋势。这次,咱们将专一于大型项目中的问题,这些问题激发了其余办法和思维形式。 网页简史Web 最后由动态文档链接在一起组成。那时候,人们能够提前准备一份文件,并把它放在电脑上。而当初最酷的就是,人人都能够拜访它,无需亲临其境。不知从何时起,咱们感觉,让这些文件变成动静,会十分酷。于是咱们有了像 CGI 这样的技术,使咱们可能依据申请提供不同的内容。而后,咱们有了像 Perl 这样的表达式语言来编写这些脚本。它对最后针对 Web 开发的 PHP 产生了影响。PHP 的翻新之处在于将 HTML 间接连贯到后端代码。这使得以编程形式创立嵌入动静值的文件变得容易了。 Web 最重要的冲破之一来自于此: <html> <body> This document has been prepared ahead of time. Regards. </body></html>具备易于嵌入的动静值: <html> <body> Y2K? <?php echo time(); ?> </body></html>框架时代拉开大幕这些动静页面很受欢迎。咱们能够很轻松地对发送给用户的内容进行定制,包含启用会话的 cookies。在与数据库交互的语言生态系统中,曾经有了基于服务器的模板框架。通过这些框架,咱们能够轻松地从动态页面开始,而后扩大到动静页面。Web 的倒退日新月异,咱们想要更多的互动体验。为了这个目标,咱们应用了 Flash 这样的浏览器插件。在其余方面,咱们会在后端提供的 HTML 上“撒上” Javascript 片段。像 jQuery 和 Prototype 这样的工具呈现了,它们暗藏了 Web API 的复杂度,打消了浏览器之间的差别。光阴荏苒,科技公司的规模在不断扩大,并且因为我的项目和开发团队的增长,在模板中退出更多的业务逻辑是十分广泛的。编写的服务器代码,将解决后的数据传输到服务器模板语言中。模板经常调演变成业务逻辑的“混合体”来拜访全局变量。因为像 SQL 注入这样的攻打曾经司空见惯,因而平安问题也越来越突出。最终,论文《Ajax:Web 利用的新办法》(Ajax: A New Approach to Web Applications)为咱们带来了 Ajax 技术。当初你用 Ajax 技术能够做的新事件就是用异步形式更新页面,而不再是以同步的形式来更新页面。这种模式被第一批大型客户端应用程序所推广,如谷歌地图和谷歌文档。起初,咱们开始看到 Web 散发对桌面格调的软件的影响力。与在商店里购买光盘的软件相比,这是一个重大的提高。 ...

October 25, 2022 · 2 min · jiezi

关于javascript:ts-取对象所有键类型组成的联合类型

keyof 取对象中的 key 为类型 type Person = {id: number; name: string;age: number}type P1 = keyof Person; // 'id' | 'name' | 'age'获取对象所有属性的类型 type P2 = Person[keyof Person]; // number | string

October 25, 2022 · 1 min · jiezi

关于javascript:最新js解密方法

废话不多说,代码敏感,只上局部。 源代码(function() { let _0xce6384; try { const _0x20cdc4 = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');'); _0xce6384 = _0x20cdc4(); } catch (_0x46317e) { _0xce6384 = window; } const _0x348798 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; _0xce6384['atob'] || (_0xce6384['atob'] = function(_0x4e070f) { const _0x1d59b8 = String(_0x4e070f)['replace'](/=+$/, ''); let _0x1dc99e = ''; for (let _0x3327e6 = 0x0, _0x169c0b, _0x52066b, _0x4f42b7 = 0x0; _0x52066b = _0x1d59b8['charAt'](_0x4f42b7++); ~_0x52066b && (_0x169c0b = _0x3327e6 % 0x4 ? _0x169c0b * 0x40 + _0x52066b : _0x52066b, _0x3327e6++ % 0x4) ? _0x1dc99e += String['fromCharCode'](0xff & _0x169c0b >> (-0x2 * _0x3327e6 & 0x6)) : 0x0) { _0x52066b = _0x348798['indexOf'](_0x52066b); } return _0x1dc99e; });}());先在JS加密工具站初步解一下码,太简单的也能够找客服人工解码(function() { let _0xce6384; try { const _0x20cdc4 = Function('return (function() ' + '{}.constructor("return this")( )' + ');'); _0xce6384 = _0x20cdc4(); } catch (_0x46317e) { _0xce6384 = window; } const _0x348798 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; _0xce6384['atob'] || (_0xce6384['atob'] = function(_0x4e070f) { const _0x1d59b8 = String(_0x4e070f)['replace'](/=+$/, ''); let _0x1dc99e = ''; for (let _0x3327e6 = 0x0, _0x169c0b, _0x52066b, _0x4f42b7 = 0x0; _0x52066b = _0x1d59b8['charAt'](_0x4f42b7++); ~_0x52066b && (_0x169c0b = _0x3327e6 % 0x4 ? _0x169c0b * 0x40 + _0x52066b : _0x52066b, _0x3327e6++ % 0x4) ? _0x1dc99e += String['fromCharCode'](0xff & _0x169c0b >> (-0x2 * _0x3327e6 & 0x6)) : 0x0) { _0x52066b = _0x348798['indexOf'](_0x52066b); } return _0x1dc99e; });}());问题点这个JS加密在NodeJs环境下运行会报错,window对象找不到,这个比拟好解决,间接var window = global;就行了,随后又报错,atob办法找不到。 ...

October 25, 2022 · 2 min · jiezi

关于javascript:二叉树中的小钢炮二叉查找树

原文参考我的公众号文章 梳理一波「二叉树 二叉树二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,别离是左子节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只有左子节点,有的节点只有右子节点。根节点:无父节点的节点叶子结点:无子节点的节点兄弟节点:有雷同根节点的节点对于“树”,还有三个比拟类似的概念:高度(Height)、深度(Depth)、层(Level)。它们的定义是这样的: 二叉查找(排序)树也叫二叉搜寻树,反对动态数据汇合的疾速插入、删除、查找操作;有序二叉树:在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值;是一颗二叉树,每个节点最多两个子结点,即每一层最多 2^(level - 1)个节点;树结构/** 树节点 */class BinaryNode { constructor(data) { this.data = data; //存储的数据 this.left = null; //左节点 this.right = null; //右节点 this.level = 1; //所属层级 this.count = 1; //反复数据次数 this.isDeleted = false; //是否被删除 }}/** 二叉树 */class BinarySearchTree { constructor() { this.root = null; //根节点:在第一次insert时会被赋予值 this.nodes = 0; //节点数 this.list = []; //遍历二叉树时长期存储数据的数组 }}插入节点插入规定:新结点值与以后插入地位(从根节点开始)的节点值进行比拟小于父节点值:插在父节点左节点上;大于父节点值:插在父节点右节点上;等于父节点值:父节点 count++;(这种形式看状况,如果结点还有其余数据而非只有一个 data,那能够。否则应合并到上一种状况,合并到右节点上)插入过程可减少被插入的结点所属 level 的保护!// class BinarySearchTree { ... } /** * 插入数据 * @param {*} data 结点的值 */ insert(data) { this.nodes++; // 递归插入 // let newNode = new BinaryNode(data); // if (this.root === null) { // this.root = newNode; // } else { // this._insert(this.root, newNode); // } // 循环插入 this.loopInsert(data) } /** * 递归的形式插入节点:新结点值与以后插入地位(从根节点开始)的节点值进行比拟 * 小于根节点值:插在根节点左节点上; * 大于等于根节点值:插在根节点右节点上; * 减少结点所属level的保护! * @param {*} theRootNode 被插入地位节点(从根节点开始) * @param {*} newNode 新插入的节点 */ _sameValAsBigInsert(theRootNode, newNode) { newNode.level++; //从根登程,每执行一次_sameValAsBigInsert,层级便主动+1 if (theRootNode.data > newNode.data) { if (theRootNode.left === null) { theRootNode.left = newNode; } else { // 阐明不是叶子结点,持续向上层插入判断 this._sameValAsBigInsert(theRootNode.left, newNode); } } else { if (theRootNode.right === null) { theRootNode.right = newNode; } else { // 阐明不是叶子结点,持续向上层插入判断 this._sameValAsBigInsert(theRootNode.right, newNode); } } } /** * !!!值雷同,则合并到以后根节点 * @param {*} theRootNode 被插入地位节点(从根节点开始) * @param {*} newNode 新插入的节点 */ _sameValMergeInsert(theRootNode, newNode) { newNode.level++; //从根登程,每执行一次_sameValMergeInsert,层级便主动+1 if (theRootNode.data > newNode.data) { if (theRootNode.left === null) { theRootNode.left = newNode; } else { // 阐明不是叶子结点,持续向上层插入判断 this._sameValMergeInsert(theRootNode.left, newNode); } } else if (theRootNode.data < newNode.data) { if (theRootNode.right === null) { theRootNode.right = newNode; } else { // 阐明不是叶子结点,持续向上层插入判断 this._sameValMergeInsert(theRootNode.right, newNode); } } else { theRootNode.count++; // 值雷同,则合并到以后根节点 } } /** * 循环的形式插入 * @param {*} data * @returns */ loopInsert(data) { if (this.root == null) { this.root = new BinaryNode(data); return; } let p = this.root; while (p != null) { if (data > p.data) { if (p.right == null) { p.right = new BinaryNode(data); return; } p = p.right; } else { // data <= p.data if (p.left == null) { p.left = new BinaryNode(data); return; } p = p.left; } } } ...

October 25, 2022 · 3 min · jiezi

关于javascript:解决项目中两个值一直相等的问题

有任何问题都能够留言征询。 问题切换实例名称的下拉选项后,应该会更新缓存中的实例名称的值。 但发现不管怎么切换,实例名称的值都不会扭转。 页面页面是上面这样的。 切换以后实例的下拉选项,会更新缓存中的inst和instName的值。 有问题可群征询:https://public-1253796280.cos... 代码单从代码逻辑来看,是看不出什么问题的。 因为代码逻辑还是比较简单清晰,这里没有什么简单的判断。 奇怪的问题是,每次切换后,都能进入if条件外面,但instName和inst的值始终没更新。 详情 请查看原文。

October 25, 2022 · 1 min · jiezi