关于javascript:DOM操作

DOM一、获取标签罕用: document.querySelector()document.querySelectorAll()依据节点获取: 父.children父.firstElementChild父.lastElementChild标签.previousElementSubling标签.nextElementSibling子.parentElement不罕用: document.getElementById() document.getElementsByTagName()document.getElementsByClassName()document.getElementsByName()二、操作标签创立标签: document.createElement()插入标签: 父.appendChild(子)父.insertBefore(新, 旧)替换标签: 父.replaceChild(新, 旧)删除标签: 父.removeChild(子)复制标签: 标签.cloneNode(true)标签属性: 标签.getAttribute(属性名)标签.setAttribute(属性名, 属性值)标签.removeAttribute(属性名)类名操作: 标签.className // 能够获取/能够赋值标签.classListclassList的办法: add()remove()has()toggle()内容操作: 标签.innerText标签.innerHTML表单标签.value款式操作: 获取款式: getComputedStyle(标签) // 获取到所有款式组成的对象设置款式: 标签.style.css键 = css的值获取标签名: 标签.tagName获取标签大小: 蕴含边框的: 标签.offsetWidth标签.offsetHeight不蕴含边框的: 标签.clientWidth标签.clientHeight获取标签地位: 标签.offsetLeft标签.offsetTop获取标签边框厚度: 标签.clientLeft标签.clientTop

February 23, 2023 · 1 min · jiezi

关于javascript:事件

事件用于解决用在网页中的行为 语法: 标签.on事件类型 = 一段函数代码/函数名一、事件类型1、鼠标类型clickdblclickcontextmenumouseover mouseentermouseout mouseleavemousedown mouseupmousemovemousewheel2、键盘类keydown keyup keypress3、表单类focusblurchangeinputsubmitsubmit的事件源是form标签,点击提交按钮的时候会触发 4、window窗口类loadscrollresize二、事件流概念:事件从开始触发到执行完结的整个过程 3个阶段: 捕捉阶段:从window向内找指标元素的过程指标阶段:找到指标元素后,执行的他的事件函数冒泡阶段:从指标元素向外到window来到的过程留神:父标签的事件会在子标签事件的冒泡阶段执行 三、事件侦听器概念:另外一种事件绑定形式 语法: 标签.addEventListener(事件类型, 事件函数, 是否在捕捉阶段执行)长处: 能够让以后事件在子标签事件的捕捉阶段执行能够让标签绑定多个同类型的事件,并一起登程事件解绑: 什么叫解绑?将事件删除掉 为什么解绑?因为事件绑定后会始终保留在内存中,节约了内存空间 如何解绑? on事件类型绑定的事件,解绑形式:标签.on类型 = null 事件侦听器绑定的事件,解绑形式:标签.removeEventListener(事件类型, 绑定的事件函数) 留神:当事件侦听器绑定的函数是匿名函数就无奈解绑了 四、事件对象概念:事件函数中零碎内置了一个用于记录事件所有信息的对象 获取事件对象: 标签.on类型 = function(e) { e就是事件对象}标签.on类型 = function() { window.event是事件对象}作用: 获取鼠标按键码 - 事件对象.button 0示意左键;1示意滚轮;2示意右键 获取事件类型 - 事件对象.type获取键盘按键码 - 事件对象.keyCode 回车键:13 空格键:32 上下左右:38 40 37 39 组合键:返回布尔值,示意这几个键是否跟其余键组合应用了 事件对象.shiftKey 事件对象.altKey 事件对象.ctrlKey 获取鼠标地位 绝对事件源的地位 事件对象.offsetX事件对象.offsetY绝对以后浏览器可视窗口 事件对象.clientX事件对象.clientY绝对于整个网页文档 事件对象.pageX事件对象.pageY获取精准的事件指标元素 事件对象.target阻止事件冒泡 事件对象.stopPropagation()事件对象.cancelBubble = true阻止默认行为 ...

February 23, 2023 · 1 min · jiezi

关于javascript:Spartacus-使用-Command-设计模式之后对以前-Connector-实现的重用

Command 设计模式提供了一种弱小且简化的形式来解决状态(换句话说,加载和缓存),并针对后端系统执行操作,比方 Spartacus Storefront B2B 场景下设置 Payment Method,即切换下图所示的 Radio button,对应的后盾实现就通过 Command 形式触发一个发送到 Commerce Cloud 后盾的 HTTP PUT OCC 申请。 Command 示意一种能够更改零碎状态的操作,通常是通过向后端收回 REST 调用来实现。想想上图 Spartacus 的例子,如何找到该 Command 对应的 OCC 申请精确的发动地位?还有 Connector 参加吗? 把鼠标移到 network 标签页的 Initiator 栏,查看函数调用列表。乍一看,咱们在 Spartacus B2B Storefront 发动的 OCC API 申请里,看不到 connector 的参加了? checkoutPaymentTypeFacade 定义在 checkout/b2b 的 root 文件夹之下: core 文件夹下的 service 实现了这个 facade: 通过存储 CommandService.create 工厂办法调用的后果,能够将命令实例定义为类的属性。 创立命令的工厂函数里,具备以下参数: (1) 调度命令的函数(通常是对连接器的调用)(2) 一个选项对象(通常用于指定策略) 上图 command 创立时,传入的调度函数第 60 行,就是 paymentTypeConnector 的连接器调用: ...

February 23, 2023 · 1 min · jiezi

关于javascript:关于错误消息-RangeError-Maximum-call-stack-size-exceeded-at-XXX

谬误音讯:RangeError: Maximum call stack size exceeded at ConnectableSubscriber.error 执行 Angular 开发的 Spartacus Storefront 时遇到。 RangeError: Maximum call stack size exceeded 当函数调用超出调用堆栈大小时抛出。 这可能是因为以下起因造成的: 函数调用太多。解决递归的问题,例如递归函数中短少根本状况以进行有限调用本身。这个谬误通常是由递归调用导致的。递归调用可能会导致堆栈溢出。在这种状况下,须要找到造成递归调用的代码并找到一种办法来防止递归调用。首先,能够应用调试工具(例如浏览器开发工具)查看抛出谬误的代码。而后,您能够思考上面几种解决方案: (1) 防止对数据进行反复订阅。如果您在多个中央订阅了同一个数据源,则可能会产生递归调用。 (2) 应用 takeUntil 操作符,以在察看的某个时刻终止订阅。 (3) 应用可察看的错误处理机制(例如 catchError),以在产生谬误时终止订阅。 上面这段代码能够轻易重现该谬误。 RangeError: Maximum call stack size exceeded at 浏览器里执行的后果: 超出范围的操作。如果因为过多的函数调用或变量而产生此谬误,则应尽可能减少这些谬误。还应查看并防止任何超出范围的操作。 能够应用浏览器控制台和开发人员工具查看这些问题。此外,如果开发人员不小心两次导入/嵌入雷同的 JavaScript 文件,也可能会遇到这种状况。 要解决此问题,请查看 JS 文件中的导入。此时开发人员会发现浏览器的资源选项卡很有用。 在旧版浏览器中,当尝试将太多参数传递给浏览器无奈解决的函数时,也会呈现 RangeError。

February 23, 2023 · 1 min · jiezi

关于javascript:uniapp-canvas绘图

需要,uniapp微信小程序将页面某一部分保留为图片能够分享,下载。实现这一性能须要应用canvas绘图,背景图为网络图片,两头有个原型的二维码,图片格式为base64,还有一些其余的文字。最重要的是:无论是网络图片还是base64格局的,拿到一个长期地址!!!办法参考此文章注:base64能够间接canvas绘制,然而真机不显示!!!模拟器失常! //绘制canvas <canvas style="width: 280px;height:380px" canvas-id="activityCode" ></canvas>//上面两个办法是将base64图片转换成长期地址function removeSave(FILE_BASE_NAME = 'tmp_base64src', format = 'jpg') { return new Promise((resolve) => { // 把文件删除后再写进,避免超过最大范畴而无奈写入 const fsm = uni.getFileSystemManager(); //文件管理器 const FILE_BASE_NAME = 'tmp_base64src'; const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`; fsm.unlink({ filePath: filePath, success(res) { console.log('文件删除胜利'); resolve(true); }, fail(e) { console.log('readdir文件删除失败:', e); resolve(true); } }); })}function base64ToSave(base64data: any, FILE_BASE_NAME = 'tmp_base64src') { const fsm = uni.getFileSystemManager(); return new Promise(async (resolve, reject) => { //format这个跟base64数据的结尾对应 const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || []; if (!format) { reject(new Error('ERROR_BASE64SRC_PARSE')); } await removeSave(FILE_BASE_NAME, format); const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`; //const buffer = wx.base64ToArrayBuffer(bodyData); fsm.writeFile({ filePath, data: bodyData, //data: base64data.split(";base64,")[1], encoding: 'base64', success() { resolve(filePath); }, fail() { reject(new Error('ERROR_BASE64SRC_WRITE')); }, }); });}//开始绘制//1.背景网络图片function drawCanvas() { const ctx = uni.createCanvasContext('activityCode') uni.getImageInfo({ src: '****', success:res=>{ //背景图 ctx.drawImage(res.path, 0, 0, 140, 190); //插入图片 //绘制文案 ctx.setFontSize(9) ctx.fillStyle='#FFFFFF' ctx.setTextAlign('center') ctx.fillText('***', 70, 40) //绘制一个原型的图片 circleImg(ctx) ctx.draw() }, fail:res=>{ console.log(`缓存失败:${res.errMsg}`); } }) }//2.绘制圆形图片function circleImg(ctx) { ctx.beginPath() ctx.arc(70, 100, 34, 0, 2 * Math.PI) ctx.setFillStyle('#ffffff') ctx.fill() ctx.clip() //url就是上方保留的base64长期地址 ctx.drawImage(url, 40, 70, 60, 60); }//保留图片function saveImg() { uni.canvasToTempFilePath({ canvasId: 'activityCode', success: function(res) { uni.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: function () { uni.showToast({ title: '保留胜利', icon: 'success' }) }, fail: function () { uni.showToast({ title: '保留失败', icon: 'none' }) } }) } })}注:保留图片的时候最好不要写尺寸,否则会影响生成图片的清晰度!效果图:本文参加了SegmentFault 思否写作挑战赛,欢送正在浏览的你也退出。 ...

February 23, 2023 · 1 min · jiezi

关于javascript:varlet的区别

var申明晋升console.log(name) //土豆var name = '土豆';应用var申明的变量会主动晋升到函数作用域的顶部 function foo(){ console.log(name); var name = "土豆";}foo() //undefined//等价于function foo(){ var name; console.log(name); name = "土豆";}foo(); //undefinedconsole.log(name) //ReferenceError name没有被定义let name ="土豆";而应用let定义的name不会被晋升,报出ReferenceError的谬误; var能够反复申明同一个变量var name = "番茄";var name = "西瓜";var name = "土豆";console.log(name);//土豆而应用let反复申明同一个变量会报错。 var name = "土豆";let name = "土豆";console.log(name);//'name' has already been declaredlet name = "土豆";var name = "土豆";console.log(name);//Cannot redeclare block-scoped variable 'name'.var全局申明var name = "土豆";console.log(window.name);//土豆let age = "24";console.log(window.age); //undefined应用var定义的变量会被挂载到window上,成为window对象的属性,而应用let不会。 作用域if(true){ var name = "土豆"; console.log(name);}console.log(name);//土豆//土豆if(true){ let age = 24; console.log(age);}console.log(age);//24//undefined应用var申明的范畴是函数作用域,应用let申明的范畴是块作用域。 ...

February 22, 2023 · 1 min · jiezi

关于javascript:HHDESK文件夹比较功能

在做我的项目的时候,往往会产生很多版本,以及多个相似的文件夹。工夫久了记不清更改内容便是常事。 HHDESK有个性能,能够简略快捷的帮你“找不同” 1.文件夹的初步比拟在HHDESK首页,别离抉择须要分别的文件夹能够很清晰的看到,右边多了一个CSS-春节的文件夹,因而立即想起来,这个文件是之前保留的春节版。为了避免再次遗记,间接进行重命名实现,整个过程只须要2分钟不到,且齐全没有难度。 2.文件夹内容比照抉择点击目录比照,会主动呈现方才选定的2个文件夹。 点击比拟,会将雷同、右侧独有、左侧独有、不同文件别离演绎显示,高深莫测。 也可依据本身需要,勾选各个选项,“找不同”或者“找雷同”之类。也能够独自筛选文件格式,比如说,只想筛查批改过的html,就将后缀退出筛选即可。

February 22, 2023 · 1 min · jiezi

关于javascript:关于微前端你想知道的都在这

更多请关注微前端专题https://codeteenager.github.io/Micro-Frontends/介绍微前端官网:https://micro-frontends.org/问题:如何实现多个利用之间的资源共享? 之前比拟多的解决形式是npm包模式抽离和援用,比方多个利用我的项目之间,可能有某业务逻辑模块或其余是可复用的,便抽离进去以npm包的模式进行治理和应用。但这样却带来了以下几个问题: 公布效率低下:如果须要迭代npm包内的逻辑业务,须要先公布npm包之后,再每个应用了该npm包的利用都更新一次npm包版本,再各自构建公布一次,过程繁琐。如果波及到的利用更多的话,破费的人力和精力就更多了。多团队合作容易不标准:蕴含通用模块的npm包作为共享资产,每个人领有它,但在实践中,这通常意味着没有人领有它,它很快就会充斥芜杂的格调不统一的代码,没有明确的约定或技术愿景。这些问题让咱们意识到,扩大前端开发规模以便多个团队能够同时开发一个大型且简单的产品是一个重要但又辣手的难题。因而,早在2016年,微前端概念诞生了。 微前端概念“微前端”一词最早于 2016 年底在 ThoughtWorks Technology Radar 中提出,它将后端的微服务概念扩大到了前端世界。微服务是服务端提出的一个有界上下文、松耦合的架构模式,具体是将利用的服务端拆分成更小的微服务,这些微服务都能独立运行,采纳轻量级的通信形式(比方 HTTP )。 微前端概念的提出能够借助上面的 Web 利用架构模式演变图来了解。 最原始的架构模式是单体 Web 利用,整个利用由一个团队来负责开发。 随着技术的倒退,开发职责开始细分,一个我的项目的负责团队会分化成前端团队和后端团队,即呈现了前后端拆散的架构形式。 随着我的项目变得越来越简单,先感触到压力的是后端,于是微服务的架构模式开始呈现。 随着前端运行环境进一步晋升,Web 利用的发展趋势越来越偏向于富利用,即在浏览器端集成更多的性能,前端层的代码量以及业务逻辑也开始快速增长,从而变得越来越难以保护。于是引入了微服务的架构思维,将网站或 Web 利用依照业务拆分成粒度更小的微利用,由独立的团队负责开发。 从图上能够看出,微前端、微服务这些架构模式的演变趋势就是一直地将逻辑进行拆分,从而升高我的项目复杂度,晋升可维护性和可复用性。 所以说微前端是一种相似于微服务的架构,是一种由独立交付的多个前端利用组成整体的架构格调,将前端利用分解成一些更小、更简略的可能独立开发、测试、部署的利用,而在用户看来依然是内聚的单个产品。有一个基座利用(主利用),来治理各个子利用的加载和卸载。 微前端的利用场景从下面的演变过程能够看出,微前端架构比拟适宜大型的 Web 利用,常见的有以下 3 种模式。 公司外部的平台零碎。这些零碎之间存在肯定的相关性,用户在应用过程中会波及跨零碎的操作,频繁地页面跳转或零碎切换将导致操作效率低下。而且,在多个独立零碎外部可能会开发一些反复度很高的性能,比方用户治理,这些反复的性能会导致开发成本和用户应用成本上升。大型单页利用。这类利用的特点是零碎体量较大,导致在日常调试开发的时候须要消耗较多工夫,重大影响到开发体验和效率。而且随着业务上的性能降级,我的项目体积还会一直增大,如果我的项目要进行架构降级的话革新老本会很高。对已有零碎的兼容和扩大。比方一些我的项目应用的是老旧的技术,应用微前端之后,对于新性能的开发能够应用新的技术框架,这样防止了颠覆重构,也防止了持续基于过期的技术进行开发。微前端的架构模式微前端架构按集成微利用的地位不同,次要能够分为 2 类: 在服务端集成微利用,比方通过 Nginx 代理转发;在浏览器集成微利用,比方应用 Web Components 的自定义元素性能。服务端集成服务端集成罕用的形式是通过反向代理,在服务端进行路由转发,即通过门路匹配将不同申请转发到对应的微利用。这种架构形式实现起来比拟容易,革新的工作量也比拟小,因为只是将不同的 Web 利用拼凑在一起,严格地说并不能算是一个残缺的 Web 利用。当用户从一个微利用跳转到另一个微利用时,往往须要刷新页面从新加载资源。 这种代理转发的形式和间接跳转到对应的 Web 利用相比具备一个劣势,那就是不同利用之间的通信问题变得简略了,因为在同一个域下,所以能够共享 localstorage、cookie 这些数据。譬如每个微利用都须要身份认证信息 token,那么只须要登录后将 token 信息写入 localstorage,后续所有的微利用就都能够应用了,不用再从新登录或者应用其余形式传递登录信息。 浏览器集成浏览器集成也称运行时集成,常见的形式有以下 3 种。 iframe。通过 iframe 的形式将不同的微利用集成到主利用中,实现成本低,但款式、兼容性方面存在肯定问题,比方沙箱属性 sandbox 的某些值在 IE 下不反对。前端路由。每个微利用暴露出渲染函数,主利用在启动时加载各个微利用的主模块,之后依据路由规定渲染相应的微利用。尽管实现形式比拟灵便,但有肯定的革新老本。Web Components。基于原生的自定义元素来加载不同微利用,借助 Shadow DOM 实现隔离,革新老本比拟大。这也是一种十分热门的集成形式,代表性的框架有 single-spa 以及基于它批改的乾坤。 ...

February 22, 2023 · 4 min · jiezi

关于javascript:如何优雅的实现网页多主题风格换肤功能

海阔凭鱼跃,天高任鸟飞。好久不见!我是猫力Molly 对于网页换肤,例如最常见的深色、浅色格调曾经是很常见的一个需要了。始终以来也有很多的实现计划,这里我次要介绍一下基于 CSS variable的实现形式 简略列举下一些其它实现形式1、把不同格调款式写到不同的类名上面,通过切换类名来实现换肤 这种形式没啥显著的长处,只是单纯的实现了此需要。反而减少了css款式文件代码冗余且会造成大量反复代码,款式代码不利于拓展保护,且开发效率低下 2、实现多套主题款式文件,通过 link 标签动静加载不同的款式文件 这种形式的长处大略是做到了按需加载吧,但同时也造成了须要拷贝大量反复代码来独自批改,也算是做到了款式隔离,相比上一种形式稍稍进步了一点可维护性吧 在多个款式文件切换的时候,可能会有加载提早。这时候能够思考应用 alternate 来解决 3、通过less或sass的变量形式实现 这种形式咱们能够将所有格调变量抽离进去,在款式代码中间接应用该变量,是一种比拟举荐的形式。极大进步了代码的拓展性和维护性 CSS variable的实现形式 如图所示,目前支流浏览器都曾经反对css variable,咱们只管放心使用 CSS variable 容许咱们在 css 外面申明变量,在变量前加上两根小横线即可(--) body { --foo: #000; --bar: #fff;}须要留神的是css vars变量申明,辨别大小写--foo 与 --Foo 是两个不同的变量 var() 函数应用var()函数来读取变量 p{ color:var(--foo)}var()函数反对第二个参数,用于示意变量的默认值,如果变量值不存在,则以默认值为准 p{ color:var(--fooo, #ccc)}对于var()函数此处不做过多赘述,详情请查阅官网文档 计划落地大抵思路:不论深色或是浅色格调,咱们都能够把它视作一个个主题。把每个主题的色彩值、盒子宽高、图片地址等抽离为一个字典对象构造。一个主题对应一个配置文件,再通过切换配置文件来实现主题格调的变动 一、和UI设计师沟通好各主题的色阶一个主题对应一份配置文件,所以咱们须要提前和UI设计师沟通好各主题对应的色阶,字号,一些通用款式规定等 css vars变量名称是不变的,变量值随着主题的切换而产生扭转 我的UI共事应用的是 figma,而后我发现 figma 右侧的信息栏外面有色彩编号,正好能够应用这个来当做变量名称。在编码阶段,看到这个编号,就晓得用什么变量名了,十分不便。 如果你的UI共事应用的是别的设计工具,最好也是提前约定好变量名,使其大家都不便 二、将各主题色阶抽离为一个字典对象dark.js export default { '--grey900': '#EBEEF5', '--grey600': '#A7ABC0', '--grey500': '#72768D', '--grey400': '#5D6177', '--grey300': '#404759', '--grey200': '#2C323E', '--grey100': '#282B32', '--grey50': '#171B22', '--grey0': '#222730', ...} white.js ...

February 22, 2023 · 1 min · jiezi

关于javascript:深入浅出-JS系列-你不知道的数据类型一

1.原始类型的办法2.数字类型3.字符串4.数组5.数组办法6.Iterable object(可迭代对象)7.Map and Set(映射和汇合)8.WeakMap and WeakSet(弱映射和弱汇合)9.Object.keys,values,entries10.解构赋值11.日期和工夫12.JSON 办法,toJSON 原始类型的办法

February 21, 2023 · 1 min · jiezi

关于javascript:箭头函数详解

定义箭头函数ES6容许应用箭头 => 定义函数 let v = 100// 箭头函数let f = a => v;// 等同于let f2 = function (a){ return v}// 等同于let f3 = (a) => { return v }console.log(f()); // 100console.log(f2()); // 100console.log(f3()); // 100 箭头函数参数箭头函数中,应用圆括号()代表参数的局部 // 无参数let a1 = () => 5;// 等同于let a2 = function () {return 5}// 有参数let a3 = (num1,num2) => num1 + num2// 等同于let a4 = function (num1,num2) { return num1 + num2}如果箭头函数中的代码块为一句话,能够省略大括号。如果箭头函数中的代码块多于一句,须要应用大括号括起来,应用return能够返回数据。 ...

February 21, 2023 · 2 min · jiezi

关于javascript:万物皆可集成资源包低代码集成系列一网打尽

如何花最短的工夫、用起码的老本解决客户的企业级利用定制问题? 如何满足数据库集成、Web API集成、第三方软件集成等需要,在现在万物皆可盘的当下,低代码如何用积木大玩具的形式疾速构建各种利用,实现“万物皆可集成”? 如果你也面临以上两个问题,是时候体验低代码技术带给你的便捷与高效了。 这里咱们这里整顿了8个不同平台与低代码的集成,从泛微、用友到WebAPI、微信小程序,你关注的就在这里。全文中提到的内容合集可在文末扫码支付。 低代码对接泛微e-cology泛微e-cology作为面向大中型企业的平台型协同办公自动化零碎,它的标准化性能和软件的易用性,大大晋升了大中型企业外部治理的效率。但随着企业业务的疾速倒退,如何晋升平台产品的二次开发效率,保障性能的疾速迭代,升高企业应用的开发成本,成为每一位定制化开发人员须要解决的事件。 本集成计划介绍了e-cology配置平安程序,集成登录与菜单设置与单点登录的实现,从搭建到公布,一次带你解决。 低代码开释用友U8+深度价值企业工作流程差别大,软件标准化通用性能并不能满足企业定制化需要;同时挪动端应用需要增大,而用友U8+次要是以桌面端利用为主,短少挪动端解决方案。 在这里活字格为大家提供了用友U8+客开解决方案,该低代码开发套包,由活字格低代码开发平台和用友 U8+深度集成套件形成。集成内容包含:数据集成、C/S页面嵌入、用户集成。 依据企业定制化需要,疾速构建出集成至用友 U8+CS 门户、BS 门户的功能模块,也能通过 APP、微信或钉钉等平台进一步加强零碎的挪动端能力相比。应用活字格做客开,无需把握 VB 语言,技术门槛更低,开发成本更省,交付速度更快。 该系列从零碎对接、数据拓展、数据交融三大方面,深度展现低代码与用友U8+集成,让开发更加容易。 低代码对接企企云实现数据集成企业上云作为数字化转型的重要渠道,逐步成为越来越多企业的抉择。如何将云上业务与低代码开发的新零碎做整合,是很多敌人关注的外围。企企云作为一款成熟的企业云服务,领有很多的用户,如何与企企云实现数据集成,感兴趣的敌人不要错过。 低代码如何不成为数据孤岛企业倒退到肯定阶段,必然会追随时代倒退进行信息化建设。而信息化建设的不均衡,催生了“数据孤岛”景象的产生。企业外部间的数据不足关联性,无奈彼此兼容。 而活字格作为一款开放性十足的低代码平台,当然也少不了接口的对接。因为任何零碎对接活字格都有可能。这部分咱们为大家展现如何调用活字格的接口,来实现活字格自定义接口的对接。 低代码通过Web API对接百度AI服务数据录入作为常见工作场景,根底数据的精确与保护是要害。身份证、发票、驾驶证、银行卡等进行数据录入,手工操作易错切工作简单。过百度AI文字辨认性能解决以上问题,文字辨认准确性高、稳定性强、简略易用,而且实用于多种场景,同时能够节约录入工夫,加重工作量,进步工作效率。 活字格与第三方软硬件的高集成度、高灵活性、高效都使它与第三方服务有极强适配性。 为了不便大家应用,咱们在该计划中将百度AI智能辨认封装成插件,大家能够间接下载。(具体内容见计划内下载地址) 除了上述集成计划该系列还蕴含微信、阿里物流等集成内容,万物集成系列总有你感兴趣的。 扫码回复“万物集成”,获取内容!

February 21, 2023 · 1 min · jiezi

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

实现call办法call做了什么: 将函数设为对象的属性执行和删除这个函数指定this到函数并传入给定参数执行函数如果不传入参数,默认指向为 window// 模仿 call bar.mycall(null);//实现一个call办法:// 原理:利用 context.xxx = self obj.xx = func-->obj.xx()Function.prototype.myCall = function(context = window, ...args) { if (typeof this !== "function") { throw new Error('type error') } // this-->func context--> obj args--> 传递过去的参数 // 在context上加一个惟一值不影响context上的属性 let key = Symbol('key') context[key] = this; // context为调用的上下文,this此处为函数,将这个函数作为context的办法 // let args = [...arguments].slice(1) //第一个参数为obj所以删除,伪数组转为数组 // 绑定参数 并执行函数 let result = context[key](...args); // 革除定义的this 不删除会导致context属性越来越多 delete context[key]; // 返回后果 return result;};//用法:f.call(obj,arg1)function f(a,b){ console.log(a+b) console.log(this.name)}let obj={ name:1}f.myCall(obj,1,2) //否则this指向window实现类数组转化为数组类数组转换为数组的办法有这样几种: ...

February 21, 2023 · 8 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('李四'); ...

February 21, 2023 · 2 min · jiezi

关于javascript:源码库细数-Vue3-的实例方法和属性背后的故事

上一章咱们翻看了Vue3的源码的createApp的实现,并实现了一个简略的createApp; 在翻看的过程中咱们发现了Vue3的createApp的实现中,有很多的办法,比方mount、provide、use、component、directive、mixin等等; 而这些办法在官网文档中都是有提及的,明天咱们就来扒一扒Vue3 API 参考 -> 利用实例背地的实现。 大家好,这里是田八的【源码&库】系列,Vue3的源码浏览打算,Vue3的源码浏览打算不出意外每周一更,欢送大家关注。 如果想一起交换的话,能够点击这里一起独特交换成长 系列章节:【源码&库】跟着 Vue3 学习前端模块化【源码&库】在调用 createApp 时,Vue 为咱们做了那些工作?首发在掘金,所以链接都是掘金的,无任何引流的意思。 初窥咱们先来看看官网上的Vue3的API的利用实例的列表: 上一章咱们曾经实现了createApp的办法,同时也晓得了createApp的办法返回的是一个app对象; 列表中从mount开始的办法都是app对象的办法,而mount在上一章中咱们也曾经实现了,所以咱们明天就看前面的办法。 同时列表的前面还有一些实例属性,这些也是在咱们明天的学习工作中的; 接下来的学习就是边跟着官网文档的介绍,边看源码的实现,来相熟这些办法和属性; 在上一节中咱们理解到了,createApp返回的app对象是在createAppAPI中创立的,咱们先来回顾一下createAppAPI的实现: let uid$1 = 0;function createAppAPI(render, hydrate) { return function createApp(rootComponent, rootProps = null) { // ... const context = createAppContext(); const installedPlugins = new Set(); let isMounted = false; const app = (context.app = { _uid: uid$1++, _component: rootComponent, _props: rootProps, _container: null, _context: context, _instance: null, version, get config() { return context.config; }, set config(v) { if ((process.env.NODE_ENV !== 'production')) { warn(`app.config cannot be replaced. Modify individual options instead.`); } }, use(plugin, ...options) { // ... return app; }, mixin(mixin) { // ... return app; }, component(name, component) { // ... return app; }, directive(name, directive) { // ... return app; }, mount(rootContainer, isHydrate, isSVG) { // ... }, unmount() { // ... }, provide(key, value) { // ... return app; } }); return app; };}通过下面的代码能够看到的,官网介绍的app实例办法是一个也不少都在这; ...

February 21, 2023 · 6 min · jiezi

关于javascript:我所了解的-JavsScript

引言JavaScript 是每个程序员无奈回避的编程语言。它依靠浏览器的反对,牢牢占据着前端编程的市场,又凭借nodejs,在服务端编程也占有一席之地。很多程序员对它是爱恨交加,爱它的灵便不便,恨它过于灵便的类型转换,简单的包治理等等。明天,我想以一个 非JavaScript程序员的角度,来聊聊我所理解的 JavaScript,作为这些年来对它重复浅尝辄止的一个总结。 网页最早接触到 JavaScript,是十多年前的QQ空间。过后的QQ空间是一个粗劣的网页,能够由用户自行设置,难看的打扮须要用Q币购买,或者充值黄钻能力取得。而很多人不想充钱,又想让本人的空间不那么一般,于是有人发现间接在地址栏输出一段神秘代码,就能获取打扮。那时网上最常被搜寻的就是“QQ空间打扮代码”。具体的原理我也没搞清,到底是开发人员成心留的收费打扮,还是被人找到了后门。总之,起初我在晓得,那些代码里有些就是 JavaScript。 工夫再往前追溯,到互联网刚刚呈现的年代,最早的网络只有 HTML,毕竟网速和显示设施的限度摆在那里,人们对于能看到纯文字的网页曾经很惊奇了。起初慢慢地人民大众对于美好生活的谋求进步了,相应地网页也要有更丰富多彩的成果。于是有了 CSS款式,再起初,人们想在浏览器里运行代码,换句话说,在用户的设施上间接运行通用的代码。于是呈现了各种备选项,比方 Java 等等。最初是网景公司推出的 JavaScript 取得了最宽泛的采纳,这个名字据说也是为了蹭当年 Java 的热度。 为了让普通人最快速度上手,获取最多的用户,JavaScript 也有了一些非凡的适配,例如在语法上,字符串能够用单引号,也能够用双引号;表达式的开端能够加分号,也能够不加分号。这样防止了程序员因为语法上的好恶而放弃这门语言。 在性能上,提供方便的类型转换,数字、数组、函数都能够间接被 + 转换为字符串: let a = 1;a += "2" // '12'let b = [1, 2, 3];b += "2" // '1,2,32'let c = () => {};c += "2" // '() => {}2'这样的设计兴许是因为网页是须要显示给用户看的,数据被转换为字符串,是一种常常会应用到的操作。 OO忘了是在什么时候,可能是刚刚接触编程的时候吧,就经常听到人说起:“JavaScript 外面一切都是对象”,那时候搞不懂啥是对象。当初我违心将其了解为一种相似哈希表的构造,外面有一些预制的项,例如,.constructor.name 就示意这个对象是由哪个类创立的,默认是 "Object" 类。数字是 "Number" 类,false 是 "Boolean" 类。但我当初至多能够举出两个例子来反驳下面这种论断,undefined 和 null 都不是对象。 Object Oriendted(面向对象)的编程概念是由 Alan Kay 提出的,最早如同使用于 SmallTalk 语言外面。强调的是在编程时模仿事实世界的物体,比方汽车,苹果,动物等等,都能够看作是一个对象,对象之间通过消息传递来交换。JavaScript 外面有多少真正应用了面向对象的准则我不敢说,集体感觉,除了应用了 Object 这个名字,其它和面向对象的本意仿佛没有多少关系,当然,面向对象和编程里的一些其它概念一样,早已重大偏离了其本意。 ...

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

February 21, 2023 · 1 min · jiezi

关于javascript:社招中级前端笔试面试题总结

HTTP世界全览 互联网上绝大部分资源都应用 HTTP 协定传输;浏览器是 HTTP 协定里的申请方,即 User Agent;服务器是 HTTP 协定里的应答方,罕用的有 Apache 和 Nginx;CDN 位于浏览器和服务器之间,次要起到缓存减速的作用;爬虫是另一类 User Agent,是主动拜访网络资源的程序。TCP/IP 是网络世界最罕用的协定,HTTP 通常运行在 TCP/IP 提供的牢靠传输根底上DNS 域名是 IP 地址的等价代替,须要用域名解析实现到 IP 地址的映射;URI 是用来标记互联网上资源的一个名字,由“协定名 + 主机名 + 门路”形成,俗称 URL;HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,为 HTTP 套了一个平安的外壳;代理是 HTTP 传输过程中的“中转站”,能够实现缓存减速、负载平衡等性能协商缓存和强缓存的区别(1)强缓存应用强缓存策略时,如果缓存资源无效,则间接应用缓存资源,不用再向服务器发动申请。 强缓存策略能够通过两种形式来设置,别离是 http 头信息中的 Expires 属性和 Cache-Control 属性。 (1)服务器通过在响应头中增加 Expires 属性,来指定资源的过期工夫。在过期工夫以内,该资源能够被缓存应用,不用再向服务器发送申请。这个工夫是一个相对工夫,它是服务器的工夫,因而可能存在这样的问题,就是客户端的工夫和服务器端的工夫不统一,或者用户能够对客户端工夫进行批改的状况,这样就可能会影响缓存命中的后果。 (2)Expires 是 http1.0 中的形式,因为它的一些毛病,在 HTTP 1.1 中提出了一个新的头部属性就是 Cache-Control 属性,它提供了对资源的缓存的更准确的管制。它有很多不同的值, Cache-Control可设置的字段: public:设置了该字段值的资源示意能够被任何对象(包含:发送申请的客户端、代理服务器等等)缓存。这个字段值不罕用,个别还是应用max-age=来准确管制;private:设置了该字段值的资源只能被用户浏览器缓存,不容许任何代理服务器缓存。在理论开发当中,对于一些含有用户信息的HTML,通常都要设置这个字段值,防止代理服务器(CDN)缓存;no-cache:设置了该字段须要先和服务端确认返回的资源是否产生了变动,如果资源未发生变化,则间接应用缓存好的资源;no-store:设置了该字段示意禁止任何缓存,每次都会向服务端发动新的申请,拉取最新的资源;max-age=:设置缓存的最大有效期,单位为秒;s-maxage=:优先级高于max-age=,仅实用于共享缓存(CDN),优先级高于max-age或者Expires头;max-stale[=]:设置了该字段表明客户端违心接管曾经过期的资源,然而不能超过给定的工夫限度。一般来说只须要设置其中一种形式就能够实现强缓存策略,当两种形式一起应用时,Cache-Control 的优先级要高于 Expires。 no-cache和no-store很容易混同: no-cache 是指先要和服务器确认是否有资源更新,在进行判断。也就是说没有强缓存,然而会有协商缓存;no-store 是指不应用任何缓存,每次申请都间接从服务器获取资源。(2)协商缓存如果命中强制缓存,咱们无需发动新的申请,间接应用缓存内容,如果没有命中强制缓存,如果设置了协商缓存,这个时候协商缓存就会发挥作用了。 下面曾经说到了,命中协商缓存的条件有两个: max-age=xxx 过期了值为no-store应用协商缓存策略时,会先向服务器发送一个申请,如果资源没有产生批改,则返回一个 304 状态,让浏览器应用本地的缓存正本。如果资源产生了批改,则返回批改后的资源。 协商缓存也能够通过两种形式来设置,别离是 http 头信息中的Etag 和Last-Modified属性。 ...

February 21, 2023 · 4 min · jiezi

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

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

February 21, 2023 · 3 min · jiezi

关于javascript:油猴脚本笔记如何获取React框架开发的页面元素对元素使用click没有反应怎么办如何一步步的执行操作

页面元素应用.click()没有反馈怎么办?如果是React开发的页面大概率是因为没有设置事件监听器。 先来看看有没有绑定事件监听器:F12 -> CTRL+SHIFT+C 审查元素 -> Event Listeners选项卡 有绑定事件监听器的元素:没有绑定事件监听器的元素:没有绑定事件监听器的元素的解决办法: const ele = document.querySelector("#nameZh");const prop = Object.keys(zh).find(p => p.startsWith('__reactEventHandlers'));console.log(ele[prop]);下面最要害的代码是第二行变量prop的获取,利用遍历键值,获取react元素绑定的办法。 而后触发这些事件。 let mousedown = new Event("mousedown" ,{ "bubbles": true, "cancel" : true, "composed": true}); let keyup = new Event('keyup' ,{ "bubbles": true, "cancel" : true, "composed": true}); var click = new Event('click' ,{ "bubbles": true, "cancel" : true, "composed": true}); let ele = document.querySelector("selector") ele.dispatchEvent(mousedown) ele.dispatchEvent(keyup) ele.dispatchEvent(click)如何一步步的执行代码,不应用异步操作?把函数都封装返回成Promise 例子:``` // 填充指定input框 // @param {string} selector // @param {string} content const fillInput = (selector, content) => { return new Promise(resolve => { setTimeout(() => { var mousedown = new Event("mousedown", { "bubbles": true, "cancel": true, "composed": true }); var keyup = new Event('keyup', { "bubbles": true, "cancel": true, "composed": true }); let ele = document.querySelector(selector) ele.focus(); document.execCommand("inserttext", false, content) ele.dispatchEvent(mousedown); ele.dispatchEvent(keyup); // console.log(selector) resolve(); }, 300); }) } 调用: fillInput(zhTitSelector, zh_title) .then(() => fillInput(zhContSelector, zh_content)) .then(() => fillInput(enTitSelector, en_title)) .then(() => fillInput(enContSelector, en_content))```扭转了input值,然而无奈通过校验,点击保留值会清空有2个可能的计划, ...

February 20, 2023 · 1 min · jiezi

关于javascript:学习图片05GIF

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。了解GIF图像格式,同时解释图像编码的工作原理。 尽管在古代 Web 上不是特地有用,但 GIF(Graphics Interchange Format)为咱们对图像编码外围概念的介绍提供了根底。 GIF 能够被认为是图像数据的一个包装器。它有一个称为 logical screen 的视口,到该视口的独自的图像帧绘制,这有点像 Photoshop 文档中的图层。这就是 GIF 反对它翻页动画的形式:一个帧被绘制到逻辑屏幕上,而后被另一个替换,再另一个取代。当然,当咱们解决动态GIF时,这种区别并不重要,它是由绘制在逻辑屏幕上的单帧组成的。 GIF 应用无损数据压缩办法,如果你感兴趣,能够看作是“Lempel–Ziv–Welch”算法的变体。该算法工作的细节在这里不须要理解,但从高层次上看,它有点像“Uglifying” JavaScript,其中文件中的反复字符串被保留到外部字典中,因而能够援用而不是每次呈现时反复。 当然,该算法并不像按数字涂色那么简略。它通过生成的颜色代码表再次查找像素色彩的反复序列,并创立一个可援用代码的第二张表。然而,在任何时候都不会失落任何图像数据,而仅仅是以能够读取而不扭转它的形式进行排序和从新组织。 尽管GIF在技术上应用无损压缩,但它的确有一个重大影响图像品质的次要限度:将图像保留为GIF总是会导致保真度升高,除非该图像曾经应用256色或更少。 在GIF的逻辑屏幕上绘制的每一帧最多只能蕴含256种颜色。GIF还反对 "索引通明",一个通明的像素将参考色表中一个通明 "色彩 "的索引。 将一个数值范畴放大到一个较小的、近似的输入值汇合的做法被称为量化,在学习图像编码时你会常常看到这个术语。这种调色板量化的后果通常很显著。 为了更好地了解这个过程,回忆一下你可能从我的形容中从新创立的光栅图像网格。 这一次,在那张原始图像上减少一点细节:多几个像素,其中一个是略微深一些的蓝色。 如果没有任何压缩--能够这么说--你能够把这个网格形容为: 第一行,第一列是#0000FF。第一行,第二列是#0000FF。第一行,第三列是#0000FF。第一行,第四列是#FF0000。第二行,第一列是#0000FF。第二行,第二列是#000085。第二行,第三列是#0000FF。第二行,第四列是#FF0000。应用相似于GIF的无损数据压缩和色彩索引的货色,你能够把它形容为: A:#0000ff,B:#ff0000,C:#000085。第一行第一至三列是A,第一行第四列是B,第二行第一列是A,第二行第二列是C,第二行第三列是A,第二行第四列是B。这种办法可能在几个中央简化像素对像素的形容("第1列到第3列是..."),并通过在结尾定义反复色彩的字典类型来节俭一些字符。图像的可视度没有扭转。信息曾经压缩,没有任何损失。 正如你所看到的,单个深蓝色像素对咱们编码的大小产生了过大的影响。如果我把本人限度在一个量化的调色板上,它能够被进一步缩小: A:#0000ff,B:#ff0000。第一行,第一至三列是A,第一行,第四列是B。可怜的后果是,节俭的字节导致咱们失去了像素完满的精度。 当然,你,渲染引擎,不晓得这一点——更深蓝色像素的细节被我编码源图像时脱漏了。你依照咱们对于手头的色彩的独特了解恰好渲染了图像。 当初,在这个夸大的例子中,将三种色彩缩小到两种,使品质有了显著的差异。在一个更大、更具体的图像中,其成果可能不那么显著,但它们依然是可见的。 当编码为GIF时,像暗影这样的奥妙突变变得斑驳,个别像素与周围环境造成鲜明对比: 实际上,无损压缩和调色板量化的联合意味着GIF在古代Web开发中并不是很有用。无损压缩并不能无效缩小文件大小,缩小调色板意味着品质显著降落。 归根结底,GIF只是一种无效的格局,用于编码简略的图像,这些图像曾经应用了无限的调色板、硬边缘而不是抗锯齿、纯色而不是突变--所有的应用状况都是由其余格局更好地满足的。更小、更有特色的PNG通常是光栅图像的更好抉择,只管两者在文件大小和视觉保真度方面都远逊于SVG,而在图标或线条艺术等应用案例中,矢量图像是最突出的。GIF最常见的古代用例是动画,但有更无效的、更容易取得的古代视频格式来满足这一目标。 代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。 原文:https://web.dev/learn/images/... 交换有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

February 20, 2023 · 1 min · jiezi

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

异步并发数限度/** * 关键点 * 1. new promise 一经创立,立刻执行 * 2. 应用 Promise.resolve().then 能够把工作加到微工作队列,避免立刻执行迭代办法 * 3. 微工作处理过程中,产生的新的微工作,会在同一事件循环内,追加到微工作队列里 * 4. 应用 race 在某个工作实现时,持续增加工作,放弃工作依照最大并发数进行执行 * 5. 工作实现后,须要从 doingTasks 中移出 */function limit(count, array, iterateFunc) { const tasks = [] const doingTasks = [] let i = 0 const enqueue = () => { if (i === array.length) { return Promise.resolve() } const task = Promise.resolve().then(() => iterateFunc(array[i++])) tasks.push(task) const doing = task.then(() => doingTasks.splice(doingTasks.indexOf(doing), 1)) doingTasks.push(doing) const res = doingTasks.length >= count ? Promise.race(doingTasks) : Promise.resolve() return res.then(enqueue) }; return enqueue().then(() => Promise.all(tasks))}// testconst timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i))limit(2, [1000, 1000, 1000, 1000], timeout).then((res) => { console.log(res)})实现some办法Array.prototype.mySome=function(callback, context = window){ var len = this.length, flag=false, i = 0; for(;i < len; i++){ if(callback.apply(context, [this[i], i , this])){ flag=true; break; } } return flag; } // var flag=arr.mySome((v,index,arr)=>v.num>=10,obj) // console.log(flag);实现ES6的extendsfunction B(name){ this.name = name;};function A(name,age){ //1.将A的原型指向B Object.setPrototypeOf(A,B); //2.用A的实例作为this调用B,失去继承B之后的实例,这一步相当于调用super Object.getPrototypeOf(A).call(this, name) //3.将A原有的属性增加到新实例上 this.age = age; //4.返回新实例对象 return this;};var a = new A('poetry',22);console.log(a);实现call办法call做了什么: ...

February 20, 2023 · 13 min · jiezi

关于javascript:腾讯前端一面经典手写面试题合集

查找字符串中呈现最多的字符和个数例: abbcccddddd -> 字符最多的是d,呈现了5次let str = "abcabcabcbbccccc";let num = 0;let char = ''; // 使其依照肯定的秩序排列str = str.split('').sort().join('');// "aaabbbbbcccccccc"// 定义正则表达式let re = /(\w)\1+/g;str.replace(re,($0,$1) => { if(num < $0.length){ num = $0.length; char = $1; }});console.log(`字符最多的是${char},呈现了${num}次`);手写类型判断函数function getType(value) { // 判断数据是 null 的状况 if (value === null) { return value + ""; } // 判断数据是援用类型的状况 if (typeof value === "object") { let valueClass = Object.prototype.toString.call(value), type = valueClass.split(" ")[1].split(""); type.pop(); return type.join("").toLowerCase(); } else { // 判断数据是根本数据类型的状况和函数的状况 return typeof value; }}实现Event(event bus)event bus既是node中各个模块的基石,又是前端组件通信的依赖伎俩之一,同时波及了订阅-公布设计模式,是十分重要的根底。 ...

February 20, 2023 · 10 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。 ...

February 20, 2023 · 3 min · jiezi

关于javascript:腾讯前端必会面试题必备

如何提取高度嵌套的对象里的指定属性?有时会遇到一些嵌套水平十分深的对象: const school = { classes: { stu: { name: 'Bob', age: 24, } }}像此处的 name 这个变量,嵌套了四层,此时如果依然尝试老办法来提取它: const { name } = school显然是不见效的,因为 school 这个对象自身是没有 name 这个属性的,name 位于 school 对象的“儿子的儿子”对象外面。要想把 name 提取进去,一种比拟笨的办法是逐层解构: const { classes } = schoolconst { stu } = classesconst { name } = stuname // 'Bob'然而还有一种更规范的做法,能够用一行代码来解决这个问题: const { classes: { stu: { name } }} = schoolconsole.log(name) // 'Bob'能够在解构进去的变量名右侧,通过冒号+{指标属性名}这种模式,进一步解构它,始终解构到拿到指标数据为止。 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?行内元素有:a b span img input select strong;块级元素有:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p;空元素,即没有内容的HTML元素。空元素是在开始标签中敞开的,也就是空元素没有闭合标签: ...

February 20, 2023 · 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相干常识,你应该事后就理解了 ...

February 20, 2023 · 7 min · jiezi

关于javascript:责任链和策略设计模式基于Java编程语言

作者:京东物流 钟磊 1 前言最近在梳理接口逻辑的时候发现,代码中应用的策略和责任链设计模式给我留下了十分粗浅的印象。一个业务逻辑流程通常非常适合应用责任链和策略设计模式来实现,因为一个业务需要通常能够拆分成一个个独立的逻辑处理单元并按程序组合而成,而责任链设计模式能够很好的链接整个业务流程,同时策略设计模式能够将业务中变动的算法局部抽离进去,从而复用次要的公共逻辑并能够灵便替换业务算法,应用这两种设计模式能够灵便扩大咱们的代码以适应不同的业务需要。因为这两种设计模式十分实用,上面简略介绍一下我对这两种设计模式的了解和它们在Spring框架源码中的利用。 2 责任链设计模式的个别定义责任链设计模式是设计模式中的一种行为型设计模式。其根底构造相似于一个链条,整个链条由一个个独自的链环组成,每个链环在程序代码中就是一个独立的处理单元,每个处理单元都有本人负责的独特逻辑,当一个解决申请来到这个链条后,会顺次沿着每个处理单元进行传递直到这个申请被处理完毕为止。 2.1 应用场景:1.一个业务申请须要通过一组处理单元的解决。这种场景相似于一个业务逻辑流程中设置了多个性能不同的处理单元,一个业务申请须要通过这多个处理单元的串行解决。 2.程序中存在能解决同一个申请的多个处理单元,但决定具体应用哪个处理单元须要在程序运行时依据申请动静确定。 2.2 类图构造和Spring AOP框架中的利用1:类图构造 2:责任链设计模式在Spring AOP框架中的利用Spring框架中的AOP模块就应用了责任链设计模式将指标办法的一次调用过程包装成了一条办法调用链来加强指标办法。Spring AOP模块中包含了Before、After、AfterReturning、AfterThrowing、Around这五种告诉办法,Spring AOP模块将这些告诉办法和指标办法通过动静代理的形式包装成了一条调用链来别离履行各个告诉模块的解决逻辑,上面是Spring AOP的源码剖析图。 Spring AOP通过递归的形式来实现责任链的性能,首先将所有的告诉办法进行排序,而后利用一个List索引来管制整个执行流程的开始和完结,在整个责任链中Before告诉负责执行前置解决,After告诉负责执行后置解决,AfterReturning办法负责在指标办法胜利执行返回后执行解决逻辑,AfterThrowing办法负责在指标办法异样执行后执行解决逻辑。Spring AOP将告诉办法包装成办法调用链上的每一个节点,奇妙地利用责任链模式实现了指标办法的解决加强。 3:泛化的责任链设计模式在日常代码的编写中,责任链设计模式并不需要如此严格的构造,只有代码整体流程由一个个独立的处理单元形成,并且按肯定程序组合组合而成,那么也能够看作是一种更加泛化的责任链设计模式,也能很好的满足开闭准则,例如上面这种更加罕用的代码构造。 下面这种构造同样也能实现责任链解决性能,也能够更加简洁的进行编写,同样能够很好的进批改和灵便扩大,在保护代码的适宜也会更加清晰。 2.3 责任链模式的长处:1.每个解决节点都有本人的独特的解决逻辑,明确各自在整个流程中的职责,合乎类的繁多职责准则。 2.构建的责任链能够依据业务需要进行灵便扭转,能动静进行程序调整以及动静插拔,满足重要的开闭准则。 3.升高了申请发送者以及申请解决者之间的耦合度。 3 策略设计模式的个别定义策略设计模式同样也是设计模式中的一种行为型设计模式,其在结构上的体现就是将可变的算法策略局部从业务代码逻辑中独立进去,将这些算法策略造成策略池,从而能够随时替换和更新,使得咱们的代码构造更加灵便、更易扩大。 3.1 应用场景1:当代码须要依据上下文逻辑来抉择应用不同的业务算法时,咱们能够应用策略设计模式来优化代码的判断构造,从而防止大量的if/else分支判断。 2:当代码的主体解决逻辑大致相同,仅仅在局部的业务算法上存在不同时,能够将这些不同的业务算法抽离进去,从而能防止大量反复的代码编写,并能复用主体代码逻辑。 3.2 类图构造和Spring框架中的利用1:类图构造 2:Spring框架中的利用Spring框架中给咱们开发者留下了十分多的扩大策略点,实现了可动静插拔的性能扩大,其中典型的一个策略扩大点就是BeanPostProcessor接口,BeanPostProcessor接口容许咱们在Bean的初始化前和初始化后做一些逻辑解决策略来扭转Bean的属性,容许咱们对Bean进行革新和个性化,Spring AOP就是利用BeanPostProcessor这个策略扩大点实现了动静代理Bean的创立,上面是Spring AOP后置处理器的源码剖析。 Spring AOP通过导入AspectJAwareAdvisorAutoProxyCreator这个实现了BeanPostProcessor接口的后置处理器,在Bean初始化后进行了一个动静代理类的创立,其在postProcessAfterInitaliztion办法中的WarpIfNecessary中办法中实现了代理类的创立。Spring框架利用这种模板加策略的设计模式让咱们能够个性化扩大框架的性能,让框架变得非常灵活可扩大,咱们也能够依据业务需要退出本人的BeanPostProcessor策略来实现本人的独特逻辑,很好地满足了重要的开闭设计准则。 3:泛化的策略设计模式同样地咱们也不用严格依照定义的策略设计模式进行编写,只有在整体上满足业务主体逻辑不变,将变动局部抽离进去,造成能够按需扩大的策略思维就行了,上面以SpringBoot主动拆卸的源码来阐明这种更加泛化的策略模式。SpringBoot主动拆卸机制是依照用户以后的代码运行环境并联合@Conditional注解来动静为咱们主动加载须要应用的类,这种策略设计模式是一种更加泛化的策略设计模式,同样满足策略设计模式的按需抉择,动静插拔的设计准则。SpringBoot的主动拆卸机制的原理如下: ①SpringBoot在@EnableAutoConfiguration注解中应用了@import注解导入了 EnableAutoConfigurationImportSelector类。 ②利用EnableAutoConfigurationImportSelector类的selectImports办法来加载jar包外面META-INF/spring.factories文件中配好的类。 ③最初联合各种@Conditional注解来实现按需加载的策略设计模式。 SpringBoot这种按需主动拆卸的策略设计思维,在结构上并不严格合乎策略设计模式的构造,但他的整体设计思维十分合乎策略设计模式,咱们在我的项目中也能够通过配置文件的形式来灵便切换咱们代码中应用的策略算法。 3.3 策略设计模式的长处:1:能够在程序运行时动静抉择切换须要应用的独立业务算法。 2:将可变的业务算法与业务主体逻辑剥离,实现更加灵便的保护和扩大。 3:满足开闭准则,无需批改原有的代码逻辑就能实现不同业务算法灵便切换。 4 联合策略设计模式和责任链设计模式将策略设计模式和责任链设计模式进行联合就能造成灵便可扩大的流程构造,能应答多变的业务需要,上面是将两者进行联合的结构图。 一个request在通过每一个handler处理单元时,会依据request的上下文内容抉择适合的策略进行解决,而后将这所有的handler串联起来造成残缺的业务流程。 5 总结在日常代码的编写中,业务需要的变动总是不定的,这样会导致咱们的代码会频繁的随着需要的扭转进行调整,稍加不留神的话就会导致咱们的代码十分臃肿和简单,累加到肯定水平后会变得难以保护,这时事后应用适合的代码设计模式能无效的缓解这种状况,文中形容的责任链和策略设计模式能无效满足代码编写的开闭准则,能更加无效的应答随时变动的业务需要。

February 20, 2023 · 1 min · jiezi

关于javascript:社招前端必会手写面试题集锦

查找字符串中呈现最多的字符和个数例: abbcccddddd -> 字符最多的是d,呈现了5次let str = "abcabcabcbbccccc";let num = 0;let char = ''; // 使其依照肯定的秩序排列str = str.split('').sort().join('');// "aaabbbbbcccccccc"// 定义正则表达式let re = /(\w)\1+/g;str.replace(re,($0,$1) => { if(num < $0.length){ num = $0.length; char = $1; }});console.log(`字符最多的是${char},呈现了${num}次`);深克隆(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);};局限性: ...

February 19, 2023 · 10 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);参考 前端进阶面试题具体解答 ...

February 19, 2023 · 12 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) 这两个函数,别离是对依赖的收集和触发。 ...

February 19, 2023 · 5 min · jiezi

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

具体阐明 Event loop家喻户晓 JS 是门非阻塞单线程语言,因为在最后 JS 就是为了和浏览器交互而诞生的。如果 JS 是门多线程的语言话,咱们在多个线程中解决 DOM 就可能会产生问题(一个线程中新加节点,另一个线程中删除节点),当然能够引入读写锁解决这个问题。 JS 在执行的过程中会产生执行环境,这些执行环境会被程序的退出到执行栈中。如果遇到异步的代码,会被挂起并退出到 Task(有多种 task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出须要执行的代码并放入执行栈中执行,所以实质上来说 JS 中的异步还是同步行为。 console.log('script start');setTimeout(function() { console.log('setTimeout');}, 0);console.log('script end');以上代码尽管 setTimeout 延时为 0,其实还是异步。这是因为 HTML5 标准规定这个函数第二个参数不得小于 4 毫秒,有余会主动减少。所以 setTimeout 还是会在 script end 之后打印。 不同的工作源会被调配到不同的 Task 队列中,工作源能够分为 微工作(microtask) 和 宏工作(macrotask)。在 ES6 标准中,microtask 称为 jobs,macrotask 称为 task。 console.log('script start');setTimeout(function() { console.log('setTimeout');}, 0);new Promise((resolve) => { console.log('Promise') resolve()}).then(function() { console.log('promise1');}).then(function() { console.log('promise2');});console.log('script end');// script start => Promise => script end => promise1 => promise2 => setTimeout以上代码尽管 setTimeout 写在 Promise 之前,然而因为 Promise 属于微工作而 setTimeout 属于宏工作,所以会有以上的打印。 ...

February 19, 2023 · 6 min · jiezi

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

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

February 19, 2023 · 1 min · jiezi

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

代码输入后果function runAsync (x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000)) return p}Promise.race([runAsync(1), runAsync(2), runAsync(3)]) .then(res => console.log('result: ', res)) .catch(err => console.log(err))输入后果如下: 1'result: ' 123then只会捕捉第一个胜利的办法,其余的函数尽管还会继续执行,然而不是被then捕捉了。 冒泡排序--工夫复杂度 n^2题目形容:实现一个冒泡排序 实现代码如下: function bubbleSort(arr) { // 缓存数组长度 const len = arr.length; // 外层循环用于管制从头到尾的比拟+替换到底有多少轮 for (let i = 0; i < len; i++) { // 内层循环用于实现每一轮遍历过程中的反复比拟+替换 for (let j = 0; j < len - 1; j++) { // 若相邻元素后面的数比前面的大 if (arr[j] > arr[j + 1]) { // 替换两者 [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; } } } // 返回数组 return arr;}// console.log(bubbleSort([3, 6, 2, 4, 1]));Vuex有哪些根本属性?为什么 Vuex 的 mutation 中不能做异步操作?有五种,别离是 State、 Getter、Mutation 、Action、 Module1、state => 根本数据(数据源寄存地)2、getters => 从根本数据派生进去的数据3、mutations => 提交更改数据的办法,同步4、actions => 像一个装璜器,包裹mutations,使之能够异步。5、modules => 模块化Vuex1、Vuex中所有的状态更新的惟一路径都是mutation,异步操作通过 Action 来提交 mutation实现,这样能够不便地跟踪每一个状态的变动,从而可能实现一些工具帮忙更好地理解咱们的利用。2、每个mutation执行实现后都会对应到一个新的状态变更,这样devtools就能够打个快照存下来,而后就能够实现 time-travel 了。如果mutation反对异步操作,就没有方法晓得状态是何时更新的,无奈很好的进行状态的追踪,给调试带来艰难。代码输入后果// afunction Foo () { getName = function () { console.log(1); } return this;}// bFoo.getName = function () { console.log(2);}// cFoo.prototype.getName = function () { console.log(3);}// dvar getName = function () { console.log(4);}// efunction getName () { console.log(5);}Foo.getName(); // 2getName(); // 4Foo().getName(); // 1getName(); // 1 new Foo.getName(); // 2new Foo().getName(); // 3new new Foo().getName(); // 3输入后果:2 4 1 1 2 3 3 ...

February 19, 2023 · 7 min · jiezi

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

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

February 19, 2023 · 2 min · jiezi

关于javascript:源码PDFjs批注注释插件库纯JS-创建和保存PDF批注PDF-高亮签名插图截屏文本框画笔多边形

基于 PDF.js 开发了 PDF 批注正文插件库,反对多种批注类型,反对写入批注到pdf中并保留,为目前纯前端 JavaScript 最佳实现计划,完满反对 老版浏览器、手机、平板 等挪动端设施,仅应用 PDF.js dist 版本,能够不便集成到任意我的项目中。 Demo及源码Demo和源码在:https://demos.libertynlp.com 基于 pdf.js-dist 开发的批注正文插件库,能够不便集成到任意我的项目中。 性能演示视频:https://www.bilibili.com/vide... 功能模块① 下载文件 : 把批注标记保留到pdf文件中 ② 文本高亮 : 高亮滑选的文本 ③ 文本下划线 : 给滑选的文本减少下划线 ④ 文档截图: 截图PDF页面并保留为PNG图片 ⑤ 正文列表 : 关上正文列表并编辑 (复制/删除/返回) ⑥ 选中对象 : 选中批注对象并批改 (地位/X轴缩放/Y轴缩放/旋转) ⑦ 选中对象 : 选中批注对象并批改 (色彩/角度/大小/地位/透明度) ⑧ 插入图片 : 插入本地图片如电子签名 ⑨ 画笔工具 : 在以后页面应用画笔工具自在绘制 ⑩ 文本框工具 : 给以后页面增加可输出文本框 ⑪ 多边形工具: 减少并编辑 箭头/矩形/圆形 ⑫ 编辑正文: 复制、删除和返回批注 ⑬ 导出正文 : 导出残缺构造Json标注,可保留到服务器并回显 ⑭ 导入标注 : 导入残缺构造标注回显 ⑮ 下载标注 : 导出以后文件标注和评论为txt格局文档 ⑯ 切换语言 : 切换提醒语言至英文 ⑰ 帮忙文档 : 关上帮忙文档 ...

February 17, 2023 · 1 min · jiezi

关于javascript:JavaScript混淆加密保护你的JavaScript代码安全

JavaScript混同加密:爱护你的JavaScript代码平安在当今的互联网时代,JavaScript是一种十分重要的编程语言,被广泛应用于网站开发、利用程序开发等畛域。然而,因为JavaScript代码的个性,攻击者很容易从中找到破绽,因而爱护JavaScript代码的安全性显得尤为重要。而JavaScript混同加密就是一种爱护JavaScript代码的无效办法。 什么是JavaScript混同加密?JavaScript混同加密是一种将JavaScript代码转换为难以了解的模式的技术,旨在使代码更难以被反编译和剖析。这通常通过应用各种技术来使代码难以浏览和了解,例如删除空格和正文、变量和函数重命名、应用特殊字符、压缩和优化代码等。 JavaScript混同加密的目标是爱护代码的机密性和完整性,避免攻击者轻易地批改代码或获取敏感信息。这对于那些须要将JavaScript代码公开或交给第三方进行应用的公司或集体尤为重要。 JavaScript混同加密的长处进步代码的安全性JavaScript混同加密使得代码更难以被反编译和剖析,从而进步了代码的安全性。攻击者须要破费更多的工夫和精力能力了解和剖析代码,从而升高了攻击者入侵的成功率。 爱护知识产权JavaScript混同加密能够帮忙开发者爱护本人的知识产权。将JavaScript代码混同加密后,攻击者无奈轻易地复制或批改代码,从而爱护开发者的权利。 进步性能JavaScript混同加密能够通过压缩和优化代码来进步代码的性能。压缩和优化代码能够使代码更小,从而放慢代码的加载速度,进步网站或应用程序的性能。 JavaScript混同加密的局限性只管JavaScript混同加密能够进步代码的安全性,但它并不能齐全爱护代码不被反编译和剖析。如果攻击者有足够的工夫和资源,他们依然可能可能了解代码并找到其中的破绽。因而,JavaScript混同加密应该与其余安全措施联合应用,如输出验证和服务器端验证。 总结JavaScript混同加密是一种爱护JavaScript代码平安的无效办法。它能够进步代码 jsjiami.com 上方网站,底部有我联系方式详谈(座右铭:世界上没有解不开的加密)。

February 16, 2023 · 1 min · jiezi

关于javascript:js判断是否有滚动条及滚动到最底部

如果需要是强制要求用户将滚动条拉到最底部能力进行下一个动作,在不能保障内容很多(比方一段文案是否很长)肯定会超过元素设置的固定高度产生滚动条的状况下,先判断这个元素上是否有滚动条,如果没有滚动条那就去掉滑动到最底部能力执行下一步动作的限度。 //判断是否有滚动条const hasScrollBar=(ele,direction)=>{ //元素的scrollHeight或者scrollWidth的值比clientHeight或者clientWidth的值大,则有滚动条 if(direction==="vertical"){ return ele.scrollHeight>ele.clientHeight } if(direction==="cross"){ return ele.scrollWidth>ele.clientWidth }}const scrollBottom=(ele)=>{ if ( ele.scrollTop + (ele.clientHeight + 1) >= ele.scrollHeight ) { //滚动到了最底部 } else { //没有滚动到最底部 }}

February 16, 2023 · 1 min · jiezi

关于javascript:HHDESK图片管理批量重命名及递归搜索

1.图片批量重命名性能HHDESK作为一款国产桌面软件,思考到国人的操作及浏览习惯。因而咱们开发了一些有意义的新性能,比方明天要介绍的图片批量重命名及递归搜寻性能图片批量重命名性能网上下载的图片名称大多横七竖八,一眼望去毫无脉络。 而windows自带的命名性能会主动退出(),不合乎国人语言及存储习惯,甚至让许多强迫症无法忍受,只能手动一个个批改(比方笔者本人)。 而HHDESK批量图片重命名性能,能够自行定义命名规定。 举例: 1.点击递归搜寻,抉择按文件名搜寻; 2.找到须要批量重命名的图片,点击进入所在目录; 3.将序号初值设置为1,填写规定。 成果如下图所示,清晰简洁明了。 如果有别的需要,还能够自行加上日期、工夫等。 这也使得后续应用图片时更加不便。 2 应用技巧应用HHDESK递归搜寻性能,能够在搜寻到所需图片的同时,清晰的找到图片所属文件夹,间接能够进入下一步操作,不须要多余操作。

February 16, 2023 · 1 min · jiezi

关于javascript:nodejskoaSequelizepkg后端服务实践

nodejs+koa+Sequelize实际Node.js® 是一个开源、跨平台的 JavaScript 运行时环境。Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 利用和 API 开发畛域中的一个更小、更富裕表现力、更强壮的基石。 通过利用 async 函数,Koa 帮你抛弃回调函数,并无力地加强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的办法,帮忙您疾速而欢快地编写服务端应用程序。Sequelize是一个基于 promise 的 Node.js ORM, 目前反对 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具备弱小的事务反对, 关联关系, 预读和提早加载,读取复制等性能。pkg能够将 Node.js 我的项目打包为可执行文件,甚至能够在未装置 Node.js 的设施上运行。根本架构 **model层:数据长久化,并提共数据处理,长久化操作接口control层:业务模块流程管制,调用service层接口service层:业务操作实现类,调用model层接口** 中间件:中间件作用特点koa-static动态资源门路koa-logger日志打点中间件koa2-cors跨域解决koa-jwt次要提供路有权限管制的性能,它会对须要限度的资源申请进行查看koa-body是一个能够帮忙解析 http 中 body 的局部的中间件,包含 json、表单、文本、文件等。SequelizeSequelize 是一个基于 promise 的 Node.js ORM, 目前反对 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具备弱小的事务反对, 关联关系, 预读和提早加载,读取复制等性能。koa-routerkoa 的一个路由中间件,它能够将申请的URL和办法(如:GET 、 POST 、 PUT 、 DELETE 等) 匹配到对应的响应程序或页面数据库相干数据库配置 ...

February 15, 2023 · 2 min · jiezi

关于javascript:对国际化-i18n-项目的一点思考

国际化是什么?国际化 对应的英文单词为 Internationalization,又称 i18n: i 为单词的 【第一个】 字母18 为 【i 和 n 之间】 单词的个数n 代表这个单词的 【最初一个】 字母如果你的我的项目是 Vue,那么置信你在实现国际化性能时,也必不可少的会应用到 vue-i18n 这个库,接下来本文也是通过这个库搭配 Vue 实现最根本的国际化性能,但关注点并不是如何应用这个库,而是在实现的过程中思考 可优化的点。 实现根本国际化性能这里就不再多余演示 demo 我的项目的创立过程了,并且文中只演示最根本的 中英文 切换,好了当初直奔外围吧! 集成 vue-i18n装置依赖相熟的命令:npm install vue-i18n -S 配置 vue-i18n 在 src 目录下创立 language 目录用于放弃和语言切换相干的内容在 language 目录下创立 lang 目录用于保留不同语言的映射关系,如中文对应 zh.js、英文对应 en.js 等在 language 目录下创立 index.js 作为默认导出,并在其中创立 i18n 对象 import { createI18n } from "vue-i18n"; import zh from './lang/zh'; import en from './lang/en'; const i18n = createI18n({ legacy: false, locale: "zh", // 初始化配置语言 messages: { zh, en, }, }); export default i18n;main.js 注册 i18n内容非常简单,间接上代码: ...

February 15, 2023 · 4 min · jiezi

关于javascript:wrnecharts在-RN-中使用-ECharts

本篇文章次要介绍 wrn-echarts 我的项目,接下来本文会从诞生背景、设计与实现、成果演示等环节向大家具体介绍这个我的项目。 官网:https://wuba.github.io/wrn-ec...源码:https://github.com/wuba/wrn-e... 背景在日常进行业务需要的开发时,常常会遇到须要绘制图表的场景,其中咱们应用频率最高的图表库是 ECharts。ECharts 作为市面上最成熟的图表库之一,次要面向 Web 端应用,官网对小程序端也提供了解决方案,而在 RN 的开发场景中却没有比拟好的实现办法,面对这种状况以前咱们的解决方案有: 放弃 ECharts,应用针对RN原生开发的图表库,如 react-native-charts-wrapper、victory-native 等通过 Webview 来应用 web 端的 ECahrts,如 react-native-echarts-pro、native-echarts 等计划1,RN 现有图表库的款式与交互与 ECahrts 相比有较大差距,图表的丰富性也有余,尤其是有多端需要的场景下,须要为 RN 独自进行UI交互设计,设计与实现老本高。 计划2,通过 Webview 的形式,当页面上有多个图表或者图表元素过多时,会遇到性能方面的瓶颈,比方安卓端的大数据量面积图、单轴散点图等会有白屏景象,而且失常渲染过程中也会有比拟显著的卡顿、掉帧的状况。 所以,咱们心愿开发一个图表库,能够应用 RN 的原生渲染控件将 Web ECharts的能力集成到 RN 利用中,来进步开发效率以及不同平台产品体验的一致性,同时为咱们未来实现真正的跨端图表库打下基础。 可行性剖析既然要用RN原生渲染,那首先看目前 RN 反对的图形库有哪些: react-native-svg:提供可在 RN 应用的根底 SVG 图形库,该库通过相似于 Web 端的 SVG 渲染模式来渲染图形(此计划下文中简称 WRNSVG 模式)react-native-skia:Skia 是跨平台的图形渲染引擎,该库将 Skia 的 2d 图形库引入 RN,同时也提供了 ImageSVG 组件,反对对 SVG 格局的图片进行渲染(此计划下文中简称 WRNSkia 模式)剖析得之,上述两种计划实现的外围都是要获取到 ECharts 图表的 SVG 图形数据。而咱们晓得 ECharts 自身就反对 SVG 格局的渲染,所以咱们就去 ECharts 代码仓库查看相干的实现,看是否能获取到咱们想要的数据。 ...

February 14, 2023 · 4 min · jiezi

关于javascript:H5页面打开app安卓端和苹果端

对于App的分享页面,挪动端常常会遇到须要唤起App并定位的性能。 跳转到App办法安卓通常应用 URL Scheme 办法IOS有两种办法 meta标签和Universal Links, 咱们通常应用Universal Links URL SchemeURL Scheme就是一个能够让app相互之间能够跳转的对外接口。每个app都不同,如果有反复的会响应先装置的app。URL Scheme的格局为: [scheme]://[host]/[path]?[query]比方: 淘宝: taobao://QQ: mqq://微信: weixin://meta标签在网页上设置meta标签,应用safari关上的时候,就会在顶部显示本人app的导航条。如果没有装置app点击可能跳转到appstore去下载,如果装置了app就能间接通过顶部的meta标签唤醒app了。(此为IOS特有) <meta charset="UTF-8" name="apple-itunes-app" content="app-id=yourId, affiliate-data=myAffiliateData, app-argument=yourScheme://">Universal LinksiOS 9之前,始终应用的是URL Schemes技术来从内部对App进行跳转,然而iOS零碎中进行URL Schemes跳转的时候如果没有装置App,会提醒Cannot open Page的提醒,而且当注册有多个scheme雷同的时候,目前没有方法辨别,然而从iOS 9起能够应用Universal Links技术进行跳转页面,这是一种体验更加完满的解决方案 实现唤醒APP性能大多数须要唤醒app时都是在微信内,但因为微信外部禁用了唤醒性能,所以做了一个疏导页,疏导用户通过浏览器关上。(一些出名app能够唤起) <div class="main"> <div class="tips" id="ios"></div> <div class="tips" id="android"></div> <div class="logo"></div> <div class="info"></div> <div id="a-btn" class="downloadBtna"><a href="https://wwww.******.com.cn/api/app/download"></a></div> <div id="i-btn" class="downloadBtni"><a href="https://itunes.apple.com/cn/app/yourId"></a></div></div>// 获取浏览器用于 HTTP 申请的用户代理头的值var u = navigator.userAgent, ua = u.toLowerCase()var isWeiXin = ua.indexOf('micromessenger') != -1;var {isAndroid, isIOS} = detectVersion()// 获取参数id值、起源值,以便用于scheme跳转var id = getQueryString('id')var source = getQueryString('source')// 判断以后浏览器function detectVersion() { var isAndroid, isIOS; if(u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) { // android or uc browser // android isAndroid = true } if(ua.indexOf("like mac os x") > 0) { isIOS = true } return {isAndroid, isIOS}}// 唤起app办法function openApp(callback) { var url = "" if (isAndroid ) { url = '[scheme]://'+ source +'?id=' + id var timeout, t = 3000, hasApp = true var openScript = setTimeout( function () { if (!hasApp) { callback && callback() } document.body.removeChild(ifr) },5000) var t1 = Date.now() var ifr = document.createElement("iframe") ifr.setAttribute("src", url) ifr.setAttribute("style", "display:none") document.body.appendChild(ifr) timeout = setTimeout( function () { var t2 = Date.now() if (t2 - t1 < t + 100) { hasApp = false // 此处创立一个定时器,以便用于判断页面是否跳转,如果未胜利跳转,那么判断未装置app,此时跳转到app下载 window.location.href="https://www.******.com.cn/api/app/download" } },t) } if (isIOS) { // Universal Links 须要IOS工程师进行配置 window.location.href= "https://www.******.com.cn/" + source + "?id=" + id }}$(function () { if(isWeiXin) { if(isAndroid) { $("#a-btn").show() $("#android").show() } else { $("#i-btn").show() $("#ios").show() } } else { if(isAndroid) { $("#android").show() $("#a-btn").show() openApp() } else { $("#ios").show() $("#i-btn").show() openApp() } } })以上并没有思考ios9以下版本本文参加了SegmentFault 思否写作挑战赛,欢送正在浏览的你也退出。

February 14, 2023 · 2 min · jiezi

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

实现 add(1)(2)(3)函数柯里化概念: 柯里化(Currying)是把承受多个参数的函数转变为承受一个繁多参数的函数,并且返回承受余下的参数且返回后果的新函数的技术。 1)粗犷版 function add (a) {return function (b) { return function (c) { return a + b + c; }}}console.log(add(1)(2)(3)); // 62)柯里化解决方案 参数长度固定var add = function (m) { var temp = function (n) { return add(m + n); } temp.toString = function () { return m; } return temp;};console.log(add(3)(4)(5)); // 12console.log(add(3)(6)(9)(25)); // 43对于add(3)(4)(5),其执行过程如下: 先执行add(3),此时m=3,并且返回temp函数;执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数因为前面没有传入参数,等于返回的temp函数不被执行而是打印,理解JS的敌人都晓得对象的toString是批改对象转换字符串的办法,因而代码中temp函数的toString函数return m值,而m值是最初一步执行函数时的值m=12,所以返回值是12。参数长度不固定function add (...args) { //求和 return args.reduce((a, b) => a + b)}function currying (fn) { let args = [] return function temp (...newArgs) { if (newArgs.length) { args = [ ...args, ...newArgs ] return temp } else { let val = fn.apply(this, args) args = [] //保障再次调用时清空 return val } }}let addCurry = currying(add)console.log(addCurry(1)(2)(3)(4, 5)()) //15console.log(addCurry(1)(2)(3, 4, 5)()) //15console.log(addCurry(1)(2, 3, 4, 5)()) //15基于Generator函数实现async/await原理外围:传递给我一个Generator函数,把函数中的内容基于Iterator迭代器的特点一步步的执行function readFile(file) { return new Promise(resolve => { setTimeout(() => { resolve(file); }, 1000); })};function asyncFunc(generator) { const iterator = generator(); // 接下来要执行next // data为第一次执行之后的返回后果,用于传给第二次执行 const next = (data) => { let { value, done } = iterator.next(data); // 第二次执行,并接管第一次的申请后果 data if (done) return; // 执行结束(到第三次)间接返回 // 第一次执行next时,yield返回的 promise实例 赋值给了 value value.then(data => { next(data); // 当第一次value 执行结束且胜利时,执行下一步(并把第一次的后果传递下一步) }); } next();};asyncFunc(function* () { // 生成器函数:控制代码一步步执行 let data = yield readFile('a.js'); // 等这一步骤执行执行胜利之后,再往下走,没执行完的时候,间接返回 data = yield readFile(data + 'b.js'); return data;})Function.prototype.apply()第一个参数是绑定的this,默认为window,第二个参数是数组或类数组 ...

February 14, 2023 · 10 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。 ...

February 14, 2023 · 3 min · jiezi

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

请实现一个 add 函数,满足以下性能add(1); // 1add(1)(2); // 3add(1)(2)(3);// 6add(1)(2, 3); // 6add(1, 2)(3); // 6add(1, 2, 3); // 6function add(...args) { // 在外部申明一个函数,利用闭包的个性保留并收集所有的参数值 let fn = function(...newArgs) { return add.apply(null, args.concat(newArgs)) } // 利用toString隐式转换的个性,当最初执行时隐式转换,并计算最终的值返回 fn.toString = function() { return args.reduce((total,curr)=> total + curr) } return fn}考点: 应用闭包, 同时要对JavaScript 的作用域链(原型链)有深刻的了解重写函数的 toSting()办法// 测试,调用toString办法触发求值add(1).toString(); // 1add(1)(2).toString(); // 3add(1)(2)(3).toString();// 6add(1)(2, 3).toString(); // 6add(1, 2)(3).toString(); // 6add(1, 2, 3).toString(); // 6判断是否是电话号码function isPhone(tel) { var regx = /^1[34578]\d{9}$/; return regx.test(tel);}解析 URL Params 为对象let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';parseParam(url)/* 后果{ user: 'anonymous', id: [ 123, 456 ], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型 city: '北京', // 中文需解码 enabled: true, // 未指定值得 key 约定为 true}*/function parseParam(url) { const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来 const paramsArr = paramsStr.split('&'); // 将字符串以 & 宰割后存到数组中 let paramsObj = {}; // 将 params 存到对象中 paramsArr.forEach(param => { if (/=/.test(param)) { // 解决有 value 的参数 let [key, val] = param.split('='); // 宰割 key 和 value val = decodeURIComponent(val); // 解码 val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字 if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则增加一个值 paramsObj[key] = [].concat(paramsObj[key], val); } else { // 如果对象没有这个 key,创立 key 并设置值 paramsObj[key] = val; } } else { // 解决没有 value 的参数 paramsObj[param] = true; } }) return paramsObj;}数组去重const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];// => [1, '1', 17, true, false, 'true', 'a', {}, {}]办法一:利用Setconst res1 = Array.from(new Set(arr));办法二:两层for循环+spliceconst unique1 = arr => { let len = arr.length; for (let i = 0; i < len; i++) { for (let j = i + 1; j < len; j++) { if (arr[i] === arr[j]) { arr.splice(j, 1); // 每删除一个树,j--保障j的值通过自加后不变。同时,len--,缩小循环次数晋升性能 len--; j--; } } } return arr;}办法三:利用indexOfconst unique2 = arr => { const res = []; for (let i = 0; i < arr.length; i++) { if (res.indexOf(arr[i]) === -1) res.push(arr[i]); } return res;}当然也能够用include、filter,思路大同小异。 ...

February 14, 2023 · 11 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): ...

February 14, 2023 · 3 min · jiezi

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

对this对象的了解this 是执行上下文中的一个属性,它指向最初一次调用这个办法的对象。在理论开发中,this 的指向能够通过四种调用模式来判断。 第一种是函数调用模式,当一个函数不是一个对象的属性时,间接作为函数来调用时,this 指向全局对象。第二种是办法调用模式,如果一个函数作为一个对象的办法来调用时,this 指向这个对象。第三种是结构器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。第四种是 apply 、 call 和 bind 调用模式,这三个办法都能够显示的指定调用函数的 this 指向。其中 apply 办法接管两个参数:一个是 this 绑定的对象,一个是参数数组。call 办法接管的参数,第一个是 this 绑定的对象,前面的其余参数是传入函数执行的参数。也就是说,在应用 call() 办法时,传递给函数的参数必须一一列举进去。bind 办法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了应用 new 时会被扭转,其余状况下都不会扭转。这四种形式,应用结构器调用模式的优先级最高,而后是 apply、call 和 bind 调用模式,而后是办法调用模式,而后是函数调用模式。 说一下HTTP 3.0HTTP/3基于UDP协定实现了相似于TCP的多路复用数据流、传输可靠性等性能,这套性能被称为QUIC协定。 流量管制、传输可靠性性能:QUIC在UDP的根底上减少了一层来保障数据传输可靠性,它提供了数据包重传、拥塞管制、以及其余一些TCP中的个性。集成TLS加密性能:目前QUIC应用TLS1.3,缩小了握手所破费的RTT数。多路复用:同一物理连贯上能够有多个独立的逻辑数据流,实现了数据流的独自传输,解决了TCP的队头阻塞问题。疾速握手:因为基于UDP,能够实现应用0 ~ 1个RTT来建设连贯。原型/原型链__proto__和prototype关系 :__proto__和constructor是对象独有的。2️prototype属性是函数独有的 在 js 中咱们是应用构造函数来新建一个对象的,每一个构造函数的外部都有一个 prototype 属性值,这个属性值是一个对象,这个对象蕴含了能够由该构造函数的所有实例共享的属性和办法。当咱们应用构造函数新建一个对象后,在这个对象的外部将蕴含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。一般来说咱们是不应该可能获取到这个值的,然而当初浏览器中都实现了 proto 属性来让咱们拜访这个属性,然而咱们最好不要应用这个属性,因为它不是标准中规定的。ES5 中新增了一个 Object.getPrototypeOf() 办法,咱们能够通过这个办法来获取对象的原型。当咱们拜访一个对象的属性时,如果这个对象外部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有本人的原型,于是就这样始终找上来,也就是原型链的概念。原型链的止境一般来说都是 Object.prototype 所以这就是咱们新建的对象为什么可能应用 toString() 等办法的起因。 特点:JavaScript 对象是通过援用来传递的,咱们创立的每个新对象实体中并没有一份属于本人的原型正本。当咱们批改原型时,与 之相干的对象也会继承这一扭转原型(prototype): 一个简略的对象,用于实现对象的 属性继承。能够简略的了解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都蕴含一个__proto__(非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行拜访。构造函数: 能够通过new来 新建一个对象 的函数。实例: 通过构造函数和new创立进去的对象,便是实例。 实例通过__proto__指向原型,通过constructor指向构造函数。以Object为例,咱们罕用的Object便是一个构造函数,因而咱们能够通过它构建实例。// 实例const instance = new Object()则此时, 实例为instance, 构造函数为Object,咱们晓得,构造函数领有一个prototype的属性指向原型,因而原型为:// 原型const prototype = Object.prototype这里咱们能够来看出三者的关系: ...

February 14, 2023 · 4 min · jiezi

关于javascript:从URL输入到页面展现到底发生什么

从开发&运维角度方面来看,总体来说分为以下几个过程: DNS 解析:将域名解析成 IP 地址TCP 连贯:TCP 三次握手发送 HTTP 申请服务器解决申请并返回 HTTP 报文浏览器解析渲染页面断开连接:TCP 四次挥手一、什么是URL?URL(Uniform Resource Locator),对立资源定位符,用于定位互联网上资源,俗称网址。 scheme: // host.domain:port / path / filename ? abc = 123 # 456789 scheme - 定义因特网服务的类型。常见的协定有 http、https、ftp、file, 其中最常见的类型是 http,而 https 则是进行加密的网络传输。host - 定义域主机(http 的默认主机是 www)domain - 定义因特网域名,比方 baidu.comport - 定义主机上的端口号(http 的默认端口号是 80)path - 定义服务器上的门路(如果省略,则文档必须位于网站的根目录中)。filename - 定义文档/资源的名称query - 即查问参数fragment - 即 # 后的hash值,个别用来定位到某个地位二、DNS域名解析在浏览器输出网址后,首先要通过域名解析,因为浏览器并不能间接通过域名找到对应的服务器,而是要通过 IP 地址。 IP 地址IP 地址是指互联网协议地址,是 IP Address 的缩写。IP 地址是 IP 协定提供的一种对立的地址格局,它为互联网上的每一个网络和每一台主机调配一个逻辑地址,以此来屏蔽物理地址的差别。什么是域名解析DNS 协定提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务。DNS 是一个网络服务器,咱们的域名解析简略来说就是在 DNS 上记录一条信息记录。浏览器如何通过域名去查问 URL 对应的 IP 呢?DNS域名解析分为递归查问和迭代查问两种形式,现个别为迭代查问。 ...

February 14, 2023 · 2 min · jiezi

关于javascript:京东前端经典面试题整理

img的srcset属性的作⽤?响应式页面中常常用到依据屏幕密度设置不同的图片。这时就用到了 img 标签的srcset属性。srcset属性用于设置不同屏幕密度下,img 会主动加载不同的图片。用法如下: <img src="image-128.png" srcset="image-256.png 2x" />应用下面的代码,就能实现在屏幕密度为1x的状况下加载image-128.png, 屏幕密度为2x时加载image-256.png。 依照下面的实现,不同的屏幕密度都要设置图片地址,目前的屏幕密度有1x,2x,3x,4x四种,如果每一个图片都设置4张图片,加载就会很慢。所以就有了新的srcset规范。代码如下: <img src="image-128.png" srcset="image-128.png 128w, image-256.png 256w, image-512.png 512w" sizes="(max-width: 360px) 340px, 128px" />其中srcset指定图片的地址和对应的图片品质。sizes用来设置图片的尺寸零界点。对于 srcset 中的 w 单位,能够了解成图片品质。如果可视区域小于这个品质的值,就能够应用。浏览器会主动抉择一个最小的可用图片。 sizes语法如下: sizes="[media query] [length], [media query] [length] ... "sizes就是指默认显示128px, 如果视区宽度大于360px, 则显示340px。 左右居中计划行内元素: text-align: center定宽块状元素: 左右 margin 值为 auto不定宽块状元素: table布局,position + transform/* 计划1 */.wrap { text-align: center}.center { display: inline; /* or */ /* display: inline-block; */}/* 计划2 */.center { width: 100px; margin: 0 auto;}/* 计划2 */.wrap { position: relative;}.center { position: absulote; left: 50%; transform: translateX(-50%);}Loader和Plugin 有什么区别Loader:直译为"加载器"。Webpack将所有文件视为模块,然而webpack原生是只能解析js文件,如果想将其余文件也打包的话,就会用到loader。 所以Loader的作用是让webpack领有了加载和解析非JavaScript文件的能力。 Plugin:直译为"插件"。Plugin能够扩大webpack的性能,让webpack具备更多的灵活性。 在 Webpack 运行的生命周期中会播送出许多事件,Plugin 能够监听这些事件,在适合的机会通过 Webpack 提供的 API 扭转输入后果。 ...

February 14, 2023 · 5 min · jiezi

关于javascript:从输入URL到渲染的完整过程

浏览器有一个重要的安全策略,称之为「同源策略」 其中,源=协定+主机+端口,**两个源雷同,称之为同源,两个源不同,称之为跨源或跨域 同源策略是指,若页面的源和页面运行过程中加载的源不统一时,出于平安思考,浏览器会对跨域的资源拜访进行一些限度 同源策略对 ajax 的跨域限度的最为凶狠,默认状况下,它不容许 ajax 拜访跨域资源 所以,咱们通常所说的跨域问题,就是同源策略对 ajax 产生的影响 有多种形式解决跨域问题,常见的有: 代理,罕用CORS,罕用JSONP无论应用哪一种形式,都是要让浏览器晓得,我这次跨域申请的是本人人,就不要拦挡了。 跨域解决办法1-代理对于前端开发而言,大部分的跨域问题,都是通过代理解决的 代理实用的场景是:生产环境不产生跨域,但开发环境产生跨域 因而,只须要在开发环境应用代理解决跨域即可,这种代理又称之为开发代理 在理论开发中,只须要对开发服务器稍加配置即可实现 // vue 的开发服务器代理配置// vue.config.jsmodule.exports = { devServer: { // 配置开发服务器 proxy: { // 配置代理 "/api": { // 若申请门路以 /api 结尾 target: "http://dev.taobao.com", // 将其转发到 http://dev.taobao.com }, }, },};跨域解决办法2-JSONP在CORS呈现之前,人们想了一种微妙的方法来实现跨域,这就是JSONP。 要实现JSONP,须要浏览器和服务器来一个浑然一体的绝妙配合。 JSONP的做法是:当须要跨域申请时,不应用AJAX,转而生成一个script元素去申请服务器,因为浏览器并不阻止script元素的申请,这样申请能够达到服务器。服务器拿到申请后,响应一段JS代码,这段代码实际上是一个函数调用,调用的是客户端事后生成好的函数,并把浏览器须要的数据作为参数传递到函数中,从而间接的把数据传递给客户端 JSONP有着显著的毛病,即其只能反对GET申请 跨域解决办法3-CORS概述CORS是基于http1.1的一种跨域解决方案,它的全称是Cross-Origin Resource Sharing,跨域资源共享。 它的总体思路是:如果浏览器要跨域拜访服务器的资源,须要取得服务器的容许 而要晓得,一个申请能够附带很多信息,从而会对服务器造成不同水平的影响 比方有的申请只是获取一些新闻,有的申请会改变服务器的数据 针对不同的申请,CORS 规定了三种不同的交互模式,别离是: 简略申请须要预检的申请附带身份凭证的申请这三种模式从上到下层层递进,申请能够做的事越来越多,要求也越来越严格。 上面别离阐明三种申请模式的具体标准。 简略申请当浏览器端运行了一段 ajax 代码(无论是应用 XMLHttpRequest 还是 fetch api),浏览器会首先判断它属于哪一种申请模式 ...

February 14, 2023 · 2 min · jiezi

关于javascript:手写一个前端存储工具库

在我的项目开发的过程中,为了缩小进步性能,缩小申请,开发者往往须要将一些不易扭转的数据放入本地缓存中。如把用户应用的模板数据放入 localStorage 或者 IndexedDB。代码往往如下书写。 // 这里将数据放入内存中let templatesCache = null;// 用户id,用于多账号零碎const userId: string = '1';const getTemplates = ({ refresh = false} = { refresh: false}) => { // 不须要立刻刷新,走存储 if (!refresh) { // 内存中有数据,间接应用内存中数据 if (templatesCache) { return Promise.resolve(templatesCache) } const key = `templates.${userId}` // 从 localStorage 中获取数据 const templateJSONStr = localStroage.getItem(key) if (templateJSONStr) { try { templatesCache = JSON.parse(templateJSONStr); return Promise.resolve(templatesCache) } catch () { // 解析失败,革除 storage 中数据 localStroage.removeItem(key) } } } // 进行服务端掉用获取数据 return api.get('xxx').then(res => { templatesCache = cloneDeep(res) // 存入 本地缓存 localStroage.setItem(key, JSON.stringify(templatesCache)) return res })};能够看到,代码十分冗余,同时这里的代码还没有解决数据版本、过期工夫以及数据写入等性能。如果再把这些性能点退出,代码将会更加简单,不易保护。 ...

February 14, 2023 · 8 min · jiezi

关于javascript:30个Javascript知识点总结总有你不会的

最近重温了一遍红宝书,发现一些比拟好玩的写法,很多货色日常都在用,然而发现还会有不一样的写法,联合一些日常工作中应用的办法,为大家总结一篇日常常常应用可能还不晓得的点,心愿对你能有所帮忙: 一行代码实现构造加赋值咱们日常常常应用构造赋值,个别都是先构造,再赋值,当然咱们也能够一行就实现解构加赋值操作,看起来十分简化,当然可读性你懂得! let people = { name: null, age: null };let result = { name: '张三', age: 16 };({ name: people.name, age: people.age} = result);console.log(people) // {"name":"张三","age":16}###对根底数据类型进行解构日常中咱们应该用不到这样的场景,然而实际上咱们也能够对根底数据类型解构 const {length : a} = '1234';console.log(a) // 4对数组解构疾速拿到最初一项值实际上咱们是能够对数组解构赋值拿到length属性的,通过这个个性也能够做更多的事件。 const arr = [1, 2, 3];const { 0: first, length, [length - 1]: last } = arr;first; // 1last; // 3length; // 3将下标转为中文零一二三...日常可能有的列表咱们须要将对应的012345转为中文的一、二、三、四、五...,在老的我的项目看到还有通过本人手动定义很多行这样的写法,于是写了一个这样的办法转换 export function transfromNumber(number){ const INDEX_MAP = ['零','一'.....] if(!number) return if(number === 10) return INDEX_MAP[number] return [...number.toString()].reduce( (pre, cur) => pre + INDEX_MAP[cur] , '' )}判断整数的不同办法 ...

February 13, 2023 · 2 min · jiezi

关于javascript:Babel配置不要再复制粘贴了带你自己配一个Babel

前言问题咱们在应用各种打包工具,须要配置Babel的时候,置信大家一开始都是间接在网上复制粘贴一段配置过去,而后能跑通就高枕无忧了吧?因而,咱们有时会遇到打包部署后,手机运行呈现白屏问题;或者是,打包后代码包过大,加载迟缓等等问题。 其实这所有,大部分起因是因为咱们对Babel各项配置没有一个零碎的了解,所以即便从网上复制粘贴了配置,呈现问题了,不晓得怎么去剖析呈现的问题。 筹备如果你曾经对Babel曾经有一个大略的理解了,那浏览这篇文章,会让你对配置有一个更零碎的理解;如果你才刚接触Babel,或者对Babel处于懵懵懂懂的状态,那我强烈建议你先浏览这篇文章——想弄懂Babel?你必须得先弄清楚这几个包,它次要介绍剖析了一些概念跟以下几个包: @babel/core@bable/cli@bable/preset-envpolyfill@babel/polyfillcore-js@babel/runtime@babel/plugin-transform-runtime并且为咱们答疑了一些看官网时的纳闷。因为在分明了这几包后,咱们学习配置这块会更容易了解一些。 备注以后@babel/core最新版本是:7.20.12以后@babel/preset-env最新版本是:7.20.2再谈core-js通过上篇文章—— 想弄懂Babel?你必须得先弄清楚这几个包咱们晓得:core-js是一种polyfill,它提供了旧版本浏览器缺失的所有的ES6+ API的办法与实现。 在这里,以及下文,咱们把通过引入core-js的某个模块,来实现旧版本浏览器不反对的某个ES6+ API的过程,叫做垫平。 咱们看看core-js这个包外面的次要一些模块: es:外面只蕴含有稳固的ES性能。proposals:外面蕴含所有stage阶段的APIstable:它外面蕴含了,只有稳固的ES性能跟网络规范所以,咱们能够这么应用: 当咱们只须要垫平某个稳固的ES6+ API,咱们能够用es这个文件夹里的polyfill来垫平 (import X from 'es/xx')当咱们须要用到提案阶段的API时,我就用proposals这个文件夹里的polyfill来垫平(import X from 'proposals/xx')当咱们想垫平所有稳固版本的ES6+ API,能够导入用stable文件夹(import 'core-js/stable')当咱们想垫平所有的ES6+ API(包含提案阶段),能够间接import 'core-js'以上是我集体的应用习惯,因人而异,具体的介绍能够看看参考文章。 参考文章:core-js 再谈@bable/preset-env通过上篇文章—— 想弄懂Babel?你必须得先弄清楚这几个包,咱们晓得: Babel大体由两个性能组成: 编译ES6+最新语法(let、class、() => {}等)实现旧版本浏览器不反对的ES6+的API(Promise、Symbol、Array.prototype.includes等)@babel/preset-env有以下两个性能: 它只编译ES6+语法它并不提供polyfill,然而能够通过配置咱们代码运行的指标环境,从而管制polyfill的导入跟语法编译,使ES6+的新个性能够在咱们想要的指标环境中顺利运行@babel/plugin-transform-runtime也有以下两个性能: @babel/runtime跟@babel/plugin-transform-runtime两者配合,能够缩小打包体积也有一个配置性能,用来解决polyfill如何垫平如果咱们想要在旧浏览器用到ES6+ API时,咱们应该装置3版本的core-js(或者后续更高版本的);那咱们能够很分明的晓得: 实现Babel第一个性能:咱们用@babel/preset-env就能够了实现Babel第二个性能:咱们就须要用core-js这个包来提供polyfill,并与@babel/preset-env或者@babel/plugin-transform-runtime的配置性能相互配合应用咱们先来看看@babel/preset-env的配置项有哪些: // babel.config.jsconst presets = [ [ '@babel/preset-env', { modules, targets, corejs, useBuiltIns, spec, loose, debug, bugfixes, include, exclude, forceAllTransforms, configPath, ignoreBrowserslistConfig, browserslistEnv, shippedProposals } ]];module.exports = {presets};咱们能够看到配置项还是蛮多的(有一些配置项,前期可能会废除),然而,其实咱们平时我的项目中次要用到前四个配置,所以在这里咱们重点来看看前四个配置(能不学的尽量不学,太累了)。 参考文章:@babel/preset-env modules性能:启用ES模块语法向另一种模块类型的转换默认值:auto可取的值:"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false当咱们设置成false的时候,Babel编译产生的一些辅助函数的引入形式会变成ES6的模式引入(import A from 'B')。 ...

February 13, 2023 · 3 min · jiezi

关于javascript:从-微信-JSSDK-认识-JSBridge

前言前段时间因为要实现 H5 挪动端拉取微信卡包并同步卡包数据的性能,于是在我的项目中引入了 微信 JS-SDK(jweixin) 相干包实现性能,但也由此让我对其产生了好奇心,于是打算好好理解下相干的内容,通过查阅相干材料发现这其实属于 JSBridge 的一种实现形式。 因而,只有理解 JSBridge 就能明确 微信 JS-SDK 是怎么一回事。 为什么须要 JSBridge?置信大多数人都有雷同的经验,第一次理解到对于 JSBridge 都是从 微信 JS-SDK(WeiXinJSBridge) 开始,当然如果你从事的是 Hybrid 利用 或 React-Native 开发的话置信你天然(应该、会)很理解。 其实 JSBridge 早就呈现并被理论利用了,如早前桌面利用的音讯推送等,而在挪动端流行的时代曾经越来越须要 JSBridge,因为咱们冀望挪动端(Hybrid 利用 或 React-Native)能做更多的事件,其中包含应用 客户端原生性能 提供更好的 交互 和 服务 等。 然而 JavaScript 并不能间接调用和它不同语言(如 Java、C/C++ 等)提供的性能个性,因而须要一个中间层去实现 JavaScript 与 其余语言 间的一个相互协作,这里通过一个 Node 架构来进行阐明。 Node 架构 核心内容如下: 顶层 Node Api 提供 http 模块、流模块、fs文件模块等等,能够通过 JavaScript 间接调用中间层 Node Bindings 次要是使 JavaScript 和 C/C++ 进行通信,起因是 JavaScript 无奈间接调用 C/C++ 的库(libuv),须要一个两头的桥梁,node 中提供了很多 binding,这些称为 Node bindings底层 V8 + libuv ...

February 13, 2023 · 3 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,前面咱们会实现这个办法。 ...

February 13, 2023 · 6 min · jiezi

关于javascript:前端一面常考手写面试题整理

请实现 DOM2JSON 一个函数,能够把一个 DOM 节点输入 JSON 的格局<div> <span> <a></a> </span> <span> <a></a> <a></a> </span></div>把下面dom构造转成上面的JSON格局{ tag: 'DIV', children: [ { tag: 'SPAN', children: [ { tag: 'A', children: [] } ] }, { tag: 'SPAN', children: [ { tag: 'A', children: [] }, { tag: 'A', children: [] } ] } ]}实现代码如下: function dom2Json(domtree) { let obj = {}; obj.name = domtree.tagName; obj.children = []; domtree.childNodes.forEach((child) => obj.children.push(dom2Json(child))); return obj;}转化为驼峰命名var s1 = "get-element-by-id"// 转化为 getElementByIdvar f = function(s) { return s.replace(/-\w/g, function(x) { return x.slice(1).toUpperCase(); })}批改嵌套层级很深对象的 key// 有一个嵌套档次很深的对象,key 都是 a_b 模式 ,须要改成 ab 的模式,留神不能用递归。const a = { a_y: { a_z: { y_x: 6 }, b_c: 1 }}// {// ay: {// az: {// yx: 6// },// bc: 1// }// }办法1:序列化 JSON.stringify + 正则匹配 ...

February 13, 2023 · 11 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])// 输入:YIYING3bind定义与应用Function.prototype.bind(): developer.mozilla.org/zh-CN/docs/…// Function.prototype.bind()样例function fun(arg1, arg2) { console.log(this.name) console.log(arg1 + arg2)}const _this = { name: 'YIYING' }// 只变更fun中的this指向,返回新function对象const newFun = fun.bind(_this)newFun(1, 2)// 输入:YIYING3参考 前端进阶面试题具体解答 ...

February 13, 2023 · 2 min · jiezi

关于javascript:可视化搭建内置-API

在设计好画布与组件数据流体系后,实践上主体性能曾经实现,但不足不便易用的 API,所以还须要内置一些状态与办法。 然而内置状态与办法必须寻求业务的最大公约数,极具抽象性,增加需谨慎。 接下来咱们从必须有与倡议有的角度,看看一个可视化搭建须要内置哪些 API。 状态状态是可变的,援用形式有如下两种。 第一种在任意 React 组件内通过 useDesigner 拜访,当状态变动时会触发所在组件重渲染: const { componentTree } = useDesigner((state) => ({ componentTree: state.componentTree,}));第二种在任意组件元信息内通过 selector 拜访,当状态变动时会触发不同行为,比方在 runtimeProps 会触发组件重渲染,在 fetcher 会触发从新查问: const tableMeta = { /** ... */ runtimeProps: ({ selector }) => { const { componentTree } = selector(({ state }) => ({ componentTree: state.componentTree, })); return { componentTree }; },};componentTree评估:必须有类型:ComponentInstance形容残缺组件树 JSON 构造。在非受控模式下,组件树就存储在 <Designer /> 实例外部,而受控模式下,组件树存储在内部状态。 但咱们容许这两种模式都能够拜访此状态,这样在开发可视化搭建利用的过程中,就不必关怀受控或非受控模式了,即一套代码同时兼容受控与非受控模式。 selectedComponentIds评估:倡议有类型:string[]定义以后选中组件实例 id 列表。 尽管这个状态业务也能够定义,但选中组件在可视化搭建是一种常见行为,当前定义插件、自定义组件兴许都会读取以后选中的组件,如果框架定义了此通用 key,那么插件和自定义组件就可无缝联合到任意业务代码里。反之如果在业务层定义该状态,插件或者自定义组件也不晓得如何规范的读取到以后选中的组件。 ...

February 13, 2023 · 2 min · jiezi

关于javascript:前端必会面试题

let 闭包let 会产生临时性死区,在以后的执行上下文中,会进行变量晋升,然而未被初始化,所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,就援用此变量就会报错,此变量未初始化。 数组的遍历办法有哪些办法是否扭转原数组特点forEach()否数组办法,不扭转原数组,没有返回值map()否数组办法,不扭转原数组,有返回值,可链式调用filter()否数组办法,过滤数组,返回蕴含符合条件的元素的数组,可链式调用for...of否for...of遍历具备Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历一般的obj对象,将异步循环变成同步循环every() 和 some()否数组办法,some()只有有一个是true,便返回true;而every()只有有一个是false,便返回false.find() 和 findIndex()否数组办法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值reduce() 和 reduceRight()否数组办法,reduce()对数组正序操作;reduceRight()对数组逆序操作其余值到字符串的转换规则?Null 和 Undefined 类型 ,null 转换为 "null",undefined 转换为 "undefined",Boolean 类型,true 转换为 "true",false 转换为 "false"。Number 类型的值间接转换,不过那些极小和极大的数字会应用指数模式。Symbol 类型的值间接转换,然而只容许显式强制类型转换,应用隐式强制类型转换会产生谬误。对一般对象来说,除非自行定义 toString() 办法,否则会调用 toString()(Object.prototype.toString())来返回外部属性 [[Class]] 的值,如"[object Object]"。如果对象有本人的 toString() 办法,字符串化时就会调用该办法并应用其返回值。浏览器是如何对 HTML5 的离线贮存资源进行治理和加载?在线的状况下,浏览器发现 html 头部有 manifest 属性,它会申请 manifest 文件,如果是第一次拜访页面 ,那么浏览器就会依据 manifest 文件的内容下载相应的资源并且进行离线存储。如果曾经拜访过页面并且资源曾经进行离线存储了,那么浏览器就会应用离线的资源加载页面,而后浏览器会比照新的 manifest 文件与旧的 manifest 文件,如果文件没有产生扭转,就不做任何操作,如果文件扭转了,就会从新下载文件中的资源并进行离线存储。离线的状况下,浏览器会间接应用离线存储的资源。当在浏览器中输出 Google.com 并且按下回车之后产生了什么?(1)解析URL: 首先会对 URL 进行解析,剖析所须要应用的传输协定和申请的资源的门路。如果输出的 URL 中的协定或者主机名不非法,将会把地址栏中输出的内容传递给搜索引擎。如果没有问题,浏览器会查看 URL 中是否呈现了非法字符,如果存在非法字符,则对非法字符进行本义后再进行下一过程。 (2)缓存判断: 浏览器会判断所申请的资源是否在缓存里,如果申请的资源在缓存里并且没有生效,那么就间接应用,否则向服务器发动新的申请。 (3)DNS解析: 下一步首先须要获取的是输出的 URL 中的域名的 IP 地址,首先会判断本地是否有该域名的 IP 地址的缓存,如果有则应用,如果没有则向本地 DNS 服务器发动申请。本地 DNS 服务器也会先查看是否存在缓存,如果没有就会先向根域名服务器发动申请,取得负责的顶级域名服务器的地址后,再向顶级域名服务器申请,而后取得负责的权威域名服务器的地址后,再向权威域名服务器发动申请,最终取得域名的 IP 地址后,本地 DNS 服务器再将这个 IP 地址返回给申请的用户。用户向本地 DNS 服务器发动申请属于递归申请,本地 DNS 服务器向各级域名服务器发动申请属于迭代申请。 ...

February 13, 2023 · 3 min · jiezi

关于javascript:promise执行顺序面试题令我头秃你能作对几道

阐明最近在温习 Promise 的常识,所以就做了一些题,这里挑出几道题,大家一起看看吧。 题目一const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2);})promise.then(() => { console.log(3);})console.log(4);解析首先 Promise 新建后立刻执行,所以会先输入 1,2,而 Promise.then() 外部的代码在 当次 事件循环的 结尾 立即执行 ,所以会持续输入4,最初输入3。 答案1243题目二const promise = new Promise((resolve, reject) => { resolve('success1'); reject('error'); resolve('success2');});promise.then((res) => { console.log('then:', res);}).catch((err) => { console.log('catch:', err);})解析resolve 函数将 Promise 对象的状态从“未实现”变为“胜利”(即从 pending 变为 resolved),在异步操作胜利时调用,并将异步操作的后果,作为参数传递进来; reject 函数将 Promise 对象的状态从“未实现”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的谬误,作为参数传递进来。 而一旦状态扭转,就不会再变。所以 代码中的reject('error'); 不会有作用。 Promise 只能 resolve 一次,剩下的调用都会被疏忽。所以 第二次的 resolve('success2'); 也不会有作用。 ...

February 13, 2023 · 4 min · jiezi

关于javascript:三次握手与四次挥的问题怎么回答

在面试中,三次握手和四次挥手能够说是问的最频繁的一个知识点了,我置信大家也都看过很多对于三次握手与四次挥手的文章,明天的这篇文章,重点是围绕着面试,咱们应该把握哪些比拟重要的点,哪些是比拟被面试官给问到的,我感觉如果你能把我上面列举的一些点都记住、了解,我想就差不多了。 三次握手因为在面试中,三次握手是被问的最频繁的面试题,所以本次咱们从面试的角度来解说三次握手当面试官问你为什么须要有三次握手、三次握手的作用、讲讲三次三次握手的时候,我想很多人会这样答复: 首先很多人会先讲下握手的过程: 1、第一次握手:客户端给服务器发送一个 SYN 报文。 2、第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文。 3、第三次握手:客户端收到 SYN+ACK 报文之后,会回应一个 ACK 报文。 4、服务器收到 ACK 报文之后,三次握手建设实现。 作用是为了确认单方的接管与发送能力是否失常。 这里我顺便解释一下为啥只有三次握手能力确认单方的承受与发送能力是否失常,而两次却不能够: 第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接管能力是失常的。 第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接管、发送能力,客户端的接管、发送能力是失常的。不过此时服务器并不能确认客户端的接管能力是否失常。 第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接管、发送能力失常,服务器本人的发送、接管能力也失常。 因而,须要三次握手能力确认单方的接管与发送能力是否失常。 这样答复其实也是能够的,但我感觉,这个过程的咱们应该要形容的更具体一点,因为三次握手的过程中,单方是由很多状态的扭转的,而这些状态,也是面试官可能会问的点。所以我感觉在答复三次握手的时候,咱们应该要形容的具体一点,而且形容的具体一点意味着能够扯久一点。加分的形容我感觉应该是这样: 刚开始客户端处于 closed 的状态,服务端处于 listen 状态。而后 1、第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 SN(c)。此时客户端处于 SYN_Send 状态。 2、第二次握手:服务器收到客户端的 SYN 报文之后,会以本人的 SYN 报文作为应答,并且也是指定了本人的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,示意本人曾经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。 3、第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,示意曾经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。 4、服务器收到 ACK 报文之后,也处于 establised 状态,此时,单方以建设起了链接。 ...

February 13, 2023 · 2 min · jiezi

关于javascript:ES5和ES6之间的区别

ECMAScript是ECMA International定义的商标脚本语言标准。 创立它是为了标准化JavaScript。 ES脚本语言具备许多实现,风行的实现是JavaScript。 通常,ECMAScript用于万维网的客户端脚本。ES5是ECMAScript 5的缩写,也被称为ECMAScript2009。ECMAScript规范的第六版是ES6或ECMAScript6。它也被称为ECMAScript2015。ES6是JavaScript语言的次要加强,容许咱们编写程序。ES6实用于简单的应用程序。 只管ES5和ES6在实质上有一些相似之处,但它们之间也有许多不同之处 代码转换到目前为止,还没有齐全反对ES6性能的浏览器。 然而,咱们能够应用转译将ES6代码转换为ES5代码。 有两个次要的编译器Babel和Traceur,用于在构建过程中将ES6代码转换为ES5代码。 点差运算符(…)它在ES6中引入,使合并数组和对象变得容易。 let & var & const const命令的用法和let类似,最大不同点就是:const申明一个只读的常量。一旦申明,常量的值就不能扭转。 ES5 只有两种申明变量的办法:var命令和function命令。 ES6 除了增加let和const命令,另外两种申明变量的办法:import命令和class命令。所以,ES6 一共有 6 种申明变量的办法

February 12, 2023 · 1 min · jiezi

关于javascript:this你到底是谁javascript

this是javascript前端编程中十分罕用的一个关键字,也是面试常考题目,然而因为this不是其余面向对象语言的固定指向,而是状况不同的调用代码,会产生不同指向的this。上面咱们就零碎的剖析下咱们在编程时,如何了解每种状况下的this指向。 this的定义首先,咱们面对一个编程语言问题的时候,特地是关键字或者原生API的时候,第一反馈应该是去查官网文档,因为官网文档才是最正确,最权威,最艰深的解释,这也是我编程这么多年的经验总结。上面是this在MDN Web Docs中的解释 在与其余语言相比,函数的 this 关键字在 JavaScript 中的体现略有不同,此外,在严格模式和非严格模式之间也会有一些差异。 绝大多数状况下,函数的调用形式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。ES5 引入了 bind 办法来设置函数的 this 值,而不必思考函数如何被调用的。ES2015 引入了箭头函数,箭头函数不提供本身的 this 绑定(this 的值将放弃为闭合词法上下文的值)。 其中最重要的一句是,”函数的调用形式决定了 this 的值(运行时绑定)“,咱们能够了解为在例如person.run()调用时,run办法中的this指向的是person这个对象。 下一章节中依据具体案例具体分析一下。(下列状况均指在非严格模式下的状况剖析) this的案例剖析咱们将应用6个案例来剖析this的每种场景下的含意 案例1 函数执行function run(){ console.log('this->' + this)}run()//this->[object Window]console.log('this->' + this)//this->[object Window]var title = 'window'function doJob(){ let title = 'doJob' function test(){ console.log('this->' + this.title)//this->window } test()}doJob()第一个是打印执行run时的this对象,因为未指定run的执行对象,默认this指向window。 第二个是在全局环境下执行打印this,此时this也是默认的window对象。 第三个的重点是看test的执行,test是独自执行,没有任何绑定对象,所以test中的this是window对象 案例2 对象创立function run(){ this.sum = 18 console.log('this->' + this)}new run()//this->[object Object]let person = {name:'123',prun:run};person.prun()//this->[object Object]let arr = [1,2,run]arr[2]() //this->1,2,function run(){...}留神: new在执行时会做四件事件 ...

February 12, 2023 · 1 min · jiezi

关于javascript:D3js-绘制柱状图二

前言上一篇文章 咱们讲了 D3.js 中一些常见的 API,并且通过一个 demo 理解了 D3.js 是如何工作的。铺垫完之后,这篇文章咱们正儿八经的来实现一个柱状图。 注释比例尺比例尺是 D3.js 中一个重要的概念,它用于在值和坐标之间的互相转换。本文中呈现的相干 API 如下 API阐明scaleBand个别用于将一组离散值映射到间断范畴的值scaleLinear线性转换,将间断的输出域映射到间断的输入范畴设想一下,咱们须要在一个 800 x 600 宽高的容器内绘制一个坐标系。通常状况下,坐标的数值不会与理论的宽高齐全对应。因而,咱们须要一种工具来将理论的宽高与坐标系中的数值进行映射。 对于 scaleLinear 这个线性转换函数,能够用上面的公式来形容: $y = mx + b(b 为任意常量)$ 通过输出 $x$(通常是一个数值),咱们能够取得元素在页面上的高度或宽度。 绘制坐标系首先咱们先增加初始代码:引入 D3.js & 设置根底款式 <html><head> <title>Bar</title> <style> #bar { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; } </style></head><body><div id="bar"></div></body><script src="<https://d3js.org/d3.v7.min.js>"></script></html>紧接着咱们来创立一个 svg,宽高为:800 x 600 const width = 800; const height = 600; const data = Array.from({length: 26}).map((_, i) => ({ name: String.fromCharCode(65 + i), value: Math.random() * 100 })) const svg = d3.select('#bar') .append('svg') .attr('width', width) .attr('height', height)此时页面上仍旧是赤裸裸的一片,没关系,咱们先把 x 轴加上: ...

February 10, 2023 · 2 min · jiezi

关于javascript:前端开发立即执行函数function与function的区别

前言在前端开发过程中,JS中的原理应用知识点是陈词滥调,然而有时候在开发中会疏忽一些细节和不经意的知识点,尤其是刚入行的新晋开发者更是只知其一;不知其二,在对JS整体应用的时候会有所脱漏。那么本篇博文就来分享一下对于在JS中立刻执行函数相干的比照应用总结,不便查阅应用。什么是立刻执行函数申明一个函数,而后立刻调用该函数,这时候的该函数就是一个立刻执行函数,换句话说就是申明函数当前立刻执行该函数就叫做立刻执行函数,即IIFE (Immediately Invoked Function Expression)。通常立刻执行函数会以匿名函数的模式来申明,匿名函数的写法格局为function(){},即应用关键字function来申明函数,且未给该函数命名,然而匿名函数不能间接独自应用,须要应用小括号()包裹起来,不然就会报错。 立刻执行函数的作用立刻执行函数的作用大略有三个方面: 为了防止净化全局变量,申明函数不设置函数名;通过创立一个独立的作用域,使得作用域外面的变量等内容不被作用域之外拜访,防止申明的变量互相净化;JS常见的一个经典知识点,闭包的实现,还有数据私有化的设置。语法立刻执行函数的两种写法模式,如下所示: // 写法一:用小括号把整个函数的定义和括号调用全副包裹起来(function(){// 函数体...}())// 写法二:用小括号只把把函的数定义包裹起来,而后前面再加括号调用(function (){// 函数体...})()须要留神的是:应用小括号包裹是因为浏览器的JS引擎规定要求,如果function放在首行,一律解析成语句,然而在应用立刻执行函数的时候须要浏览器的JS引擎把function解析为一个表达式,所以小括号包裹为的就是解决这个问题的。 函数理论写法场景这里依照个别的一般函数和匿名函数的写法做一个简略的比照,一般函数和匿名函数按程序示意雷同的作用,具体比照如下所示: 1.一般函数模式function bar(){console.log("Hello JavaScript!")}()//在申明的函数前面间接加()会报错(function bar(){console.log("Hello JavaScript!")}())//用小括号把整个函数表达式包起来就能够失常执行(function bar(){console.log("Hello JavaScript!")})()//用小括号把函数包起来也能够失常执行!function bar(){console.log("Hello JavaScript!")}()//应用!取反,只为了通过JS语法查看。+function bar(){console.log("Hello JavaScript!")}()//应用+能够失常执行,只为了通过JS语法查看。-function bar(){console.log("Hello JavaScript!")}()//应用-能够失常执行,只为了通过JS语法查看。~function bar(){console.log("Hello JavaScript!")}()//应用~能够失常执行,只为了通过JS语法查看。void function bar(){console.log("Hello JavaScript!")}()//应用void能够失常执行,只为了通过JS语法查看。new function bar(){console.log("Hello JavaScript!")}()//应用new能够失常执行,只为了通过JS语法查看。2.匿名函数模式(function(){console.log("Anonymous Function!")}())(function(){console.log("Anonymous Function!")})()!function(){console.log("Anonymous Function!")}()+function(){console.log("Anonymous Function!")}()-function(){console.log("Anonymous Function!")}()~function(){console.log("Anonymous Function!")}()void function(){console.log("Anonymous Function!")}()new function(){console.log("Anonymous Function!")}()下面一般函数和匿名函数的比照中,函数对于应用!、+、-、=等运算符,都能让它们起到立刻执行的作用,使函数申明间接转换成了函数表达式,帮忙浏览器的JS引擎辨认它们是函数表达式,不是函数申明。 立刻执行函数传递参数若立刻执行函数外面须要应用函数内部的变量,这就须要通过应用参数传递的形式来解决。在立刻执行函数外部应用的形参就是传递到函数外部的内部变量,进入立刻执行函数本人的作用域,且不受内部变量的影响。具体应用场景如下所示: (function(a){// 应用的形参就是传递到函数外部的内部变量console.log(a)})(b)立刻执行函数的返回值立刻执行函数和其余函数一样都是能够返回任意类型的值,次要是通过返回值来实现闭包的需要,具体示例如下所示: var res = (function(){var aaa = 123456;return function() { return aaa;}})()// 该立刻执行函数的返回值是一个函数,所以须要通过 () 来调用即可console.log(res()) //输入后果为:123456 这里须要延长一下,立刻执行函数和闭包有一个独特长处就是能缩小全局变量的应用。然而它们也有不同之处,立刻执行函数只是函数的一种调用形式,在申明之后就立刻执行,该类函数个别都只调用一次,而且调用完之后会立刻销毁,不会占用内存;可是闭包次要让内部函数可能拜访外部函数的作用域,尽管也是缩小了全局变量的应用保障了外部变量的安全性,然而因被援用的外部变量不能被销毁,就增大了内存耗费,且使用不当很容易造成内存泄露。 (function(){}())与(function(){})()的区别通过下面对于立刻执行函数的介绍,(function(){}())与(function(){})()的区别这个问题,是从不同角度来看的,然而从最终的后果来看,二者没啥区别,是一回事,得出该论断的根据就是(function(){}())与(function(){})()的AST是雷同的,而且最初的后果都是一次性函数调用,以及最初解析器产生的后果也是统一的没啥区别,它们的性能也是雷同的:创立一个函数并且立刻调用执行。 最终的后果就是:(function(){}())与(function(){})()没有区别,它们是雷同的,不仅能够立刻执行函数,而且能够模仿块级作用域。 最初通过下面介绍(function(){}())与(function(){})()的区别总结,是不是彻底把握了相干知识点以及应用原理?这个知识点很重要,不论是在理论开发过程中还是在求职面试中,都是高频知识点,所以必须要彻底把握,尤其是对于vue初学者来讲更是要把握,这里不再过多赘述重要性。以上就是本章的全部内容,欢送关注三掌柜的微信公众号“程序猿by三掌柜”,三掌柜的新浪微博“三掌柜666”,欢送关注! 本文参加了「SegmentFault 思否写作挑战赛」,欢送正在浏览的你也退出。 ...

February 10, 2023 · 1 min · jiezi

关于javascript:前端开发HTTP状态码详解

前言在前端开发过程中,对于HTTP网络申请相干的应用也是必备的,尤其是前后端交互的时候,依据理论业务实现具体需要性能。前端理论开发利用场景中,比拟有代表性的对于网络申请相干的应用有:跨域问题/设置代理、接口返回code码(HTTP状态码)、代理、token、cookie欺诈、GET/POST申请等等,这些都是罕用知识点。那么本篇博文就来分享一下对于HTTP状态码相干的知识点,尤其是不同结尾的code码代表的含意,总结一下,不便查阅应用。HTTP状态码是什么?维基百科的解释:HTTP状态码(HTTP Status Code)是用以示意网页服务器超文本传输协定响应状态的3位数字代码。它由 RFC 2616 标准定义的,并失去 RFC 2518、RFC 2817、RFC 2295、RFC 2774 与 RFC 4918 等标准扩大。所有状态码被分为五类,状态码的第一个数字代表了响应的五种状态之一。所示的音讯短语是典型的,然而能够提供任何可读取的代替计划。 除非另有阐明,状态码是HTTP/1.1规范(RFC 7231)的一部分。 百度百科的解释:HTTP状态码(HTTP Status Code)是用以示意网页服务器HTTP响应状态的3位数字代码。它由 RFC 2616 标准定义的,并失去RFC 2518、RFC 2817、RFC 2295、RFC 2774、RFC 4918等标准扩大。所有状态码的第一个数字代表了响应的五种状态之一。 集体了解:HTTP状态码,也就是一个3位数的HTTP申请响应状态码,也就是前端开发中说的code码,接口依据状态类型来返回对应的状态码。 常见HTTP 状态码作为程序开发者,都晓得且在理论开发中常见的HTTP状态码,如下所示: 200 - 申请胜利;301 - 资源(网页等)被永恒转移到其它URL;304 - 客户端通常会缓存拜访过的资源,通过提供一个Header头信息指出客户端心愿只返回在指定日期之后批改的资源信息;404 - 申请的资源(网页等)不存在;500 - 外部服务器谬误。HTTP状态码分类通过上文能够晓得HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。HTTP响应分为五类:信息响应(100–199)、胜利响应(200–299)、重定向(300–399)、客户端谬误(400–499)和服务器谬误 (500–599)。具体如下表所示: HTTP状态码具体分类汇总全副的HTTP状态码有很多,这里只分享罕用的状态码,具体如下所示: 1、 1*结尾(信息提醒),示意长期的响应的状态码(留神:客户端在收到惯例响应之前,应筹备接管一个或多个 1 * 响应)。 100 - Continue 持续。初始申请已被承受,客户该当持续发送申请的其余部分。101 - Switching Protocols 切换协定。 服务器将听从客户端的申请切换到另外一种协定,且只能切换到更高级的协定。2、 2**结尾 (申请胜利),示意胜利接管解决申请的状态码。 200 - 申请胜利。 服务器已胜利解决了申请, 个别这示意服务器提供了申请的网页,次要是用于GET和POST申请。201 - 已创立。 申请胜利并且创立了新的资源。202 - 已承受。 服务器曾经承受申请,但尚未处理完毕。203 - 非受权信息。申请胜利,服务器已胜利解决了申请,但返回的meta信息可能来自另一起源,而是一个正本。204 - 无内容。 服务器胜利解决申请,但没有返回任何内容。205 - 重置内容。 服务器胜利解决申请,但没有返回任何内容,客户端应该重置文档视图。206 - 局部内容。 服务器胜利解决了局部 GET 申请。3、 3** 结尾 (申请被重定向),示意要实现申请,须要进一步操作的状态码(留神:个别状况下这些状态代码被用来重定向)。 ...

February 10, 2023 · 2 min · jiezi

关于javascript:前段实现gzip与json之间的转换

https://www.cnblogs.com/zsw-w...https://blog.csdn.net/m0_4951...https://codeleading.com/artic...

February 9, 2023 · 1 min · jiezi

关于javascript:前端开发JS中原型和原型链的详解

前言在前端开发过程中,波及到JS原理相干的内容也就是罕用的几大模块,不仅罕用而且很重要,然而波及到原理的话会有点难懂,尤其是对JS接触不太久的开发者来讲。本篇博文就来分享一下对于JS的原型和原型链相干的知识点,尽管简单、难懂然而很重要,值得珍藏,不便前期查阅应用。一、prototype背景JS 中,除了根本数据类型(也叫简略数据类型)之外的类型,都是援用数据类型(也叫简单数据类型),即对象;也就是说,在JS的宇宙中,所有皆是对象。 在ES6之前,因为JS中没有类的概念(在ES6的时候引入了class,但其也只是语法糖),在理论开发中想要将所有的对象关联起来就成了问题,于是原型和原型链的概念应运而生。 原型字面释义(来源于网络)原型(prototype)这个词来自拉丁文的词proto,意谓“最后的”,意义是模式或模型。在非技术类的文中,一个原型是给定品种的一个代表性例子。 在以原型为根底的程序方面,一个原型是一个最后的对象(object);新的物体藉由复制原型产生。 JS中原型(Prototype)的概念对于这个JS中的原型概念,网上有太多文章,释义也是大同小异,那么在这里依据网上有用的释义以及本人的总结,从新总结一下JS中原型的概念,由浅及深的释义,具体如下所示: JS中的原型(Prototype)是基于继承来讲的,其实原型就是一个对象,它是JS中继承的根底,JS外面的继承就是基于原型来继承的,原型的作用就是为了实现对象的继承。JS中每个对象在创立的时候都会与之关联另外一个对象,这个关联的对象就是原型,每个对象都会从原型中继承。须要留神的是object比拟非凡,它没有对应的原型。原型(Prototype)的其余释义原型能够了解为是一个JS办法的属性,每次在创立函数办法的时候,JS会将一个名字为prototype的属性增加到函数办法上,这个prototype就是该函数办法的原型对象,它默认有一个constructor的属性指向原来办法的对象,任何增加到prototype的属性和办法都在这个constructor外面,所有同类的实例会共享这个原型对象,实例对象__proto__属性指向这个对象,办法的prototype属性指向这个对象。 其实,每个函数都会对应有一个prototype属性,prototype就是应用构造函数创立的对象的原型,它其实是一个指针,指向原型对象,该原型对象蕴含属性和办法能够被所有实例共享应用,构造函数中的prototype是显性原型,原型对象有一个constructor属性,指向函数自身。 原型对象(prototype)为什么下面解释过原型的内容之后,这里再写原型对象呢?是因为网上写法太多,容易让不太分明的开发者呈现云里雾里的感觉,所以再独自提一下。具体如下所示:function Function(){}console.log(Function.prototype) 输入后果如下所示: 在JS中,每个函数都有一个prototype属性,这个属性指向函数的原型(也叫显式原型),这个原型是一个对象,所以prototype也叫原型对象,每一个JS对象都会从一个prototype中继承属性和办法。 每个实例对象(object)都有一个公有属性(即__proto__)指向它的构造函数的原型对象,该原型对象也有一个本人的原型对象,逐层向上直到一个对象的原型对象为null的时候,依据定义流程来讲,null是没有原型的,所以到这里就作为一个原型链中的最初一步,原型链会在上面介绍。 __proto__属性(留神proto左右两边各是2个下划线)JS中的所有对象(null除外)都存在一个__proto__属性(__proto__不是规范属性,只实用于部分的浏览器,规范的形式是应用Object.getPrototypeOf()),__proto__指向实例对象的构造函数的原型(即原型对象),__proto__个别也被叫做隐式原型,它也蕴含一个constructor属性,该属性指向的是创立该实例的构造函数,具体示例如下所示: function Student(name) { this.name = name;}var student = new Student("LiMing");console.log(student._proto === Student.prototype ) //输入后果为:true 通过下面示例能够看到,stu是实例对象,Student是student的构造函数,student的__proto__属性指向构造函数Person的原型。最初,其实绝大多数的浏览器都反对__proto__这个非标准的办法拜访原型,但它不存在于 Student.prototype中,实际上是来自于 Object.prototype,相当于是一个getter/setter,在须要应用object.proto的时候就是返回的Object.getPrototypeOf(object)。 留神:如果调用实例对象的办法查不到,就会去原型对象外面持续查找。 hasOwnProperty办法当去拜访一个对象的属性的时候,该属性可能来自该对象本人,也可能来自该对象的属性指向的原型,在不确定这个对象的起源的时候,就要用到hasOwnProperty()办法来判断一个属性是否来自对象本身。 留神:通过hasOwnProperty()办法能够判断一个对象是否在对象本身中增加,但不能够判断是否存在于原型中,因为极有可能该属性就不存在,即在原型中不论属性存在与否都会返回false。 in关键字(操作符)in关键字或者说是操作符,是用来判断一个属性是否存在于该对象中,但在查找这个属性的时候,首先会在对象本身中查找,如果在对象本身中找不到会再去原型中找。也就是说只有对象和原型中有一个中央存在该属性,就返回true。 延长:在判断一个属性是否存在于原型中,若该属性存在,但不在对象本身中,那么该属性肯定存在于原型中! 原对象的原型在JS中所有原有援用类型都会在其构造函数的原型上定义方法,也就是通过Object构造函数生成的,应用最原始的形式创立,实例的proto指向构造函数的prototype。 原型与实例当读取实例属性的时候,若找不到该属性,就会查找与该实例关联的原型中的属性,若还查不到,就会去找原对象的原型,依此类推,直到找到最上层为止。 原型的作用1、应用曾经继承的办法解决办法过载的问题;2、针对类的性能进行扩大,削减内置的办法和属性等。 原型中的this指向原型中的this指向实例化对象。原型拜访的形式对于原型拜访的形式:如果想要拜访一个对象的原型,能够通过ES5中的Object.getPrototypeOf()办法和ES6中的__proto__属性两种形式来拜访。 原型对象的应用场景在理论开发中,开发者可能会应用JS类库,然而当发现以后的库中不存在想要的属性或者办法的时候,不能批改源码的状况下且不想给每个实例对象独自定义相干属性和办法的时候,此时就能够思考应用原型对象来进行扩大应用。 原型应用的示例示例一:把移除数组中的值的办法增加到数组的原型上,在应用的时候只用调用函数填入值即可。具体如下所示: let fruits =["apple","banana","cherry","orange","melone"];Array.prototype.remove = function(v){this.splice(v,1); // 依据输出的下标截取对应的一个元素return this;}fruits.remove(2); // 输出数组的下标,这里是想要移除数组的第3个元素console.log("----fruits:",fruits); //输入后果为:'apple', 'banana', 'orange', 'melone' 示例二:通过应用原型对象来扩大自定义的对象 function Student() {} //定义Student结构器var stu = new Student(); //实例化对象stu.name = "zhoujielun";stu.age = 28;/* 此时发现短少了手机号属性,应用原型对象进行扩大**/Student.prototype.phone = "185****1111";console.log(stu.phone) //输入后果为:185****1111 ...

February 9, 2023 · 1 min · jiezi

关于javascript:使用-postMessage-跨域名迁移-localStorage

敌人的网站有个需要:要从 A 域名迁徙到 B 域名。所有内容不变,只是更改域名。这个需要不简单,实践上改下配置而后 301 即可。但这个网站是纯动态网站,用户数据都存在 localStorage 里,所以他心愿可能主动帮用户把数据也迁徙到新域名。 咱们晓得,localStorage 是依照域名存储的,B 网站无法访问 A 网站的 localStorage。所以咱们就须要一些非凡的伎俩来实现需求。通过一些调研,咱们筹备应用 postMessage() 来实现这个需要。 大体的计划如下: 首先,减少 migrate.html 页面。 这个页面不须要其它具体性能,只有侦听 message 事件,并且把 localStorage 传出即可。 <!-- migrate.html --><script> window.addEventListener('message', function (message) { const { origin, source } = message; // 验证起源,只承受咱们本人的域名发来的申请 if (origin !== 'https://wordleunlimited.me') return; const local = localStorage.getItem('wordle'); // `source` 是浏览器主动填充的,即调用 `postMessage` 的起源。作为跨域 iframe 里的页面,拿不到外层 window,只能通过这种形式往回传递数据。 source.postMessage({ type: 'migrate', stored: local, }, 'https://wordleunlimited.me'); });</script>而后,在利用里减少 <iframe>,因为我用 Vue3,所以这里也用 Vue 组件的形式解决。 ...

February 9, 2023 · 2 min · jiezi

关于javascript:Vuejs设计与实现学习总结第四章7侦听器

前置知识点:执行调度 https://segmentfault.com/a/11...计算属性 https://segmentfault.com/a/11...注释在上一篇介绍了计算属性的实现原理, 这篇是 Vue 中时常和计算属性做比拟的侦听器的原理实现的简介.所谓的侦听器watch实质上就是观测响应式数据是否发生变化, 当数据发生变化时告诉并执行相应的回调函数: watch (obj, () => { console.log('数据变动了')})// 批改数据导致响应式数据变动obj.foo++实质上是利用了副作用函数effect以及调度选项option.scheduler: effect(() => { console.log(obj.foo)},// options{ scheduler () { // obj.foo 变动时, 执行 scheduler 调度函数 }})如果副作用函数存在scheduler选项, 当响应式数据发生变化时会触发scheduler调度函数执行, 而不是间接触发副作用函数利用这点能够实现最简略的watch函数: function watch (source, cb) { effect( // 触发读取操作, 从而建立联系 () => source.foo, { scheduler () { // obj.foo 变动时, 执行 scheduler 调度函数 cb() } } )}然而这个太根本了, 还只能监听obj.foo这个属性的变动, 因而须要封装一个通用的读取操作, 使watch具备通用性: function watch (source, cb) { effect( // 触发读取操作, 从而建立联系 // 调用函数递归读取将每一个数据都建立联系 () => traverse(source), { scheduler () { // obj.foo 变动时, 执行 scheduler 调度函数 cb() } } )}function traverse (value, seen = new Set()) { // 如果该值是原始数据类型, 或者已被读取过去就什么都不做 if (typeof value !== 'object' || value === null || seen.has(value)) return // 将数据增加到 seen 中, 代表遍历过了 防止引起死循环 seen.add(value) // 假如 value就是就是一个对象, 临时不思考数组等状况 for (const k in value) { // 递归调用 traverse traverse(value[k], seen) } return value}这样就能够读取对象上的任意属性, 从而当任意属性发生变化时都能触发回调函数执行, watch不仅仅能够观测响应函数还能够承受getter函数: ...

February 9, 2023 · 2 min · jiezi

关于javascript:我家等离子电视也能用的移动端适配方案

前几天我的领导“徐江”让我把一个挪动端我的项目做一下适配,最好让他在家用等离子电视也能看看成果,做不进去就给我“埋了”,在这种状况下才诞生了这篇文章~什么是挪动端适配挪动端适配是指在不同尺寸的挪动端设施上,页面能绝对达到正当的显示或者放弃对立的等比缩放成果挪动端适配的两个概念自适应:依据不同的设施屏幕大小来主动调整尺寸、大小响应式:会随着屏幕的实时变动而主动调整,是一种自适应 而在咱们日常开发中自适应布局在pc端和挪动端利用都极为广泛,个别是针对不同端别离做自适应布局,如果要想同时兼容挪动端和pc端,尤其是等离子电视这样的大屏幕,那么最好还是应用响应式布局~ 挪动端适配-视口(viewport)在一个浏览器中,咱们能够看到的区域就是视口(viewport),咱们在css中应用的fixed定位就是绝对于视口进行定位的。 在pc端的页面中,咱们不须要对视口进行辨别,因为咱们的布局视口和视觉视口都是同一个。而在挪动端是不太一样的,因为咱们的挪动端的网页往往很小,有可能咱们心愿一个大的网页在挪动端上也能够残缺的显示,所以在默认状况下,布局视口是大于视觉视口的。 <style> .box { width: 100px; height: 100px; background-color: orange; } </style> <body> <div class="box"></div> </body>pc端展现成果 挪动端展现成果 从上图能够看出在挪动端上同样是100px的盒子,然而却没有占到屏幕的1/3左右的宽度,这是因为在大部分浏览器上,挪动端的布局视口宽度为980px,咱们在把pc端的页面切换成挪动端页面时,右上角也短暂的显示了一下咱们的布局视口是980px x 1743px。 所以在挪动端下,咱们能够将视口划分为3种状况: 布局视口(layout viewport)视觉视口(visual layout)现实视口(ideal layout)这些概念的提出也是来自于ppk,是一位世界级前端技术专家。 贴上大佬的文章链接https://quirksmode.org/mobile... 所以咱们绝对于980px布局的这个视口,就称之为布局视口(layout viewport),而在手机端浏览器上,为了页面能够残缺的显示进去,会对整个页面进行放大,那么显示在可见区域的这个视口就是视觉视口(visual layout)。 然而咱们心愿设置的是100px就显示的是100px,而这就须要咱们设置现实视口(ideal layout)。 // initial-scale:定义设施宽度与viewport大小之间的缩放比例<meta name="viewport" content="width=device-width, initial-scale=1.0" />挪动端适配计划百分比设置rem单位+动静html的font-sizeflex的弹性布局vw单位在咱们挪动端适配计划中百分比设置是极少应用的,因为绝对的参照物可能是不同的,所以百分比往往很难对立,所以咱们经常应用的都是前面3种计划。 rem单位+动静html的font-sizerem单位是绝对于html元素的font-size来设置的,所以咱们只须要思考2个问题,第一是针对不同的屏幕,能够动静的设置html不同的font-size,第二是将原来的尺寸单位都转换为rem即可。 talk is cheap, show me the code/** 计划1:媒体查问 * 毛病:须要针对不同的屏幕编写大量的媒体查问,且如果动静的批改尺寸,不会实时的进行更新*/<style> @media screen and (min-width: 320px) { html { font-size: 20px; } } @media screen and (min-width: 375px) { html { font-size: 24px; } } @media screen and (min-width: 414px) { html { font-size: 28px; } } .box { width: 5rem; height: 5rem; background-color: orange; }</style><body> <div class="box"></div></body>/** 计划2:编写js动静设置font-size*/<script> const htmlEl = document.documentElement; function setRem() { const htmlWidth = htmlEl.clientWidth; const htmlFontSize = htmlWidth / 10; htmlEl.style.fontSize = htmlFontSize + "px"; } // 第一次不触发,须要被动调用 setRem(); window.addEventListener("resize", setRem);</script><style> .box { width: 5rem; height: 5rem; background-color: orange; }</style><body> <div class="box"></div></body>然而写起来感觉还是好麻烦,如果能够的话我心愿白嫖-0v0- ...

February 9, 2023 · 2 min · jiezi

关于javascript:停止像这样使用-asyncawait改用原版

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。最近我看到一些开发者应用这种办法来解决 async/await 谬误。 /** * @param { Promise } promise * @param { Object= } errorExt - Additional Information you can pass to the err object * @return { Promise } */function to(promise, errorExt) { return promise .then((data) => [null, data]) .catch((err) => { if (errorExt) { const parsedError = Object.assign({}, err, errorExt); return [parsedError, undefined]; } return [err, undefined]; });}async function doSomething() { const [error1, result1] = await to(fetch('')); if (error1) { return; } const [error2, result2] = await to(fetch(result1)); if (error2) { return; } // ...}正如你所看到的,他们把函数包起来,把原来的Promise转换成一个必定会胜利的 "Promise",并返回一个数组。 ...

February 9, 2023 · 1 min · jiezi

关于javascript:图解-Google-V8编译流水篇学习笔记二

这是《图解 Google V8》第二篇:编译流水线 学习下来最大的播种有两点: V8 如何晋升 JavaScript 执行速度 晚期缓存机器码,之后重构为缓存字节码在 JavaScript 中拜访一个属性时,V8 做了哪些优化 暗藏类内联缓存特地是第二点,让我看到了应用 TypeScript 的益处,动静语言存在的问题,动态语言都能够解决 09 | 运行时环境:运行 JavaScript 代码的基石运行时环境包含:堆空间和栈空间、全局执行上下文、全局作用域、内置的内建函数、宿主环境提供的扩大函数和对象,还有音讯循环系统 宿主浏览器为 V8 提供根底的音讯循环系统、全局变量、Web API V8 的外围是实现 ECMAScript 规范,比方:Object、Function、String,还提供垃圾回收、协程等 结构数据存储空间:堆空间和栈空间在 Chrome 中,只有关上一个渲染过程,渲染过程便会初始化 V8,同时初始化堆空间和栈空间。 栈是内存中间断的一块空间,采纳“先进后出”的策略。 在函数调用过程中,波及到上下文相干的内容都会寄存在栈上,比方原生类型、援用的对象的地址、函数的执行状态、this 值等都会存在栈上 当一个函数执行完结,那么该函数的执行上下文便会被销毁掉。 堆空间是一种树形的存储构造,用来存储对象类型的离散的数据,比方:函数、数组,在浏览器中还有 window、document 等 全局执行上下文和全局作用域执行上下文中次要蕴含三局部,变量环境、词法环境和 this 关键字 全局执行上下文在 V8 的生存周期内是不会被销毁的,它会始终保留在堆中 在 ES6 中,同一个全局执行上下文中,都能存在多个作用域: var x = 5;{ let y = 2; const z = 3;}结构事件循环系统V8 须要一个主线程,用来执行 JavaScript 和执行垃圾回收等工作 V8 是寄生在宿主环境中的,V8 所执行的代码都是在宿主的主线程上执行的 如果主线程正在执行一个工作,这时候又来了一个新工作,把新工作放到音讯队列中,期待当前任务执行完结后,再从音讯队列中取出正在排列的工作,执行完这个工作之后,再反复这个过程 10 | 机器代码:二进制机器码到底是如何被 CPU 执行的?将汇编语言转换为机器语言的过程称为“汇编”;反之,机器语言转化为汇编语言的过程称为“反汇编” ...

February 8, 2023 · 5 min · jiezi

关于javascript:经纬度转换常用方法

简略介绍一下几种常见的坐标系: WGS84坐标系:即地球坐标系(World Geodetic System),国内上通用的坐标系。设施蕴含的GPS芯片或者北斗芯片获取的经纬度个别都是为WGS84天文坐标系,目前谷歌地图采纳的是WGS84坐标系(中国范畴除外)。 GCJ02坐标系:GCJ-02是由中国国家测绘局(G示意Guojia国家,C示意Cehui测绘,J示意Ju局)制订的地理信息系统的坐标零碎。由WGS84坐标系经加密后的坐标系。谷歌中国采纳的GCJ02天文坐标系。也称:火星坐标系。 BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。 Web 墨卡托投影坐标系:也称web墨卡托,是现在支流的Web地图应用的坐标系,如国外的 Google Maps,OpenStreetMap,Bing Map,ArcGIS 和 Heremaps 等,国内的百度地图、高德地图、腾讯地图和天地图等也是基于Web墨卡托,与天文坐标系不同,投影坐标系的单位是m(因为国内政策的起因,国内地图会有加密要求,个别有两种状况,一种是在 Web墨卡托的根底上通过国家标准加密的国标02坐标系,熟称“火星坐标系”;另一种是在国标的02坐标系下进一步进行加密,如百度地图的BD09坐标系)。墨卡托投影的“等角”个性,保障了对象的形态的不变行,正方形的物体投影后不会变为长方形。“等角”也保障了方向和互相地位的正确性,因而在航海和航空中经常利用,而Google们在计算人们查问地物的方向时不会出错。————————————————版权申明:本文为CSDN博主「hhhSir'blog」的原创文章,遵循CC 4.0 BY-SA版权协定,转载请附上原文出处链接及本申明。原文链接:https://blog.csdn.net/weixin_... /** * 判断经纬度是否超出国境 */function isLocationOutOfChina(latitude, longitude) { if (longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271) return true; return false;}/** * 将WGS-84(国际标准)转为GCJ-02(火星坐标): */function transformFromWGSToGCJ(latitude, longitude) { var lat = ""; var lon = ""; var ee = 0.00669342162296594323; var a = 6378245.0; var pi = 3.14159265358979324; if (isLocationOutOfChina(latitude, longitude)) { lat = latitude; lon = longitude; } else { var adjustLat = transformLatWithXY(longitude - 105.0, latitude - 35.0); var adjustLon = transformLonWithXY(longitude - 105.0, latitude - 35.0); var radLat = latitude / 180.0 * pi; var magic = Math.sin(radLat); magic = 1 - ee * magic * magic; var sqrtMagic = Math.sqrt(magic); adjustLat = (adjustLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); adjustLon = (adjustLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); latitude = latitude + adjustLat; longitude = longitude + adjustLon; } return { latitude: latitude, longitude: longitude };}/** * 将GCJ-02(火星坐标)转为百度坐标: */function transformFromGCJToBaidu(latitude, longitude) { var pi = 3.14159265358979324 * 3000.0 / 180.0; var z = Math.sqrt(longitude * longitude + latitude * latitude) + 0.00002 * Math.sin(latitude * pi); var theta = Math.atan2(latitude, longitude) + 0.000003 * Math.cos(longitude * pi); var a_latitude = (z * Math.sin(theta) + 0.006); var a_longitude = (z * Math.cos(theta) + 0.0065); return { latitude: a_latitude, longitude: a_longitude };}/** * 将百度坐标转为GCJ-02(火星坐标): */function transformFromBaiduToGCJ(latitude, longitude) { var xPi = 3.14159265358979323846264338327950288 * 3000.0 / 180.0; var x = longitude - 0.0065; var y = latitude - 0.006; var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * xPi); var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * xPi); var a_latitude = z * Math.sin(theta); var a_longitude = z * Math.cos(theta); return { latitude: a_latitude, longitude: a_longitude };}/** * 将GCJ-02(火星坐标)转为WGS-84: */function transformFromGCJToWGS(latitude, longitude) { var threshold = 0.00001; // The boundary var minLat = latitude - 0.5; var maxLat = latitude + 0.5; var minLng = longitude - 0.5; var maxLng = longitude + 0.5; var delta = 1; var maxIteration = 30; while (true) { var leftBottom = transformFromWGSToGCJ(minLat, minLng); var rightBottom = transformFromWGSToGCJ(minLat, maxLng); var leftUp = transformFromWGSToGCJ(maxLat, minLng); var midPoint = transformFromWGSToGCJ((minLat + maxLat) / 2, (minLng + maxLng) / 2); delta = Math.abs(midPoint.latitude - latitude) + Math.abs(midPoint.longitude - longitude); if (maxIteration-- <= 0 || delta <= threshold) { return { latitude: (minLat + maxLat) / 2, longitude: (minLng + maxLng) / 2 }; } if (isContains({ latitude: latitude, longitude: longitude }, leftBottom, midPoint)) { maxLat = (minLat + maxLat) / 2; maxLng = (minLng + maxLng) / 2; } else if (isContains({ latitude: latitude, longitude: longitude }, rightBottom, midPoint)) { maxLat = (minLat + maxLat) / 2; minLng = (minLng + maxLng) / 2; } else if (isContains({ latitude: latitude, longitude: longitude }, leftUp, midPoint)) { minLat = (minLat + maxLat) / 2; maxLng = (minLng + maxLng) / 2; } else { minLat = (minLat + maxLat) / 2; minLng = (minLng + maxLng) / 2; } }}function isContains(point, p1, p2) { return (point.latitude >= Math.min(p1.latitude, p2.latitude) && point.latitude <= Math.max(p1.latitude, p2.latitude)) && (point.longitude >= Math.min(p1.longitude, p2.longitude) && point.longitude <= Math.max(p1.longitude, p2.longitude));}function transformLatWithXY(x, y) { var pi = 3.14159265358979324; var lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); lat += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; lat += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; lat += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; return lat;}function transformLonWithXY(x, y) { var pi = 3.14159265358979324; var lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); lon += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; lon += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; lon += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; return lon;}/** * 将百度转为WGS-84: */function transfromBaidutoWGS84(latitude, longitude){ if (!isNaN(latitude)&&!isNaN(longitude)){ var lat = parseFloat(latitude); var lon = parseFloat(longitude); let res= transformFromBaiduToGCJ(lat, lon); let resWGS = transformFromGCJToWGS(res.latitude,res.longitude); return {latitude: resWGS.latitude.toFixed(6), longitude: resWGS.longitude.toFixed(6)}; }else{ return { latitude: '0', longitude: '0' }; }}/** * 将WGS-84转为百度: */function transfromWGS84toBaidu(latitude, longitude){ if (!isNaN(latitude)&&!isNaN(longitude)){ var lat = parseFloat(latitude); var lon = parseFloat(longitude); let res= transformFromWGSToGCJ(lat, lon); let resBaidu = transformFromGCJToBaidu(res.latitude,res.longitude); return {latitude: resBaidu.latitude.toFixed(6), longitude: resBaidu.longitude.toFixed(6)}; } else{ return { latitude: '0', longitude: '0' }; }}module.exports = { isLocationOutOfChina: isLocationOutOfChina, transformFromWGSToGCJ: transformFromWGSToGCJ, transformFromGCJToBaidu: transformFromGCJToBaidu, transformFromBaiduToGCJ: transformFromBaiduToGCJ, transformFromGCJToWGS: transformFromGCJToWGS, transfromBaidutoWGS84:transfromBaidutoWGS84, transfromWGS84toBaidu:transfromWGS84toBaidu}

February 8, 2023 · 4 min · jiezi

关于javascript:amonthpicker组件初始化绑定日期控制台报错

解决 :valueFormat="item.format ? item.format : 'YYYYMM'"

February 8, 2023 · 1 min · jiezi

关于javascript:JS变量和执行环境

1. 数据类型1.1 根本类型和援用类型的值在JavaScript中,变量的数据类型分为根本类型和援用类型。根本类型指那些简略的数据段,包含Boolean、Number、String、Undefined、Null、Symbol,根本数据类型是间接按值拜访的,能够操作保留在变量中的理论的值。援用类型的值是保留在内存中的对象,JavaScript不能间接拜访内存中的地位,而是通过指针将变量与内存中的对象分割起来。因而在操作对象时,实际上是在操作对象的援用。 1.2 栈内存和堆内存为了更加深刻的了解JS变量根本类型和援用类型的区别,咱们还须要理解JS变量的值在内存中的存储形式。 1.2.1 栈内存栈,是一种数据结构,有着先进后出、后进先出的特点。就像一个羽毛球筒,只有一个口(即是进口也是入口),最先进入的球只能最初拿进去: 如上图,入栈的程序:1、2、3,出栈的程序:3、2、1 1.2.2 栈内存中的数据存储栈内存用来保留根本类型的变量或变量的指针,举个例子: var num1 = 3;变量 num1 在内存中的保留模式为: 对于根本类型的变量,当咱们进行复制操作时,比方这个例子: var num1 = 3;vat num2 = num1;此时JS会创立一个新值并将新值调配给新的变量,内存中的变量对象示意为: 变量 num2 失去的是一个全新的值,与变量 num1 中的值无关。 1.2.3 堆内存堆内存与栈内存不同,对于变量值的保留没有须要遵循的法则。 1.2.4 堆内存中的数据存储堆内存用来保留对象类型的变量值,对象的内容和大小也会随时变动。而此时变量对象中的变量保留的是一个指向堆内存中对象的指针,因为存在这种援用关系,对象也被称为援用类型。例: var num1 = 3;var obj = { a: 1} 当咱们对对象类型的值进行复制操作时,实际上copy的是对象的指针,因而两个变量指向的是同一个对象,例: var obj 1 = { a: 1 }var obj2 = obj1;在内存中体现为: 此时,批改变量 obj1 的属性等同于批改变量 obj2,例: var obj1 = { a: 1 };vat obj2 = obj1;obj1.b = 2;alert(obj2.b); // 21.3 包装对象对于援用类型的值,咱们能够为其增加属性和办法,也能够扭转和删除其属性和办法: ...

February 8, 2023 · 1 min · jiezi

关于javascript:闭包什么是闭包JavaScript前端

闭包的背景因为js中只有两种作用域,全局作用域和函数作用域,而在开发场景下,将变量裸露在全局作用域下的时候,是一件十分危险的事件,特地是在团队协同开发的时候,变量的值会被无心篡改,并且极难调试剖析。这样的状况下,闭包将变量封装在部分的函数作用域中,是一种十分适合的做法,这样躲避掉了被其余代码烦扰的状况。 闭包的应用上面是一种最简略间接的闭包示例 //妈妈本体function mother(){ //口袋里的总钱数 let money = 100 //消费行为 return function (pay){ //返回残余钱数 return money - pay }}//为儿子生产let payForSon = mother()//打印最初的残余钱数console.log(payForSon(5))为了便于了解,咱们将内部函数比喻为妈妈本体,外面保留着总钱数这个变量和生产这个行为,通过创立为儿子生产的这个行为对象,而后执行这个行为破费5元,返回残余的95元。 这个就是为了将变量money保留在mother本体内而防止裸露在内部的全局环境作用域中,只能通过mother()创立消费行为来影响money这个变量。 由此能够演绎总结应用闭包的三个步骤 用外层函数包裹变量,函数;外层函数返回内层函数;内部用变量保留内部函数返回的内层函数目标是为了造成一个专属的变量,只在专属的作用域中操作。 上述的闭包代码示例中,有一个缺点的场景是,在后续不须要money变量的状况下,没有开释该变量,造成内存泄露。起因是payForSon这个函数的作用域链援用着money对象,解决的方法是将payForSon = null就能够开释办法作用域,进而解除对money的援用,最初开释money变量。 闭包的扩大函数柯里化在开发的场景中,有时须要通过闭包来实现函数的柯里化调用。调用示例如下 alert(add(1)(2)(3))这种间断的传参调用函数,叫做函数柯里化。 通过闭包的实现形式如下 function add(a){ //保留第一个参数 let sum = a function tmp(b){ //从第二个函数开始递减 sum = sum + b //返回tmp,让后续能够持续传参执行 return tmp } tmp.toString = function(){ return sum } //返回加法函数 return tmp}alert(add(1)(2)(3))上面咱们来一步步剖析, add(1)执行时,保留第一个参数到sum变量中,返回tmp函数add(1)(2)执行等于tmp(2),将2的值加到了变量sum上,返回tmp函数自身add(1)(2)(3)执行等同于上述步骤的加到比变量sum上,返回tmp函数自身alert(add(1)(2)(3))执行时,alert须要将值转为string显示,最初的tmp函数执行tmp.toString,返回sum的值。 矩阵点击利用该例子的demo代码在我的github上,能够自行取阅 需要:在一个4*4的矩阵方块中,实现点击每个按钮时记录下各自的点击次数,相互之间互不烦扰。 思路:在按钮事件中应用闭包,创立独立的存储变量空间。 留神:下列的计划1到计划3是逐次演进的优化计划,须要依照计划标号的秩序逐层了解,更有利于了解最终的优化计划 计划1<div id="container"></div>...let container = document.getElementById('container')for (let r = 0; r < arr.length; r++) { for (let c = 0; c < arr[r].length; c++) { let cell = document.createElement('div') cell.innerHTML = `(${r},${c})` container.append(cell) cell.onclick = (function () { let n = 0 return function () { n++ cell.innerHTML = `点${n}` } })() }}在每个按钮上通过onclick绑定闭包办法,存储操作独立的n变量,这样就能够独自记录每个按钮的点击次数 ...

February 8, 2023 · 2 min · jiezi

关于javascript:关于aes加密的一些记录javascript-aes256-128-192加密方式

最近应用javascript的cryptojs脚本对接后盾解密aes-128-cfb的数据。 发现并不能指定128 192 默认是256, 据我一番查问找到,加密位数是依据key钥匙的长度。 256须要64个字符,128须要32个字符,192须要48个字符。 这个是怎么计算的呢? 首先 256 ,128,192,指位数(bit) 除8当前别离就是,32,16,24 字节。 两个字符是一个字节,所以用下面的字符乘2就是字符数。

February 7, 2023 · 1 min · jiezi

关于javascript:JavaScript-中递归

递归 RecursionTo iterate is human, to recurse, divine.了解迭代,神了解递归。本文会以 JavaScript为主、有局部 Rust 举例说明。 概述递归就是程序 函数本人 调用本人。递归须要有边界条件、递归后退段和递归返回段。当边界条件不满足时,递归后退;当边界条件满足时,递归返回。 帕斯卡三角: 从递推开始了解 在中国 帕斯卡三角 叫杨辉三角,因为在中国 杨辉三角 的记录比欧洲 帕斯卡三角记录早了几百年。 能产生递归的条件调用本身:以最小的函数解决问题,产生的新问题与原问题有着雷同的模式。递归进口:递归思考无限的问题,进口就是递归调用最初一次调用的进口递归与循环的区别循环是满足肯定条件,反复执行同一段代码片段。而递归是函数,一直调用本人的行为。常见有 for-in/for-of 循环,而递归常见的有数学问题:fibonacci 函数。 毛病耗内存,能够应用尾回调回溯(Backtrack)一个递归调用的过程,就是回溯。 回溯是一种算法思维,它是用递归实现的。 用一个比拟艰深的说法来解释递归和回溯:咱们在路上走着,后面是一个多岔路口,因为咱们并不知道应该走哪条路,所以咱们须要尝试。尝试的过程就是一个函数。咱们抉择了一个方向,起初发现又有一个多岔路口,这时候又须要进行一次抉择。所以咱们须要在上一次尝试后果的根底上,再做一次尝试,即在函数外部再调用一次函数,这就是递归的过程。这样反复了若干次之后,发现这次抉择的这条路走不通,这时候咱们晓得咱们上一个路口选错了,所以咱们要回到上一个路口从新抉择其余路,这就是回溯的思维。递归算法 (recursive algorithm)在递归问题中,应用 JavaScript/Rust 做为示例,有几个经典的问题 数组求和fibonacci 函数JavaScript 中应用递归实现深拷贝React-Router 递归实现配置 routesVue 中递归组件经典的 fibonacci 函数示例经典的 Fibonacci JavaScript 实现export default function fibonacci(n) { if (n < 0) throw new Error("输出的数字不能小于 0"); if (n === 1 || n === 2) { return 1; } return fibonacci(n - 2) + fibonacci(n - 1);}const fi = fibonacci(7);console.log(fi);经典的 Fibonacci Rust 实现(含测试)fn main() { println!("Hello, world!"); let f1 = fibonacci(1); println!("{}", f1); let f2 = fibonacci(2); println!("{}", f2); let f3 = fibonacci(3); println!("{}", f3); let f4 = fibonacci(4); println!("{}", f4);}pub fn fibonacci(n: i32) -> u32 { if n < 0 { panic!("输出的数字不能小于 0") }; if n == 1 || n == 2 { return 1 } fibonacci(n - 2) + fibonacci(n - 1)}#[cfg(test)]mod tests { use crate::fibonacci; #[test] fn fibonacci1() { let result = fibonacci(1); assert_eq!(result, 1); } #[test] fn fibonacci2() { let result = fibonacci(2); assert_eq!(result, 1); } #[test] fn fibonacci3() { let result = fibonacci(3); assert_eq!(result, 2); }}从求和到递归// 循环var sum = 0;for (var i = 1; i <= 10; i++) { sum += i;}console.log(sum);// 递归function sum(n) { if (n == 1) return 1; return sum(n - 1) + n;}var amount = sum(10);console.log(amount);fn main() { println!("Hello, world!"); while_sum_fn();}fn while_sum_fn() { let mut sum = 0; let mut i = 0; while i <= 10 { sum += i; i += 1; println!("sum: {}", sum); } println!("{sum}")}Rust for 循环与 js 中循环有很大的区别,此处 rust 应用 while 语句代替 JavaScript 中的 for 语句。 ...

February 7, 2023 · 3 min · jiezi

关于javascript:cookie-localStorage-sessionStorage的区别没废话版本

cookie数据存储内容很小,只在过期工夫内无效,即便浏览器敞开cookie的用法很简略,js也能够通过documnet.cookie="名称=值;"cookie个别用做为登陆态保留、明码、个人信息等要害信息保留应用,所以为了平安也是恪守同源策略准则的。 localStorage用于长久化的本地存储,除非被动删除数据,否则数据是永远不会过期的能够用于存储该浏览器对该页面的拜访次数,当然,如果换个浏览器,这个次数就从新开始计数了还能够用来存储一些固定不变的页面信息,这样就不须要每次都从新加载了,这个值也能够进行笼罩 sessionStorage用于本地存储一个会话中的数据,不是一种长久化的本地存储,仅仅是会话级别的存储也就是说只有这个浏览器窗口没有敞开,即便刷新页面或进入同源另一页面,数据依然存在敞开窗口后,sessionStorage即被销毁

February 7, 2023 · 1 min · jiezi

关于javascript:图解-Google-V8设计思想篇学习笔记一

最新在学《图解 Google V8》 这个专栏的长处是:写的通俗易懂,没有波及 V8 源码局部,对于前端还是比拟敌对的,学完之后可能晓得写下一段 js 代码后,V8 背地都做了哪些事件 这个专栏的不足之处是:没有对技术进行深刻解说,只讲了这个技术是用来解决什么问题的,以及它是怎么工作的 所以这个专栏比拟时候对 V8 还不理解的同学去学习,减少本人的知识面 上面是我本人学习每一章的总结,次要记录我在这章中学到内容,并不是对这章残缺的总结 我会分为三篇来写,这是第一篇:设计思维篇 如何学习谷歌高性能 JavaScript 引擎 V8?V8 次要波及三个技术:编译流水线、事件循环系统、垃圾回收机制 V8 执行 JavaScript 残缺流程称为:编译流水线 编译流水线波及到的技术有: JIT V8 混合编译执行和解释执行惰性解析 放慢代码启动速度暗藏类(Hide Class) 将动静类型转为动态类型,打消动静类型执行速度慢的问题内联缓存事件循环系统 JavaScript 中的难点:异步编程调度排队工作,让 JavaScript 有序的执行垃圾回收机制 内存调配内存回收01 | V8 是如何执行一段 JavaScript 代码的?筹备根底环境: 全局执行上下文:全局作用、全局变量、内置函数初始化内存中的堆和栈构造初始化音讯循环系统:音讯驱动器和音讯队列结构化 JavaScript 源代码 生成形象语法树(AST)生成相干作用域生成字节码:字节码是介于 AST 和机器码的中间代码 解释器能够间接执行编译器须要将其编译为二进制的机器码再执行解释器和监控机器人 解释器:依照程序执行字节码,并输入执行后果监控机器人:如果发现某段代码被反复屡次执行,将其标记为热点代码优化热点代码 优化编译器将热点代码编译为机器码对编译后的机器码进行优化再次执行到这段代码时,将优先执行优化后的代码反优化 JavaScript 对象在运行时可能会被扭转,这段优化后的热点代码就生效了进行反优化操作,给到解释器解释执行02 | 函数即对象:一篇文章彻底搞懂 JavaScript 的函数特点V8 外部为函数对象增加了两个暗藏属性:name,code: name 为函数名 如果是匿名函数,name 为 anonymouscode 为函数代码,以字符串的模式存储在内存中当执行到一个函数调用语句时,V8 从函数对象中取出 code 属性值,而后解释执行这段函数代码 什么是闭包:将内部变量和函数绑定起来的技术 参考资料: The story of a V8 performance cliff in React03 | 快属性和慢属性:V8 是怎么晋升对象属性访问速度的?V8 在实现对象存储时,没有齐全采纳字典的存储形式,因为字典是非线性的数据结构,查问效率会低于线性的数据结构 ...

February 7, 2023 · 2 min · jiezi

关于javascript:史上最全的vue中组件之间的传值方式

重中之重的就是组件之间数据传递的几种形式Vue2最常见的11种组件间的通信形式 props$emit / v-on.syncv-modelref(获取子组件的属性和调用子组件办法)实质就是获取到子组件的this$children / $parent(获取子组件(不包含顺孙组件)的数组 / 获取父组件的this)$attrs / $listeners($attrs子组件外面获取父组件传递的属性,$listeners子组件获取父组件自定义的办法(这个自定义办法是子组件通过$emit传递过来的))provide / injectEventBusVuex$root(获取根组件的,new Vue外面定义的办法和属性)Slot公布订阅(pubsub-js)本地存储(localstorage和sessionstorage)props父组件向子组件传送数据,这应该是最罕用的形式了子组件接管到数据之后,不能间接批改父组件的数据。否则会报错,因为当父组件从新渲染时,数据会被笼罩。如果只在子组件内要批改的话举荐应用 computed// Parent.vue 传送<template> <child :msg="msg"></child></template>// Child.vue 接管export default { // 写法一 用数组接管 props:['msg'], // 写法二 用对象接管,能够限定接管的数据类型、设置默认值、验证等 props:{ msg:{ type:String, default:'这是默认数据'} }, mounted(){ console.log(this.msg) },}.sync 子组件能够批改父组件内容.sync能够帮咱们实现父组件向子组件传递的数据的双向绑定,所以子组件接管到数据后能够间接批改,并且会同时批改父组件的数据// Parent.vue<template> <child :page.sync="page"></child></template><script>export default { data(){ return { page:1 }}}// Child.vueexport default { props:["page"], computed(){ // 当咱们在子组件里批改 currentPage 时,父组件的 page 也会随之扭转 currentPage { get(){ return this.page }, set(newVal){ this.$emit("update:page", newVal) } }}}</script>v-model和 .sync 相似,能够实现将父组件传给子组件的数据为双向绑定,子组件通过 $emit 批改父组件的数据// Parent.vue<template> <child v-model="value"></child></template><script>export default { data(){ ...

February 6, 2023 · 3 min · jiezi

关于javascript:trycatchfinally前端的好厚米我觉得你们不够了解我呀

这篇文章想跟大家一起从新复习一下对于应用 try...catch 进行异样捕捉的一些知识点。为了晋升大家的浏览趣味,咱们先来做三个小练习题,如果你都做对的话,那么表明你这一部分的常识把握的很纯熟,能够不必读这篇文章啦~ 如果做错了某道题的话,阐明咱们还有一些知识点须要再次坚固一下,话不多说,咱们先来看看这三道题: function doTask () { try { console.log('1 in try block'); throw '2 test error'; return 3; } catch (e) { console.log('4 in catch block'); console.log(e); return 5; } finally { console.log('6 in finally block'); return 7; }}// 控制台输入的后果是什么呢?console.log(doTask());function doWork () { try { console.log(1); try { console.log(2); throw 3; } finally { console.log(4); } console.log(5); } catch (e) { console.log(e); }}// 控制台输入的后果是什么呢?doWork();function doRepeat () { for (let i = 0; i < 2; i++) { try { if (i === 1) { continue; } console.log(`${i} in try`); } finally { console.log(`${i} in finally`); } }}// 控制台的输入后果是什么呢?doRepeat();下面的每一道题目都有它的小心理,一不小心就容易出错。大家能够把本人测试的后果在评论区晒一晒。 ...

February 2, 2023 · 2 min · jiezi

关于javascript:浏览器截图方案分析

浏览器截图计划剖析页面截屏是前端常常遇到的需要,比方页面生成海报,弹窗图片分享等。 以下是我整顿三种截图计划: html2canvasdom-to-imagewebRTChtml2canvashtml2canvas 用的比拟宽泛的前端截图计划,先将 DOM 一个个 转为 Canvas 而后导出图片(应用 canvas 自带的 toDataUrl、toBobl)即可。应用起来应该是兼容性比拟好的计划了,能解决大部分的需要,然而也有一写小问题,如: 图片跨域,开启CSS 属性错乱遇到 canvas 元素导出后为通明色。大部分问题还是能够通过配置和百度解决的 const getDomImg = (eleId) => { html2canvas(document.getElementById(eleId), { //superMap整个页面的节点 backgroundColor: null, //画进去的图片有红色的边框,不要可设置背景为通明色(null) allowTaint: true, useCORS: true, //反对图片跨域 scale: 1, //设置放大的倍数 }) .then((canvas) => { //截图用img元素承装,显示在页面的上 let img = new Image(); img.src = canvas.toDataURL("image/jpg"); // toDataURL :图片格式转成 base64 // 间接下载 let a = document.createElement("a"); a.href = canvas.toDataURL("image/jpeg"); a.download = "test"; a.click(); }) .catch((err) => { console.log("html2canvas err", err); });};dom-to-image应用 svg,通过 createObjectURL 或 encodeURIComponent 解决 svg 失去图像资源,能够把 svg 绘制到 canvas。 ...

February 1, 2023 · 2 min · jiezi

关于javascript:编写属于自己的音乐播放器

前言咱们在 Web 开发过程中,有很多用到音频元素audio的场景,如音乐播放器、语音播放等性能,然而因为原生组件有以下毛病: 原生UI款式丑,在谋求好看的页面中须要重写元素款式,而且反对重写的款式不多。浏览器兼容问题,不同浏览器的音频元素展现不同。因为以上两个问题,这就导致咱们须要对原生的audio进行批改时比拟艰难。而对于大多数音频的需要,咱们能够应用满足咱们要求的第三方组件库中抉择,如: 西瓜播放器Media Element而对于 UI 有要求的需要,比方音乐播放器的需要,那就要遵循整个页面的 UI 主题,这种状况下咱们就须要自定义编写一个音频组件了。 在本文中,咱们将学会: 如何批改音频元素的默认款式如何重写音频自定义款式如何批改音频元素的默认款式默认状况下,音频元素不可见。须要增加控件属性以使其控件可见。 <audio controls="true" src="音频.mp3" ></audio> 音频元素在CSS中具备以下伪元素选择器: audio::-webkit-media-controls-panelaudio::-webkit-media-controls-mute-buttonaudio::-webkit-media-controls-play-buttonaudio::-webkit-media-controls-timeline-containeraudio::-webkit-media-controls-current-time-displayaudio::-webkit-media-controls-time-remaining-displayaudio::-webkit-media-controls-timelineaudio::-webkit-media-controls-volume-slider-containeraudio::-webkit-media-controls-volume-slideraudio::-webkit-media-controls-seek-back-buttonaudio::-webkit-media-controls-seek-forward-buttonaudio::-webkit-media-controls-fullscreen-buttonaudio::-webkit-media-controls-rewind-buttonaudio::-webkit-media-controls-return-to-realtime-buttonaudio::-webkit-media-controls-toggle-closed-captions-button这写伪类选择器,能够扭转音频元素的根本款式,然而仅在Chrome浏览器下无效。 我把所有的伪类都给上不同的背景色彩,最初出现的成果如下图所示: audio::-webkit-media-controls-xxx{ background-color: 色彩随机;} 也就是,只能批改局部款式,没有提供更粗疏的批改。 如果想要设置进度条的色彩,根本只能自定义重写播放器了。 自定义音频播放器接下来,将是咱们本文的重点,咱们将创立本人的自定义音频播放器。 咱们自定义的播放器,它应用不同的元素来实现控件的UI。而后在 Javascript 的帮忙下将音频元素的性能绑定到这些元素。 首先咱们先写一个简略的布局 <div id="audio-player"> <audio src="xx.mp3" style="display: none" ></audio><!--audio 播放器,暗藏掉--> <div class="poster"> <img src='xx.png'/></div><!--封面图--> <div class="controls"> <div class="poster">音乐播放器</div> <div class="controls-con"> <button class="player-button"> <!-- 播放暂停按钮图片 --> </button> <input type="range" class="timeline" max="100" value="0" /><!--进度条 应用input[ragne]实现--> <button class="sound-button"> <!-- 音量开关按钮图片 --></button> </div> </div> </div>咱们首先创立了一个audio元素,然而不须要它显示,只须要它的音频性能,也不须要它的UI。而后咱们自定义播放器的封面图、控件等UI元素,款式能够本人调整,就不放CSS了,我调整后显示后果大略是这样。 而后咱们如何将本人定义的元素控件去作用于这个audio元素呢?这就须要用到它的一些属性和办法了,如: 属性 currentTime-以后音频的播放地位<string>duration-音频的播放总长度<string>muted-是否静音<boolean>办法 play()-播放pause()-暂停ended()-播放完结timeupdate()-音频地位变动具体参考 MDN-audio 还有对于进度条的扭转,能够通过<input type='range'>去简略实现进度条。从而能够监听进度条地位,扭转音频地位。反之能够通过监听audio的timeupdate办法扭转进度条。 这里次要用到的属性和办法为: 属性 value-以后进度<number>办法 change-进度条扭转说到这,大家也就应该明确了,咱们利用原有的audio的办法和属性去实现本人的 UI 控件,这其实也是风行音频组件库的做法。上面间接看音频控件的 javaScript 代码: const playerButton = document.querySelector(".player-button"),// 获取播放/暂停按钮 audio = document.querySelector("audio"),// 获取音频 timeline = document.querySelector(".timeline"),// 获取进度条 soundButton = document.querySelector(".sound-button"),// 过来音量按钮(是否静音)// 1. 通过监听按钮的点击工夫,批改音频的播放、暂停状态,并设置对应的 icon.playerButton.addEventListener("click", ()=> { if (audio.paused) { audio.play(); playerButton.innerHTML = pauseIcon; } else { audio.pause(); playerButton.innerHTML = playIcon; }});// 2. 通过监听音频播放的进度设置 input 进度条的 value.audio.ontimeupdate=()=> { const percentagePosition = (100 * audio.currentTime) / audio.duration; timeline.style.backgroundSize = `${percentagePosition}% 100%`; timeline.value = percentagePosition;}// 3. 如果播放完结,将播放按钮重置为暂停状态。audio.onended = audioEnded=()=>{ playerButton.innerHTML = playIcon;}// 4. 监听进度条变动,并设置音频地位。timeline.addEventListener("change", ()=>{ const time = (timeline.value * audio.duration) / 100; audio.currentTime = time;});// 5. 监听音频按钮变动,并设置对应的状态(是否静音)和iconsoundButton.addEventListener("click", ()=>{ audio.muted = !audio.muted; soundButton.innerHTML = audio.muted ? muteIcon : soundIcon;});代码片段 ...

February 1, 2023 · 1 min · jiezi

关于javascript:JavaScript二十年阅读整理

前言春节假期因为没有win电脑回家,所以才有工夫静下心来看会儿书。这次读的是《JavaScript二十年》,书籍次要介绍了语言诞生以及一些阶段性的倒退里程碑,能学到的有用常识不会太多,如果你还没看过红宝书或者《你不晓得JavaScript》等系列书籍,倡议先看完再来读这本比拟”闲“的书。 上面我会以我集体的了解角度概括一下书籍的一些次要内容,给一些想看没工夫看的兄弟节俭一下工夫。 1. 语言诞生90年代初,互联网崛起了,浏览器呈现在公众视线了,大家开始冲浪了。Netscape,也就是网景,在此时创建,很显然大家都想要捞一笔大的。 此时,Web外围还是HTML,然而此时大家都对能够不便编排用户利用操作的脚本语言有了极大的期待,于是,网景招了Brendan Eich进来(为了不便国人了解,后文用老E代替Brendan Eich),让他开发一款能够集成到网页里的脚本语言。 恰恰好在这个时候,万物起源 Java 进去了,Java的开发公司Sun和网景达成了协定,决定将Java集成到浏览器中。于是,网景老板当初的战略目标就变了,他们可能只须要一门[小语言]来补充一下Java就能够了。 此时,网景外部还是有很多不同的声音,次要是: 他妈的Java到底行不行?为什么要两门语言,间接Java不就完了,还小语言补充是瞧谁不起?谁他妈来开发这门小语言,有没有大佬,在线等,很急对于第一个问题,过后还是95年的春天,年老的Java对于初学者来说还是相当难上手的,所以,从多方面思考,被咱们寄予厚望的Java 最终还是倒在了16强! 对于第二个问题,他们对标了过后的竞品,微软,他们也是发售Visual C++给业余选手,而后应用 Visual Basic来作为补充的脚本语言,给一些菜鸡做一些[胶合]定制。这个想法很不错,所以网景也抄了。 那么就剩下第三个问题了,很显然,此时须要咱们的配角老E退场了。他花了10多天(是的,书里是这么写的,你当初是不是感觉本人像个沙比?)来创立了一门叫做Mocha的新语言,证实这门语言在网景浏览器中的可行性。95年12月的时候,正式命名为JavaScript公布,通稿中 JavaScript 被形容为「一种对象脚本语言」,可用于编写脚本来动静地「批改 Java 对象的属性和行为」。它将作为「Java 的补充,不便进行在线利用开发」。只管它们的技术设计只有外表上的类似,网景和Sun还是试图在 Java 和 JavaScript 语言间建设牢固的品牌分割。这种名称上的相似性及其带来的两种语言具备密切联系的暗示,长期以来都是导致凌乱的本源之一。 家喻户晓,程序员最精通的,还是CV,所以老E在一开始的设计中,借鉴了许多其余语言的特点。 比方Lisp 式的函数一等公民概念比方从Java借鉴的 null 概念,实质上是表白「没有对象」的对象,也是起初一个经典Bug之一比方从C借鉴的条件语句,循环语句和非顺序控制流的 break、continue和 return语句依据 Brendan Eich 的回顾,typeof null的值是原始 Mocha 实现中形象透露g的后果。null的运行时值应用了与对象值雷同的外部标记值进行编码,因而 typeof运算符的实现就间接返回了 "object"。2. 创建规范只管作者是一个蠢才,然而10天赶工进去的新语言还是有很多的问题。 JavaScript公布后的第二年,微软也发表在IE上反对这个语言,同时他们也开始了JScript的开发工作,为什么名字不一样,你想想啊,网景必定不会把代码给微软啊,所以他们只是在各自浏览器上实现了一样的逻辑,并且兼容一样的脚本代码,网景的叫做JavaScript ,微软这边就叫JScript 。每当微软比照两个浏览器时发现雷同脚本具备差别,他们就要对JavaScript做逆向工程,看看这些人底层写的什么垃圾实现,为什么不同浏览器会有不同的实现。(这个同代码不同浏览器下体现不同的经典尿性也始终连续至今) 在整个JScript 的开发过程中,微软的人一旦发现JavaScript 的语言标准缺失,就疯狂Diss网景的哥们。 JavaScript风评拉胯,[ 创建一个规范,确保在不同浏览器中的兼容性 ]变得越来越重要。 于是,网景通过人际关系找到了ECMA国内组织的秘书长,跟他提议推动JavaScript的标准化。因为国际标准组织(ISO)认可ECMA,ECMA的规范能够通过快速通道来成为ISO规范。 96年10月,ECMA邀请所有风云人物(根本是网景和微软的员工)到场独特参加JavaScript的探讨,并且组成一个新的Ecma技术委员会(Technical Committee)。 ECMA应用数字来标记旗下的技术委员会,而下一个可用的数字是39,所以这次组织会议就是经典的TC39会议会议开始,两派人马轮流演讲,最终委员会采纳了微软员工Robert Welland编写的文档,网景的确拉了跨了,还不如继承者。这份文档是利用了伪代码的概念来进行编写的,这种形式在形容JavaScript的语义方面相当无效,其具体水平足以确保互操作性。 所以,ECMAScript和JavaScript的关系是什么?前者是后者的标准,后者是前者的一个实现。比方前者形容了内置办法A,应该实现什么逻辑,什么类型入参和什么类型的返回后果。那么不同的浏览器厂商就要实现这一套逻辑,给本人的 不论是JavaScript 还是 JSCript ,又或者是什么BScript,都要有这个内置办法A,并且应用办法合乎ECMAScript的定义。 Ogay,先写到这里了,前面还没整顿完,今天再更 3. 改革失败4. 继往开来

January 31, 2023 · 1 min · jiezi

关于javascript:Nextjs-项目最佳实践

 后方高能,干货满满,倡议点赞➕关注➕珍藏;后续还有该系列的 进阶教程 继续送上 什么是 Next.js“ Nest.js 通过提供所有生产环境须要的性能来给你最佳的开发体验:构建时预渲染,服务端渲染,TypeScript 反对,智能打包,路由预加载,零配置等等 ”正如上文的介绍,Next.js 是一个十分全面的古代全栈利用构建计划。它蕴含了十分优雅的 TypeScript 和 React 反对,同时提供了古代利用常见的需要解决方案,例如:路由,API,PostCSS 工具和代码宰割等。 与此同时它也反对动态站点生成(用于能够在任何中央托管的高性能动态 HTML 页面)或者是通过 Vercel / AWS 等部署 Node.js 服务来进行数据按需加载的服务端渲染页面 Next.js 已迅速成为 Web 开发畛域最热门的技能之一。本教程旨在充当 Next.js文档 的 “ 实用 ” 延长,并帮忙你应用大量最佳实际来开发我的项目,这将有利于你在今后对我的项目施行进一步的扩大。 介绍本教程不是为了代替官网文档,因为官网文档曾经写得非常简单易懂了。我强烈推荐你在学习本文之前先大抵过一下 这一章 的内容,这样你对文中的术语和工具会比拟相熟,他们提供的一些组件与一般 HTML 组件类似,但通常是“更弱小”的版本。 我抵赖其中许多的是严格的并且带有主观色调的,如果其中任何一个对你没有吸引力,那么在大多数状况下能够简略地跳过这些局部并且应该依然可能实现本教程而不会遇到太多麻烦 当初,如果你曾经筹备好了,那就开始学习吧 ! 我的项目创立咱们将应用 TypeScript 模版来创立一个默认的 Next.js 利用 npx create-next-app@latest --typescript nextjs-fullstack-app-template-zncd nextjs-fullstack-app-template-zn// ESLInt : YES// `src/` directory : YES// `app/` directory : NO首先咱们试试这个我的项目能不能失常运行。咱们在这个例子中会应用 yarn ,当然你也能够用 NPM 或其余的工具 yarn dev你能够关上 http://localhost:3000/ 看到这个 demo 曾经胜利运行 ...

January 31, 2023 · 12 min · jiezi

关于javascript:JS-事件循环Event-Loop

转自:面试必问之 JS 事件循环(Event Loop),看这一篇足够! 了解 JavaScript 的事件循环往往随同着宏工作和微工作、JavaScript 单线程执行过程及浏览器异步机制等相干问题,而浏览器和 NodeJS 中的事件循环实现也是有很大差异。相熟事件循环,理解浏览器运行机制将对咱们了解 JavaScript 的执行过程,以及在排查代码运行问题时有很大帮忙。 本文将在浏览器异步执行原理和事件驱动的了解根底上,具体介绍 JavaScript 的事件循环机制以及在浏览器和 NodeJS 中的不同体现。 浏览器 JS 异步执行的原理JS 是单线程的,也就是同一个时刻只能做一件事件,那么思考:为什么浏览器能够同时执行异步工作呢? 因为浏览器是多线程的,当 JS 须要执行异步工作时,浏览器会另外启动一个线程去执行该工作。也就是说,“JS 是单线程的”指的是执行 JS 代码的线程只有一个,是浏览器提供的 JS 引擎线程(主线程)。浏览器中还有定时器线程和 HTTP 申请线程等,这些线程次要不是来跑 JS 代码的。 比方主线程中须要发一个 AJAX 申请,就把这个工作交给另一个浏览器线程(HTTP 申请线程)去真正发送申请,待申请回来了,再将 callback 里须要执行的 JS 回调交给 JS 引擎线程去执行。即浏览器才是真正执行发送申请这个工作的角色,而 JS 只是负责执行最初的回调解决。所以这里的异步不是 JS 本身实现的,其实是浏览器为其提供的能力。以 Chrome 为例,浏览器不仅有多个线程,还有多个过程,如渲染过程、GPU 过程和插件过程等。而每个 tab 标签页都是一个独立的渲染过程,所以一个 tab 异样解体后,其余 tab 根本不会被影响。作为前端开发者,次要重点关注其渲染过程,渲染过程下蕴含了 JS 引擎线程、HTTP 申请线程和定时器线程等,这些线程为 JS 在浏览器中实现异步工作提供了根底。 事件驱动浅析浏览器异步工作的执行原理背地其实是一套事件驱动的机制。事件触发、工作抉择和工作执行都是由事件驱动机制来实现的。NodeJS 和浏览器的设计都是基于事件驱动的,简而言之就是由特定的事件来触发特定的工作,这里的事件能够是用户的操作触发的,如 click 事件;也能够是程序主动触发的,比方浏览器中定时器线程在计时完结后会触发定时器事件。而本文的主题内容事件循环其实就是在事件驱动模式中来治理和执行事件的一套流程。 以一个简略场景为例,假如游戏界面上有一个挪动按钮和人物模型,每次点击右移后,人物模型的地位须要从新渲染,右移 1 像素。依据渲染机会的不同咱们能够用不同的形式来实现。实现形式一:事件驱动。点击按钮后,批改坐标 positionX 时,立刻触发界面渲染的事件,触发从新渲染。实现形式二:状态驱动或数据驱动。点击按钮后,只批改坐标 positionX,不触发界面渲染。在此之前会启动一个定时器 setInterval,或者利用 requestAnimationFrame 来一直地检测 positionX 是否有变动。如果有变动,则立刻从新渲染。 ...

January 30, 2023 · 3 min · jiezi

关于javascript:1vueelementUI的级联框二次封装之后在使用时容易出现下拉框不显示的问题

起因:级联框显示数据量大的时候返回慢,渲染的时候数据还没返回,导致级联框的浮层加载慢于弹层,而后浮层高度不能撑起来,或者层级不能跟着页面自适应,就看不到下拉项解决:给浮层自定义类名之后给一个最小高度,或者给层级加高,(ps:如果加的款式不失效,或者只显示类名而没有本人写的款式的话,可能是因为款式加了scoped的起因,因为级联的浮层在页面之外,所以能够另外写一个style popper-class="city-popper" <style>.city-popper{//两个写一个先试一下 z-index: 3000!important; min-height: 20px; }</style>

January 30, 2023 · 1 min · jiezi

关于javascript:SAP-UI5-应用如何加载自定义-Theme

要加载内部自定义主题,开发人员能够通过在页面中动态申明或应用 Core.setThemeRoot() 办法来设置此主题。 这十分相似于对位于不同地位的 SAP UI5 库应用 registerModulePath()。 上面是具体的操作步骤: (1) 应用上面的代码通知 SAP UI5 框架,咱们自定义 theme 的地址。 sap.ui.getCore().setThemeRoot("my_theme", "http://url.to/the/root/dir");SAPUI5 而后从该 URL 加载所有主题资源。 比方sap.ui.core库的 library.css文件,在上述代码执行之后,就变成: http://url.to/the/root/dir/sap/ui/core/themes/my_theme/library.css base directory 也能够通过 core.applyTheme(...) 办法的第二个参数指定。 如果 theme 的某些局部位于不同的地位,能够应用下面的调用来设置默认值,但通过在数组中将它们指定为第二个参数来笼罩特定库的主题地位: sap.ui.getCore().setThemeRoot("my_theme", ["my.lib.one","my.lib.two"], "http://url.to/the/other/root/dir");上面是不同的设置 theme 的实现办法: (1) 在 SAPUI5 bootstrap script 的属性中应用与 JSON 字符串雷同的对象构造: <script id="sap-ui-bootstrap" type="text/javascript" src="resources/sap-ui-core.js" data-sap-ui-theme-roots='{"my_theme" : "http://themes.org/ui5"}'></script>(2) 通过 URL parameter 指定: http://myserver.com/sap/myapp/?sap-ui-theme=my-theme@/sap/public/bc/themes/~client-111 (3) 通过全局配置对象指定。 将下列代码插入到 bootstrap 脚本之前: <script type="text/javascript">window["sap-ui-config"] = { themeRoots : { "my_preconfigured_theme" : "http://preconfig.com/ui5-themes", "my_second_preconfigured_theme" : { "" : "http://preconfig.com/ui5-themes", "sap.ui.core" : "http://core.com/ui5" } }}</script>下面的代码达到的成果: ...

January 30, 2023 · 1 min · jiezi

关于javascript:5K字-由浅入深聊聊Promise实现原理

前言大家好,我是梁木由,是一个有想头的前端。这几天再回顾基础知识时,对Promise有了较为深刻的了解,那明天就来分享下怎么由浅入深的把握Promise并且学会手写Promise 概念Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更正当和更弱小。它由社区最早提出和实现,ES6 将其写进了语言规范,对立了用法,原生提供了Promise对象。 所谓Promise,简略说就是一个容器,外面保留着某个将来才会完结的事件(通常是一个异步操作)的后果。从语法上说,Promise 是一个对象,从它能够获取异步操作的音讯。Promise 提供对立的 API,各种异步操作都能够用同样的办法进行解决。 Promise 拉进去单练那咱们先把Promise拉进去练练,看看是什么玩意,在控制台中打印看下在上图能够看出什么信息呢,那咱们列举下 首先咱们看出在new Promise时,须要传入一个回调函数它是一个类,并且会返回一个Promise对象那还能够看出它有constructor构造函数,还有catch、finally、then三个办法那咱们根据上述剖析出的信息,简略实现一下 class CustomPromise {  constructor(callBack) { }  catch() { }  then() { }  finally() { }}const customPromise = new CustomPromise()console.log(customPromis)看下咱们本人简略实现的输入后果那咱们再写一个Promise的惯例用法 const promise = new Promise((resolve, reject) => {  console.log("hellow Promise");});console.log(promise); 那咱们来看看打印后果,能剖析出什么后果 hellow promise 在控制台被输入了,那是不是说咱们传入的回调函数被立刻执行了,那阐明传入的是一个执行器那再改良一下咱们的CustomPromise class CustomPromise {  constructor(executor) {      executor() }  catch() { }  then() { }  finally() { }}const customPromise = new CustomPromise((resolve, reject) => {  console.log('hellow Promise')})console.log(customPromise)Promise基本原理与基本特征那咱们来看看咱们所熟知的Promise的基本原理 ...

January 30, 2023 · 15 min · jiezi

关于javascript:基于Sentry的前端性能监控平台搭建与应用

一、Sentry简介Sentry 是一套开源的实时异样收集、追踪、监控零碎,反对简直所有的语音和平台。 这套零碎由对应各种语言的 SDK 和一套宏大的数据后盾服务组成,通过 Sentry SDK 的配置,能够上报谬误关联的版本信息、公布环境。同时 Sentry SDK 会主动捕获异样产生前的相干操作,便于后续异样追踪。最初,异样数据上报到数据服务之后,会通过过滤、要害信息提取、演绎展现在数据后盾的 Web 界面中,性能架构如下图所示。 二、环境搭建2.1 官网Sentry服务Sentry我的项目是开源的,然而也提供付费版本,省去本人搭建和保护 Python 服务的麻烦。本人搭建的话,灵活性绝对较高,能够做很多的定制化开发。首先,咱们关上并登录官网注册账号。 2.2 私有化部署Sentry 的治理后盾是基于 Python Django 开发的。同时,这个治理后盾须要用到 Postgres 数据库(治理后盾默认的数据库)、ClickHouse(存数据特色的数据库)、relay、kafka、redis 等一些根底服务或由 Sentry 官网保护的总共 23 个服务撑持运行。如果独立的部署和保护这 23 个服务将是异样简单和艰难的,侥幸的是,官网提供了基于docker 镜像的一键部署实现 getsentry/onpremise。所以,在私有化部署之前,咱们须要在本地搭建Docker 和 Python 环境。须要阐明的是,上面的所有私有化部署都是基于Linux零碎环境的。上面是装置所需的一些软硬件环境。 Docker 19.03.6+Docker-Compose 1.28.0+4 CPU Cores8 GB RAM20 GB Free Disk Space2.3 装置docker首先,咱们在cenos服务器上安装一些工具软件,装置的命令如下。 yum install yum-utils device-mapper-persistent-data lvm2 -y  而后,咱们将镜像源设置阿里的。 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 接下来,咱们应用yum命令装置docker。 yum install docker-ce docker-ce-cli containerd.io -y而后,应用如下命令启动docker。 ...

January 30, 2023 · 3 min · jiezi

关于javascript:TS数组和元组

数组在ts中,定义数组类型语法: <font color=red>let 变量名 : 数据类型[] = [值1,值2,值3] let arr1 : number[] = [1,2,3,4]console.log(arr1);// 输入 [1,2,3,4]此外数字类型的定义还能够应用泛型,对于泛型的内容,上面只是做一个数组类型的演示,具体的请看后续对于泛型的篇章。泛型定义数组的写法:<font color=red>let 变量名 : Array<数据类型> = [值1,值2,值3] let arr2 : Array<number> = [5,6,7,8]console.log(arr2);// 输入 [5,6,7,8]定义数组类型须要留神的是,数组定义后,数组内的数据类型必须和定义数组的时候的类型是统一的,否则会有谬误提醒,某些状况下不会编译通过。 元组在ts中,元组类型就是在定义数组的时候,类型和数据的个数一开始就曾经限定好了。元组类型的语法 :let arr : [ string ,number,boolean ] = [ '东方不败' , 100 , true ] let arr3 : [string,number,boolean] = ['东方不败',100.123,true]console.log(arr3);// 输入 ['东方不败',100.123,true]应用元组类型时,须要留神的是,元组类型在应用的时候,数据的类型的地位和数据的个数,须要和 在定义元组的时候的数据类型和地位相一致,不统一则会报错提醒,如下: let arr3 : [string,number,boolean] = ['东方不败',true,123] // 报错// 类型程序为 string, number, boolean 此处传的值为 string boolean number 能够对元组内的值进行更改,比方: ...

January 29, 2023 · 1 min · jiezi

关于javascript:sort排序以及多个属性数组对象排序按条件排序

原生排序let arr = [5,2,1,4,9,8]for(let i = 0 ; i < arr.length ; i ++) { for(let j = 0 ; j < arr.length -1 ; j ++) { if(arr[j] > arr[j+1]){ let num = arr[j] arr[j] = arr[j+1] arr[j+1] = num comeout.innerText = arr } } // 后果 1,2,4,5,8,9 ES6排序sort() 办法是最弱小的数组办法之一。默认排序程序为按字母升序。应用数字排序,你必须通过一个函数作为参数来调用。比拟函数两个参数a和b,a-b 升序,返回b-a 降序留神: 这种办法会扭转原始数组! // 升序 arr.sort(function(a,b){ return a - b }) console.log(arr)// 后果 1,2,4,5,8,9// 降序arr.sort(function(a,b){ return b - a }) console.log(arr)// 后果 9,8,5,4,2,1 ...

January 28, 2023 · 1 min · jiezi

关于javascript:objabc获取值的异常处理

在平时开发过程中,总是会遇到相似于通过obj.a.b.c的形式去获取对象深层蕴含的值,然而,如果遇到a、b或者c是null、undefined、1、'2'和true等数据类型时就会呈现报错。而且,咱们往往通过后端从数据库获取到的数据,这个链路中,说不准哪一天就会在传递的过程中呈现相似的状况。上面咱们手写get办法,杜绝这种状况的产生。 1.get函数let get = function (obj, path, defaultValue) { // 将门路拆分成数组 let pathArr = path.split('.'); // 默认是传入的值 let currentValue = obj; for (let i = 1; i < pathArr.length; i++) { // 边界1:如果上一次值不是对象,或者为null,或者为undefined,间接返回默认值 if (typeof currentValue !== 'object' || currentValue === null || currentValue === undefined) { return defaultValue; } // 以后门路 let path = pathArr[i] // 以后key的数组 let keys = Object.keys(currentValue) // 边界2:以后门路不在上一次值的keys中,间接返回默认值 if (!keys.includes(path)) { return defaultValue; } // 获取以后门路下的值 currentValue = currentValue[path]; } return currentValue;}2、测试案例// 测试1let obj1 = { a: [{ b: { c: 3 } }]}console.log(get(obj1, 'obj1.a.0.b.c', -1)) // 3console.log(get(obj1, 'obj1.a.0.d.c', -1)) // -1console.log(get(obj1, 'obj1.a.0.b.c.f', -1)) // -1// 测试2let obj2 = { a: { b: null }}console.log(get(obj2, 'obj2.a.b', -1)) // nullconsole.log(get(obj2, 'obj2.a.b.c', -1)) // -1// 测试3let obj3 = { a: { b: undefined }}console.log(get(obj3, 'obj3.a.b', -1)) // undefinedconsole.log(get(obj3, 'obj3.a.b.c', -1)) // -1。

January 28, 2023 · 1 min · jiezi

关于javascript:CryptoJs-加密

惯例明码加密样例: import { CryptoJs } from "@/js/crypto.js"; let passwordVal = CryptoJs().Base64.stringify(CryptoJs().HmacSha256(this.password, 'Meiauto$'));crypto.js 源码 export const CryptoJs = () => { const CryptoJs = {} class Base { /** * Extends this object and runs the init method. * Arguments to create() will be passed to init(). * * @return {Object} The new object. * * @static * * @example * * var instance = MyType.create(); */ static create(...args) { return new this(...args); } /** * Copies properties into this object. * * @param {Object} properties The properties to mix in. * * @example * * MyType.mixIn({ * field: 'value' * }); */ mixIn(properties) { return Object.assign(this, properties); } /** * Creates a copy of this object. * * @return {Object} The clone. * * @example * * var clone = instance.clone(); */ clone() { const clone = new this.constructor(); Object.assign(clone, this); return clone; } } class WordArray extends Base { /** * Initializes a newly created word array. * * @param {Array} words (Optional) An array of 32-bit words. * @param {number} sigBytes (Optional) The number of significant bytes in the words. * * @example * * var wordArray = CryptoJS.lib.WordArray.create(); * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); */ constructor(words = [], sigBytes = words.length * 4) { super(); let typedArray = words; // Convert buffers to uint8 if (typedArray instanceof ArrayBuffer) { typedArray = new Uint8Array(typedArray); } // Convert other array views to uint8 if ( typedArray instanceof Int8Array || typedArray instanceof Uint8ClampedArray || typedArray instanceof Int16Array || typedArray instanceof Uint16Array || typedArray instanceof Int32Array || typedArray instanceof Uint32Array || typedArray instanceof Float32Array || typedArray instanceof Float64Array ) { typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); } // Handle Uint8Array if (typedArray instanceof Uint8Array) { // Shortcut const typedArrayByteLength = typedArray.byteLength; // Extract bytes const _words = []; for (let i = 0; i < typedArrayByteLength; i += 1) { _words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); } // Initialize this word array this.words = _words; this.sigBytes = typedArrayByteLength; } else { // Else call normal init this.words = words; this.sigBytes = sigBytes; } } /** * Creates a word array filled with random bytes. * * @param {number} nBytes The number of random bytes to generate. * * @return {WordArray} The random word array. * * @static * * @example * * var wordArray = CryptoJS.lib.WordArray.random(16); */ static random(nBytes) { const words = []; const r = (m_w) => { let _m_w = m_w; let _m_z = 0x3ade68b1; const mask = 0xffffffff; return () => { _m_z = (0x9069 * (_m_z & 0xFFFF) + (_m_z >> 0x10)) & mask; _m_w = (0x4650 * (_m_w & 0xFFFF) + (_m_w >> 0x10)) & mask; let result = ((_m_z << 0x10) + _m_w) & mask; result /= 0x100000000; result += 0.5; return result * (Math.random() > 0.5 ? 1 : -1); }; }; for (let i = 0, rcache; i < nBytes; i += 4) { const _r = r((rcache || Math.random()) * 0x100000000); rcache = _r() * 0x3ade67b7; words.push((_r() * 0x100000000) | 0); } return new WordArray(words, nBytes); } /** * Converts this word array to a string. * * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex * * @return {string} The stringified word array. * * @example * * var string = wordArray + ''; * var string = wordArray.toString(); * var string = wordArray.toString(CryptoJS.enc.Utf8); */ toString(encoder = Hex) { return encoder.stringify(this); } /** * Concatenates a word array to this word array. * * @param {WordArray} wordArray The word array to append. * * @return {WordArray} This word array. * * @example * * wordArray1.concat(wordArray2); */ concat(wordArray) { // Shortcuts const thisWords = this.words; const thatWords = wordArray.words; const thisSigBytes = this.sigBytes; const thatSigBytes = wordArray.sigBytes; // Clamp excess bits this.clamp(); // Concat if (thisSigBytes % 4) { // Copy one byte at a time for (let i = 0; i < thatSigBytes; i += 1) { const thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); } } else { // Copy one word at a time for (let i = 0; i < thatSigBytes; i += 4) { thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; } } this.sigBytes += thatSigBytes; // Chainable return this; } /** * Removes insignificant bits. * * @example * * wordArray.clamp(); */ clamp() { // Shortcuts const { words, sigBytes } = this; // Clamp words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); words.length = Math.ceil(sigBytes / 4); } /** * Creates a copy of this word array. * * @return {WordArray} The clone. * * @example * * var clone = wordArray.clone(); */ clone() { const clone = super.clone.call(this); clone.words = this.words.slice(0); return clone; } } const Latin1 = { /** * Converts a word array to a Latin1 string. * * @param {WordArray} wordArray The word array. * * @return {string} The Latin1 string. * * @static * * @example * * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); */ stringify(wordArray) { // Shortcuts const { words, sigBytes } = wordArray; // Convert const latin1Chars = []; for (let i = 0; i < sigBytes; i += 1) { const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; latin1Chars.push(String.fromCharCode(bite)); } return latin1Chars.join(''); }, /** * Converts a Latin1 string to a word array. * * @param {string} latin1Str The Latin1 string. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); */ parse(latin1Str) { // Shortcut const latin1StrLength = latin1Str.length; // Convert const words = []; for (let i = 0; i < latin1StrLength; i += 1) { words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); } return new WordArray(words, latin1StrLength); }, }; const Utf8 = { /** * Converts a word array to a UTF-8 string. * * @param {WordArray} wordArray The word array. * * @return {string} The UTF-8 string. * * @static * * @example * * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); */ stringify(wordArray) { try { return decodeURIComponent(escape(Latin1.stringify(wordArray))); } catch (e) { throw new Error('Malformed UTF-8 data'); } }, /** * Converts a UTF-8 string to a word array. * * @param {string} utf8Str The UTF-8 string. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); */ parse(utf8Str) { return Latin1.parse(unescape(encodeURIComponent(utf8Str))); }, }; class BufferedBlockAlgorithm extends Base { constructor() { super(); this._minBufferSize = 0; } /** * Resets this block algorithm's data buffer to its initial state. * * @example * * bufferedBlockAlgorithm.reset(); */ reset() { // Initial values this._data = new WordArray(); this._nDataBytes = 0; } /** * Adds new data to this block algorithm's buffer. * * @param {WordArray|string} data * * The data to append. Strings are converted to a WordArray using UTF-8. * * @example * * bufferedBlockAlgorithm._append('data'); * bufferedBlockAlgorithm._append(wordArray); */ _append(data) { let m_data = data; // Convert string to WordArray, else assume WordArray already if (typeof m_data === 'string') { m_data = Utf8.parse(m_data); } // Append this._data.concat(m_data); this._nDataBytes += m_data.sigBytes; } /** * Processes available data blocks. * * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. * * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. * * @return {WordArray} The processed data. * * @example * * var processedData = bufferedBlockAlgorithm._process(); * var processedData = bufferedBlockAlgorithm._process(!!'flush'); */ _process(doFlush) { let processedWords; // Shortcuts const { _data: data, blockSize } = this; const dataWords = data.words; const dataSigBytes = data.sigBytes; const blockSizeBytes = blockSize * 4; // Count blocks ready let nBlocksReady = dataSigBytes / blockSizeBytes; if (doFlush) { // Round up to include partial blocks nBlocksReady = Math.ceil(nBlocksReady); } else { // Round down to include only full blocks, // less the number of blocks that must remain in the buffer nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); } // Count words ready const nWordsReady = nBlocksReady * blockSize; // Count bytes ready const nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); // Process blocks if (nWordsReady) { for (let offset = 0; offset < nWordsReady; offset += blockSize) { // Perform concrete-algorithm logic this._doProcessBlock(dataWords, offset); } // Remove processed words processedWords = dataWords.splice(0, nWordsReady); data.sigBytes -= nBytesReady; } // Return processed words return new WordArray(processedWords, nBytesReady); } /** * Creates a copy of this object. * * @return {Object} The clone. * * @example * * var clone = bufferedBlockAlgorithm.clone(); */ clone() { const clone = super.clone.call(this); clone._data = this._data.clone(); return clone; } } class Hasher extends BufferedBlockAlgorithm { constructor(cfg) { super(); this.blockSize = 512 / 32; /** * Configuration options. */ this.cfg = Object.assign(new Base(), cfg); // Set initial values this.reset(); } /** * Creates a shortcut function to a hasher's object interface. * * @param {Hasher} SubHasher The hasher to create a helper for. * * @return {Function} The shortcut function. * * @static * * @example * * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); */ static _createHelper(SubHasher) { return (message, cfg) => new SubHasher(cfg).finalize(message); } /** * Creates a shortcut function to the HMAC's object interface. * * @param {Hasher} SubHasher The hasher to use in this HMAC helper. * * @return {Function} The shortcut function. * * @static * * @example * * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); */ static _createHmacHelper(SubHasher) { return (message, key) => new HMAC(SubHasher, key).finalize(message); } /** * Resets this hasher to its initial state. * * @example * * hasher.reset(); */ reset() { // Reset data buffer super.reset.call(this); // Perform concrete-hasher logic this._doReset(); } /** * Updates this hasher with a message. * * @param {WordArray|string} messageUpdate The message to append. * * @return {Hasher} This hasher. * * @example * * hasher.update('message'); * hasher.update(wordArray); */ update(messageUpdate) { // Append this._append(messageUpdate); // Update the hash this._process(); // Chainable return this; } /** * Finalizes the hash computation. * Note that the finalize operation is effectively a destructive, read-once operation. * * @param {WordArray|string} messageUpdate (Optional) A final message update. * * @return {WordArray} The hash. * * @example * * var hash = hasher.finalize(); * var hash = hasher.finalize('message'); * var hash = hasher.finalize(wordArray); */ finalize(messageUpdate) { // Final message update if (messageUpdate) { this._append(messageUpdate); } // Perform concrete-hasher logic const hash = this._doFinalize(); return hash; } } class HMAC extends Base { /** * Initializes a newly created HMAC. * * @param {Hasher} SubHasher The hash algorithm to use. * @param {WordArray|string} key The secret key. * * @example * * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); */ constructor(SubHasher, key) { super(); const hasher = new SubHasher(); this._hasher = hasher; // Convert string to WordArray, else assume WordArray already let _key = key; if (typeof _key === 'string') { _key = Utf8.parse(_key); } // Shortcuts const hasherBlockSize = hasher.blockSize; const hasherBlockSizeBytes = hasherBlockSize * 4; // Allow arbitrary length keys if (_key.sigBytes > hasherBlockSizeBytes) { _key = hasher.finalize(key); } // Clamp excess bits _key.clamp(); // Clone key for inner and outer pads const oKey = _key.clone(); this._oKey = oKey; const iKey = _key.clone(); this._iKey = iKey; // Shortcuts const oKeyWords = oKey.words; const iKeyWords = iKey.words; // XOR keys with pad constants for (let i = 0; i < hasherBlockSize; i += 1) { oKeyWords[i] ^= 0x5c5c5c5c; iKeyWords[i] ^= 0x36363636; } oKey.sigBytes = hasherBlockSizeBytes; iKey.sigBytes = hasherBlockSizeBytes; // Set initial values this.reset(); } /** * Resets this HMAC to its initial state. * * @example * * hmacHasher.reset(); */ reset() { // Shortcut const hasher = this._hasher; // Reset hasher.reset(); hasher.update(this._iKey); } /** * Updates this HMAC with a message. * * @param {WordArray|string} messageUpdate The message to append. * * @return {HMAC} This HMAC instance. * * @example * * hmacHasher.update('message'); * hmacHasher.update(wordArray); */ update(messageUpdate) { this._hasher.update(messageUpdate); // Chainable return this; } /** * Finalizes the HMAC computation. * Note that the finalize operation is effectively a destructive, read-once operation. * * @param {WordArray|string} messageUpdate (Optional) A final message update. * * @return {WordArray} The HMAC. * * @example * * var hmac = hmacHasher.finalize(); * var hmac = hmacHasher.finalize('message'); * var hmac = hmacHasher.finalize(wordArray); */ finalize(messageUpdate) { // Shortcut const hasher = this._hasher; // Compute HMAC const innerHash = hasher.finalize(messageUpdate); hasher.reset(); const hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); return hmac; } } // Initialization and round constants tables const H = []; const K = []; // Compute constants const isPrime = (n) => { const sqrtN = Math.sqrt(n); for (let factor = 2; factor <= sqrtN; factor += 1) { if (!(n % factor)) { return false; } } return true; }; const getFractionalBits = n => ((n - (n | 0)) * 0x100000000) | 0; let n = 2; let nPrime = 0; while (nPrime < 64) { if (isPrime(n)) { if (nPrime < 8) { H[nPrime] = getFractionalBits(n ** (1 / 2)); } K[nPrime] = getFractionalBits(n ** (1 / 3)); nPrime += 1; } n += 1; } // Reusable object const W = []; class SHA256Algo extends Hasher { _doReset() { this._hash = new WordArray(H.slice(0)); } _doProcessBlock(M, offset) { // Shortcut const _H = this._hash.words; // Working variables let a = _H[0]; let b = _H[1]; let c = _H[2]; let d = _H[3]; let e = _H[4]; let f = _H[5]; let g = _H[6]; let h = _H[7]; // Computation for (let i = 0; i < 64; i += 1) { if (i < 16) { W[i] = M[offset + i] | 0; } else { const gamma0x = W[i - 15]; const gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ ((gamma0x << 14) | (gamma0x >>> 18)) ^ (gamma0x >>> 3); const gamma1x = W[i - 2]; const gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ ((gamma1x << 13) | (gamma1x >>> 19)) ^ (gamma1x >>> 10); W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; } const ch = (e & f) ^ (~e & g); const maj = (a & b) ^ (a & c) ^ (b & c); const sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); const sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); const t1 = h + sigma1 + ch + K[i] + W[i]; const t2 = sigma0 + maj; h = g; g = f; f = e; e = (d + t1) | 0; d = c; c = b; b = a; a = (t1 + t2) | 0; } // Intermediate hash value _H[0] = (_H[0] + a) | 0; _H[1] = (_H[1] + b) | 0; _H[2] = (_H[2] + c) | 0; _H[3] = (_H[3] + d) | 0; _H[4] = (_H[4] + e) | 0; _H[5] = (_H[5] + f) | 0; _H[6] = (_H[6] + g) | 0; _H[7] = (_H[7] + h) | 0; } _doFinalize() { // Shortcuts const data = this._data; const dataWords = data.words; const nBitsTotal = this._nDataBytes * 8; const nBitsLeft = data.sigBytes * 8; // Add padding dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - (nBitsLeft % 32)); dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; data.sigBytes = dataWords.length * 4; // Hash final blocks this._process(); // Return final computed hash return this._hash; } clone() { const clone = super.clone.call(this); clone._hash = this._hash.clone(); return clone; } } CryptoJs.HmacSha256 = Hasher._createHmacHelper(SHA256Algo); CryptoJs.Base64 = { stringify: function (wordArray) { // Shortcuts const words = wordArray.words; const sigBytes = wordArray.sigBytes; const map = this._map; // Clamp excess bits wordArray.clamp(); // Convert const base64Chars = []; for (let i = 0; i < sigBytes; i += 3) { const byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; const byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; const byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; const triplet = (byte1 << 16) | (byte2 << 8) | byte3; for (let j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); } } // Add padding const paddingChar = map.charAt(64); if (paddingChar) { while (base64Chars.length % 4) { base64Chars.push(paddingChar); } } return base64Chars.join(''); }, _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' } return CryptoJs}

January 28, 2023 · 14 min · jiezi

关于javascript:前端常用重难点总结之vue篇

补上集体 vue 心得。 1、vue全家桶配置:vue+vuex+vue-router+UI(semantic-ui或者element-ui等)2、遇到问题能够从这几个方向动手,个别都能解决问题(1)生命周期(2)watch(3)$nexttick (4)vuex (5)vue-router (6)props3、v-if和v-for联合一起用能进步性能4、:key的灵便利用有奇效,补救了局部vue动静响应的缺点5、多用vue.set和splice(为了动静响应)6、计算属性computed里的...mapState进去的数据不能间接改,得通过$store.state.xxxx操作更改或者去actions、mutations改state7、路由和页面的关系和重点:进入路由(页面)时候的操作和来到路由(页面)时候的操作往往成为跨路由和跨页面数据同步的要害8、须要动静响应的数据不能间接定义在date的根级别如 data() {return {row:""}是不行的,须要定义成 data() {return {row:{row:""}},而后调用row.row能力动静响应。9、单文件组件要点分为三局部template、script、style三局部<1>、<template> ***这部分是html***</template><2>、<script>***此局部可引入import所需的组件、库等、可输入***export default{components:{},data(){},methods:{},props: {},created(),mounted() {},watch{}}***等生命周期和组件等内容</script><3>、<style scoped>***此局部为组件款式***</style>

January 24, 2023 · 1 min · jiezi

关于javascript:前端常用重难点总结之js篇

也许多少年后在某个中央,我将轻声叹气把往事回顾:一片树林里分出好几条路,而我抉择了人迹更少的一条,从此决定了我毕生的路线。以下为集体js重难点整顿。 <1>根底1、赋值的了解,=号的含意2、作用域<=>上下文<=>this三者的含意和区别3、括号语法[]和.语法的区别4、字符串和变量拼接<=>字符串和其余数据类型的区别5、参数、传参的含意和应用6、对象和数组的区别7、if else和for循环两把斧子闯天下(for of用于类数组对象)9、break、continue、return(重要)10、json11、ajax12、数组length的妙用,可配合push()等办法,罕用于for循环、数组的清空等。13、bind<=>apply<=>call三者的区别和利用14、闭包及其利用场景(可能读取其余函数外部变量的函数叫闭包)15、各种平安集:如禁用eval、function、this、with、window、document等<2>es61、箭头函数的了解(return、this指向等)2、解构赋值 比方 let{r:red,g:green,b:blue}=object 被赋值的为red、green、blue三个变量名3、生成器函数4、模块化5、promise、async的了解和利用6、class的了解利用(多用class、extend取代js传统原型的类实现形式)7、es6标准:let 取代 var ,多用单引号''和反引号``取代双引号"",多用箭头函数取代bind,import取代require等等8、同步异步<==>阻塞与非阻塞<==>promise、async等几个概念的了解和相互之间的关系9、状态机、迭代器等等。。。

January 24, 2023 · 1 min · jiezi

关于javascript:手写一个-new

写在前边:手写一个 new 咱们须要理解原型的概念,和 this的指向问题。 在执行 new 的时候做了什么咱们执行 new 来看一下 new 的过程中产生了什么: function Person(name) { this.name = name this.sayName = function () { console.log('name', this.name) }}const person = new Person('ayetongzhi')console.log('person', person)person.sayName()打印后果如上,依据打印后果咱们能够晓得: 返回了一个对象(person),这个对象不会凭空的产生,因而在 new 的过程中是创立了一个对象并返回。将 this 指向创立的新对象,并执行函数。须要将 this 指向新的对象,能力构造函数的属性赋值给实例对象。扭转实例 的 \_\_proto\_\_ 属性,指向构造函数的原型。如下图所示,通过构造函数 (Function) 创立的实例(instance) ,它的 \_\_proto\_\_ 属性指向构造函数 (Function)的 prototype。构造函数显示的返回一个对象,则返回该对象。上面对这条问题进行解释,上代码:function Person(name) { this.name = name; this.sayName = function () { console.log("name", this.name); }; // 显示的返回一个对象 return { name: "maomao", sayName: function () { console.log("name", this.name); } };}const person = new Person("ayetongzhi");console.log("person", person);person.sayName(); //maomao运行后果可知,在 new Person 操作后返回了return前面返回的对象。 ...

January 23, 2023 · 2 min · jiezi

关于javascript:day4-如何通过部分应用和柯里化让函数具象化

局部利用和柯里化函数的输出来自于参数,其中蕴含函数定义的形参和理论执行时的实参通过局部利用提早实参传入函数式编程重在申明式和可读性,而且强调每个函数尽量解决一个繁多问题。函数式编程中,咱们通常会应用局部利用。它所做的就是形象一个 partial 工具,在先预制局部参数的状况下,后续再传入残余的参数值。如以下代码所示: var fetchOrder = partial( orderEventHandler, "http://some.api/order" );var getCurrentOrder = partial( fetchOrder, { order: CURRENT_ORDER_ID } );...拓展操作符能够在函数调用或数组结构时,将数组表达式或者 string 在语法层面开展。在这里,咱们能够用它来解决预置的和后置的实参。而闭包在这里再次施展了记忆的性能,它会记住前置的参数,并在下一次收到后置的参数时,能够和后面记住的前置参数一起执行。 var partial = (fn,...presetArgs) => (...laterArgs) => fn( ...presetArgs, ...laterArgs );通过柯里化每次传一个参数 延展操作符能够在函数调用链中起到承前启后的作用。一个一般的函数通常是在调用点执行时传入参数的,而通过局部利用和柯里化,咱们做到了能够先传入局部已知参数,再在之后的某个工夫传入局部参数,这样从工夫和空间上,就将一个函数离开了。其余益处:解决未知,让函数从形象变具体、让具体的函数每次只分心做好一件事、缩小参数数量之外,还有一个更形象的益处,就是体现了函数式底层的申明式思维。罕用的参数解决工具:在函数式编程中,咱们把参数的数量叫做 arity。局部利用能够缩小每次函数调用时须要传入的参数,而柯里化更是把函数调用时须要传入的参数数量,降到了 1。它们实际上都起到了控制参数数量的作用。革新接口 unary:一元参数(unary)把一个接管多个参数的函数,变成一个只接管一个参数的函数。 function unary(fn) { return function oneArg(arg){ return fn( arg ); };}示例: ["1","2","3","4","5"].map( unary( parseInt ) ); // [1,2,3,4,5]革新参数 constant:函数签名:函数签名个别蕴含了参数及其类型返回值,还有类型可能引发或传回的异样,以及相干的办法在面向对象中的可用性信息(如关键字 public、static 或 prototype)。你能够看到在 C 或 C++ 中,会有相似这样的签名 function constant(v) { return function value(){ return v; };}咱们就能够把值包装在 constant 函数里,通过这样的形式,就能够把值作为函数参数传入了。 ...

January 19, 2023 · 1 min · jiezi