首页 文章 精选 留言 我的

精选列表

搜索[JavaScript],共9119篇文章
优秀的个人博客,低调大师

JavaScript 中 at() 方法在数组和字符串中的实际应用与边界处理

在维护一个数据看板项目时,我经常需要从数组或字符串的末尾取元素。以前习惯用 arr[arr.length - 1] 或者 str.charAt(str.length - 1),写多了总觉得啰嗦,而且一旦变量名很长,代码读起来就有点费劲。后来发现 ES2022 给数组、字符串和 TypedArray 都加了 at() 方法,可以直接传负数索引,从末尾往前数。这个 API 在 Chrome 92+、Node 16.6+ 都已经支持,但实际用的时候有几个细节容易踩坑:比如它不改变原数组,对稀疏数组的处理和普通索引一样,字符串上返回的是单个字符而不是码点。这篇文章会结合几个真实场景,聊聊 at() 的用法、和传统写法的对比,以及当索引越界或遇到非整数时它到底返回什么。

优秀的个人博客,低调大师

JavaScript 中 requestAnimationFrame 在后台标签页不触发的问题排查与替代方案

做数据大屏或者定时轮询渲染的时候,很容易遇到一个现象:页面切到后台再切回来,某些依赖于 requestAnimationFrame 的动画或状态更新会「卡住」几秒,甚至像是什么都没发生。浏览器为了省电和降低 CPU,在标签页不可见时会暂停 requestAnimationFrame 的回调,把它降频甚至完全冻结。但业务里可能用它来驱动非纯视觉任务,比如轮询状态、计算布局、播放帧序列,这时候就出问题了。下面从一次实际排查过程说起,看看为什么会这样,以及除了切回页面强制刷新外,还有哪些更可控的写法。

优秀的个人博客,低调大师

JavaScript中关于this关键字的魔幻现实 一篇文章搞懂他

不得不承认JS中存在一些“历史的遗产”,比如基于全局变量的编程模型。 如果写一个函数,如: function test(name){ var namex = name console.log(this.namex) } test('jack') 方法调用之后,this.namex=undefined,为何呢?因为此处的this是全局对象window,这就令人比较头大。 不过别着急,慢慢往下看,关于this还有很多魔幻的现实,我们来一一解锁。 1、完整的函数调用 还是上面的代码,其实他的完整调用写法是这样的: function test(name){ var namex = name console.log(this.namex) } test.call(undefined, 'jack') test是一个函数对象--即Function对象,Function.prototype有call方法。call()会有两个参数,第一个参数是this上下文对象,第二个参数是函数入参列表。 如果call()传入的this上下文是undefined或null,那么window对象将成为默认的this上下文 2、对象中的this const obj = { name: 'Jack', greet: function() { console.log(this.name) } } obj.greet() //简写调用 obj.greet.call(obj) //完整调用 obj.greet()中的this无疑就是obj对象 3、对象方法中嵌套函数的this 对2中的代码进行修改: const obj = { name: 'Jack', greet: function() { retufn function(){console.log(this.name)} } } obj.greet()() //输出null 需要注意的是嵌套函数中的this依然是window,为什么呢?可以拆分来看: var greet = obj.greet() greet() // = greet.call(undefined) 嵌套函数被调用的时候,真实的调用者上下文是undefined,也就是window 4、原型与this function Clt() { } Clt.prototype.x = 10 Clt.prototype.test = function () { console.log(this) this.y = this.x + 1 } let bean = new Clt() bean.test(); console.log(bean.y) test方法中输出的this是一个Clt对象。 这里需要引入一个新的概念:构造器函数。 new关键字就是构造器函数,它的作用是: 一旦函数被new来调用,就会创建一个链接到该函数的prototype属性的新对象,同时this会被绑定到那个新对象上 理解了构造器函数,我们就理解了原型与this的关系了,因为new会重新指定this上下文 5、箭头函数与this ECMAScript6出现了箭头函数的用法,关于箭头函数中的this,需要先记住一句话: 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 看代码(引自阮一峰老师的教程:https://es6.ruanyifeng.com/#docs/function#%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0): function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42 此处的this指向了foo的this上下文,即定义时的this对象。 箭头函数与非箭头函数的this区别: function Timer() { this.s1 = 0; this.s2 = 0; // 箭头函数 setInterval(() => this.s1++, 1000); // 普通函数 setInterval(function () { this.s2++; }, 1000); } var timer = new Timer(); setTimeout(() => console.log('s1: ', timer.s1), 3100); setTimeout(() => console.log('s2: ', timer.s2), 3100); // s1: 3 // s2: 0 箭头函数的this指向了定义时所在对象的this;非箭头函数的this指向了运行时的作用域,即全局域window this的指向固定化,也算是解决了一些历史旧账,无疑带来的很大好处,比如封装调用: var handler = { id: '123456', init: function() { document.addEventListener('click', event => this.doSomething(event.type), false); }, doSomething: function(type) { console.log('Handling ' + type + ' for ' + this.id); } }; 一个嵌套的例子: function foo() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } var f = foo.call({id: 1}); var t1 = f.call({id: 2})()(); // id: 1 var t2 = f().call({id: 3})(); // id: 1 var t3 = f()().call({id: 4}); // id: 1 最里层的this也绑定到了定义时所在对象的—即foo的this 总结 ECMAScript6的箭头函数也算是解决了一些历史问题。不过正如HTML5离不开HTML4一样,因为只有保持了继承与兼容,新技术的推广才会更加的迅速。 享受语言新特性之余,也要搞清楚旧版本的一些细节,这有助于更全面的掌握知识。 希望这篇文章对您有用!

优秀的个人博客,低调大师

通过阶乘的例子,练习在JavaScript, Scala和ABAP里实现尾递归(Tail Recursion)

Before we start to research tail recursion, let’s first have a look at the normal recursion. A simple factorial implementation by recursion: function factorial(n){ if(n ===1) { return 1; } return n *factorial(n -1); } Let N = 5, see how new stack frame is created for each time of recursive call: We have two stack frames now, one stores the context when n = 5, and the topmost one for current calculation: n = 4 Now since n equals to 1, we stop recursion. The current stack frame ( n = 1 ) will be poped up, the frame under it will be activated and become the topmost frame, with calculated result 1 passed into. key note for normal recursion: during recursion, every generated stack frame is needed and could not e destroyed until the final result is calculated. The calculation is actually not started until the recursion reaches the end ( the condition n === 1 fulfills ). If N is a big integer, it will lead to huge number of stack frames and finally the “stack overflow” or “out of memory” is inevitable. tail recursion Source code below: function tailFactorial(n, total) { if(n ===1) return total; return tailFactorial(n -1, n * total); } function factorial2(n) { return tailFactorial(n,1); } There are two biggest differences compared with normal recursion: (1) A new internal function tailFactorial is introduced here. (2) The calculation is actually now spread within every recursive stack frame. Each frame finishes one part of calculation and pass the current result to the next frame. Once the current stack frame finishes its task, it is actually not needed any more. And thus for example the model browser can then do some optimization on those useless stack frames. Observe the stack frame for tail recursion step by step: stack popped up: When N = 20, the tail recursion has a far better performance than the normal recursion: Update 2016-01-11 Tail recursion implementation via Scala: The interesting thing is, after the Scala code is compiled into Java Byte code, compiler will eliminate the recursion automatically: Tail Recursion in ABAP First this is the normal recursion: REPORT zrecursion. START-OF-SELECTION. DATA: lv_result TYPE int4. PERFORM fac USING 6 CHANGING lv_result. WRITE: / lv_result. FORM fac USING iv_n TYPE int4 CHANGING cv_result TYPE int4. DATA: lv_n TYPE i. cv_result = lv_n = iv_n. lv_n = lv_n - 1. IF lv_n > 1. PERFORM fac USING lv_n CHANGING cv_result. ENDIF. IF lv_n = 1. cv_result = cv_result * lv_n. ELSE. cv_result = cv_result * iv_n. ENDIF. ENDFORM. And here comes tail recursion version: REPORT ztail. START-OF-SELECTION. DATA: lv_result TYPE int4. PERFORM fac USING 5 1 CHANGING lv_result. WRITE: / lv_result. FORM fac USING iv_n TYPE int4 iv_acc TYPE int4 CHANGING cv_result TYPE int4. DATA: lv_n TYPE i, lv_accumulate TYPE i. IF iv_n < 1. cv_result = 1. ELSEIF iv_n = 1. cv_result = iv_acc * iv_n. ELSEIF iv_n > 1. lv_n = iv_n - 1. lv_accumulate = iv_acc * iv_n. PERFORM fac USING lv_n lv_accumulate CHANGING cv_result. ENDIF. ENDFORM. 本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。

优秀的个人博客,低调大师

JavaScript ES6 Fetch API时需要注意的一个Cookie问题

When I am doing a test of comparison between Stateful and Stateless BSP application ( mentioned in blog Stateless and Stateful – Different behavior in application side ), I meet with a strange issue. The conclusion is stateful BSP application will handle request sequentially. Suppose in client I send two request A and B to server. Request A takes 3 seconds to finish and B 2 seconds. The request is sent via jQuery API.It means for stateful application, I will observe the following timeline in Chrome network tab: (1) the start time of both request are almost the same, since I send out two request in client code almost at the same time.(2) even though the second request itself takes 2 seconds to finish, the total processing time for it is 3 seconds waiting for A to finish first + 2 seconds = 5 seconds in the end. The above test did verify the conclusion.However when I change the approach to send request into ES6 fetch API, <%@page language="abap" %> <%@extension name="htmlb" prefix="htmlb" %> <!DOCTYPE html> <html> <head> <title>Jerry Test Stateful</title> </head> <body> <button onclick="fire()">Fire two request</button> <script> function wrapperOnFetch(url){ fetch(url).then(function(response){ return response.json(); }).then(function(json){ console.log(url + ":" + json.message); }); } function fire(){ wrapperOnFetch("first.json"); wrapperOnFetch("second.json"); } </script> </body> </html> the testing request for stateful application looks as below this time: The two requests are handled simultaneously ( request B only takes 2 seconds to finish, no 3 seconds’ wait time for A to finish this time ), the response of second request returns first before the first, which could be observed in console: why the latest ES6 API causes such discrepancy with known conclusion?Just compare the cookie of requests sent via these two kinds of API: Through comparison I get to know that the session cookiesap-contextid is not sent together with request triggered by ES6 Fetch API.Then in Fetch documentation I find out that I need to add option credentials: “include”. function wrapperOnFetch(url){ // enable session cookie sent with request fetch(url,{ credentials:"include" }).then(function(response){ return response.json(); }).then(function(json){ console.log(url + ":" + json.message); }); } After this change the stateful BSP application behaves as expected: the requests are handled in sequence. 本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。

优秀的个人博客,低调大师

【CDN云课堂】技术专家直播分享:如何在CDN边缘节点执行你的JavaScript?

Serverless和边缘计算都是目前云计算领域备受瞩目的研究和应用方向。做为拥有超过130Tbps带宽分发能力的阿里云CDN,巨大的边缘网络有超过2800个节点遍布全球,如何将中心源站的计算能力下沉到边缘节点,进一步降低客户端访问延时进而提升用户体验,一直是阿里云CDN投入重点研究的方向。 阿里云CDN将Serverless和边缘计算的优势相融合,推出边缘轻量编程环境—EdgeRoutine,4月27日(周一)晚19:00,阿里云CDN技术专家将带来一场线上直播,分享阿里云CDN边缘轻量编程环境-EdgeRoutine的原理、使用场景和实践案例,欢迎大家点击报名观看。 直播介绍 直播主题:CDN边缘轻量编程环境—EdgeRoutine发布直播时间:4月27日(周一)晚19:00直播讲师:阿里云技术专家 洪晓龙直播内容:分享阿里云CDN

优秀的个人博客,低调大师

Javascript前端开发:阿里JS面试题让你深入了解原型与继承

题目如下: var F = function(){} Object.prototype.a = function(){ console.log('a()') } Function.prototype.b = function(){ console.log('b()') } var f = new F() F.a() F.b() f.a() f.b() 主要考查的技术点: 1.、原型与原型链 2、实例对象、构造函数、Object、 Function的关系 分析: F是个构造函数,而f是构造函数F的一个实例。 因为F instanceof Object == true、F instanceof Function == true 由此我们可以得出结论:F是Object 和 Function两个的实例,即F既能访问到a,也能访问到b。 所以F.a() 输出 a() F.b() 输出 b() 对于f,我们先来看下下面的结果: f并不是Function的实例,因为它本来就不是构造函数,所以就调用Function原型链上的相关属性和方法了,只能访问Object原型链。 所以f.a() 输出 a() 而f.b()就报错了。 接下来,我们具体分析下,它们是如何按路径查找的: f.a的查找路径: f自身: 没有 ---> f.__proto__(Object.prototype): 输出a() f.b的查找路径: f自身: 没有 ---> f.__proto__(Object.prototype): 没有 ---> f.__proto__.__proto__ (Object.prototype.__proto__): 因为找不到,所以报错 F.a的查找路径: F自身: 没有 ---> F.__proto__(Function.prototype): 没有 ---> F.__proto__.__proto__(Object.prototype): 输出 a() F.b的查找路径: F自身: 没有 ---> F.__proto__(Function.prototype): b()

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册