几周前,我们新开了一系列文章,旨在深入 JavaScript,探寻其工作原理。我们认为通过了解 JavaScript 的构建方式和其运行规则,我们能写出更好的代码和应用。
第一篇文章重点介绍了引擎、运行时和调用栈的概述。第二篇文章仔细地分析了 Google's V8 JavaScript 引擎的内部部分并且为如何编写更好的 JavaScript 代码提供了一些建议。
这是第三篇文章,我们将会讨论一个由于日常使用的编程语言日益成熟和复杂度提升从而让开发者忽略的话题——内存管理。我们还将提供一些有关如何处理 SessionStack 中 JavaScript 内存泄漏的建议,因为我们需要确保 SessionStack 不会导致内存泄漏,也不会增加我们集成的 Web 应用程序的内存消耗。
概述
像 C 语言,拥有底层原始的内存管理方法,例如:malloc() 和 free()。这些原始的方法被开发者用来从操作系统中分配内存和释放内存。
然而,JavaScript 当一些东西(objects,strings,etc.)被创建的时候分配内存并且当它们不再被使用的时候“自动”释放它们,这个过程被称为垃圾回收。
释放资源的这种看似“自动”的性质是造成困扰的根源。它给 JavaScript (和其它高级语言)开发者一个错误的印象——他们可以选择不关心内存管理。这是一个很大的错误。
即使是使用高级语言,开发者对内存管理也应该有所了解(至少要有基础的了解)。有时,开发者必须理解自动内存管理会遇到问题(例如:垃圾回收中的错误或者性能问题等),以便能够正确处理它们。(或者是找到适当的解决方法,用最小的代价去解决。)
内存的生命周期
无论你使用那种语言,内存的生命周期基本是都差不多:
一下是生命周期中每一步发生了什么的一个概述:
Allocate memory —— 操作系统分配内存,允许你的程序使用它。在基础语言中(例如 C ),这是一个开发者自己处理的明确操作。然而,在高级语言中,它已经为你处理了。
Use memory —— 现在你就可以使用之前分配好的内存了。当你在代码中使用变量时,读 和 写 的操作正在发生。
Release memory —— 现在该释放你不再需要的内存了,以便它们能够被再次使用。与分配内存的操作一样,这种操作在基础语言中是明确执行的。
要快速了解调用栈和内存堆的概念,你可以阅读我们该主题的第一篇文章。
什么时内存
在直接讨论 JavaScript 中的内存之前,我们先简略地讨论下一般内存是什么以及它的工作原理。
在硬件层面,计算机内存是有大量触发电路组成的。每个触发电路包含了一些晶体管并且能够存储一个位(bit)。单个触发器可通过唯一的标识符寻址,因此我们可以读取并重写它们。因此,在概念上,我们可以将整个计算机内存看作时我们可以读和写的一个由位组成的大数组。
因为作为人类,我们不是很善于在 位 上进行思考和计算,所以,我们将位组成更大的组,它们可以一起用来表示数字。8位称为1字节(byte)。除了字节之外,还有字(有时是 16 位,有时是 32 位)。
很多东西都存储在内存中:
所有程序使用的所有变量和其他数据。
程序的代码,包括操作系统的。
编译器和操作系统共同合作,帮助你管理内存,但我们建议你查看一下引擎盖下的内容。
编译代码时,编译器可以检查原始数据类型,并提前计算出需要多少内存。然后将所需的数量分配给调用堆栈中的程序。这些变量分配的空间称为堆栈空间,因为随着函数被调用,它们的内存被添加到现有存储器的顶部。当它们终止时,它们以 LIFO (last-in,first-out)顺序被移除。例如,考虑以下声明:
int n;
int x[4 ];
double m;
编译器立即会看到这段代码需要: 4 + 4x4 + 8 = 28 bytes。
这是现在整数和双精度的工作原理。大约 20 年前,整数通常为 2 字节,双精度为 4 字节。你的代码应该永远不依赖于此时基本数据类型的大小。
编译器将插入与操作系统交互的代码,以便在堆栈中请求要存储的变量所需的字节数。
在上面的示例中,编译器知道每个变量的精确内存地址。事实上,每当我们写入变量 n 时,在系统内部都会被翻译为“内存地址 4127963” 这样的东西。
注意,如果我们这里尝试访问 x[4] ,我们可能会访问到和 m 相关联的数据。这是因为我们访问的元素在数组中并不存在——这 4 个字节比数组中最后一个元素 x[3] 还要远,可能会读取(或重写) m 的位。这肯定会对程序产生难以理解的不良影响。
当函数调用其他函数时,每个函数在调用时都会获得自己的堆栈块。它保存所有的局部变量,还有一个程序计数器,可以记住函数在执行中的位置。当函数执行完成时,其内存块可以再次用于其他目的。
动态分配
不幸的是,当我们在编译一个不知道多少内存的变量时,事情就变的不那么容易了。假设我们要做如下的事情:
int n = readInput(); // reads input from the user
. ..
// create an array with "n" elements
这样,在编译的时候,编译器不知道数组需要多少内存,因为它依靠用户提供的输入。
因此,它不能为堆栈上的变量分配空间。相反,我们的程序需要在运行时明确地要求操作系统获得适当的空间量。这个内存时从堆空间分配的。静态和动态内存分配的区别如下表所示:
Static allocation
Dynamic allocation
编译时内存大小确定
编译时内存大小不确定
编译阶段执行
运行时执行
分配给栈
分配给堆
FILO
没有特定的顺序
为了充分了解动态内存分配的工作原理,我们需要花更多的时间在指针上,这可能与这篇文章的主题有些偏离了。如果你有兴趣了解的话,可以在评论中通知我们,我们可以在未来的文章中详细介绍指针。
JavaScript 中的分配
现在,我们将要解释 JavaScript 中第一步(分配内存)是如何工作的。
JavaScript 解放了开发者处理内存分配的责任——JavaScript 自己在声明 values 时就做了这件事。
var n = 374 ;
var s = 'sessionstack' ;
var o = {
a : 1 ,
b : null
};
var a = [1 , null , 'str' ];
function f (a ) {
return a + 3 ;
}
someElement.addEventListener('click' , function ( ) {
someElement.style.backgroundColor = 'blue' ;
}, false );
一些函数调用也会导致对象分配:
var d = new Date ();
var e = document .createElement('div' );
方法可以分配新值或对象:
var s1 = 'sessionstack' ;
var s2 = s1.substr(0 , 3 );
var a1 = ['str1' , 'str2' ];
var a2 = ['str3' , 'str4' ];
var a3 = a1.concat(a2);
JavaScript 中使用内存
基本上在 JavaScript 中使用内存的意思就是在内存在进行 读 和 写 。
这个操作可能是一个变量值的读取或写入,一个对象属性的读取或写入,甚至时向函数中传递参数。
当内存不再需要时释放它
大多数的内存管理问题发生在这个阶段。
这里最困难的任务就是确定内存何时就不再被需要了。它通常需要开发人员确定程序中哪里不再需要这样的内存,并释放它。
高级语言拥有垃圾回收器,它的职责就是追踪内存分配和使用情况,找到不再被使用的内存,然后自动地释放它。
不幸的是,这个过程只能得到一个近视的值,因为内存是否被需要是不可判定的(不能用算法求解)。
大多数垃圾回收器通过判断内存是否能够被再次访问来工作的,例如:指向它的所有变量都超出了作用域。然而,这只能得到一个近似值。因为在任何位置,存储器位置可能仍然具有指向其范围的变量,但是它可能将永远不会被再次访问了。
垃圾回收
由于事实上发现内存“不再被需要”是不可判定的,因此垃圾收集的通常解决方案都存在局限性。本节将介绍理解主要垃圾收集算法及其局限性的必要概念。
内存引用
垃圾回收算法依靠的主要概念就是引用 。
在内存管理的上下文中,如果前者具有对后者的访问权限(可以是隐式的或者显式的),则一个对象被成为引用另一个对象。例如:JavaScript 对象具有对其原型(隐式引用)及其属性值(显式引用)的引用。
在上下文中,“对象”的定义扩展到比常规 JavaScript 对象更广泛的东西,并且还包含了函数的作用域(或者全局的词法作用域)。
词法作用域定义了如何在嵌套函数中解析变量名称:即使父函数已返回,内部函数也可以包含父函数的范围。
引用计数——垃圾回收
这是最简单的垃圾回收算法。如果一个对象指向它的引用数为 0,那么它就应该被“垃圾回收”了。
看一下下面的代码:
var o1 = {
o2: {
x: 1
}
};
var o3 = o1;
o1 = 1 ;
var o4 = o3.o2;
o3 = '374' ;
o4 = null ;
循环依赖造成的问题
出现循环依赖就会产生限制。在以下的示例中,将创建两个对象并引用彼此,从而创建了一个循环。在函数调用之后,它们离开了作用域,因此它们实际上已经无用了,可以被释放了。然而,引用计数算法认为,由于两个对象中的每一个至少被引用了一次,所以也不能被垃圾回收。
function f () {
var o1 = {};
var o2 = {};
o1.p = o2;
o2.p = o1;
}
f();
标记扫描算法
为了确定一个对象是否被需要,这个算法会确定对象是否可以访问。
该算法由以下步骤组成:
垃圾回收器构建“roots”列表。Roots 通常是代码中保留引用的全局变量。在 JavaScript 中,“window” 对象可以作为 root 全局变量示例。
所有的 roots 被检查并标记为 active(即不是垃圾)。所有的 children 也被递归检查。从 root 能够到达的一切都不被认为是垃圾。
所有为被标记为 active 的内存可以被认为是垃圾了。收集器限制可以释放这些内存并将其返回到操作系统。
这个算法优于前一个,因为“一个对象零引用”会让这个对象不是可达的。反过来就不一定对了,因为存在循环引用。
截至 2012 年,所有现代浏览器都配备了 mark-and-sweep 机制的垃圾回收器。过去几年,JavaScript 垃圾回收(代数、增量、并行、并行垃圾收集)领域的所有改进都是对该算法(mark-and-sweep)的实现进行改进,但并没有对垃圾回收算法本身进行改进,其目标是确定一个对象是否可达。
在本文中,你可以阅读到更多关于垃圾回收的详细信息,当然也包含对其的优化。
循环引用不再是问题
在上面的第一个例子中,在函数调用后,两个对象不再被从全局对象可访问的东西所引用。因此,垃圾回收器将发现它们是不可达的。
尽管两个对象还是存在引用,但是他们从 root 出发已经是不可达的了。
反垃圾收集器的直接行为
虽然垃圾收集器很方便,但他们也有自己的一系列决策。其中一个是非确定论。换句话说,GCs 是不可预测的。你不能真正的知道回收是什么时候执行的。这意味着在某些情况下,程序使用的内存要比实际需要的还多。在另外一些情况下,如果程序特别敏感,那么一些短暂的暂停会显得特别明显。虽然不确定性意味着回收执行的时间不能被确定,但是大多数 GCs 的实现是共享模式——在分配内存期间执行回收遍历。如果没有分配执行,大多数 GCs 保持空闲状态。考虑一下情况:
相当大的一组分配被执行。
大多数元素(或全部)被标记为不可达(假设我们将指向不再需要的缓存的引用置空)。
不再进行分配。
在这种情况下,大多数 GC 将不会再运行任何进一步的收集。换句话说,即使有不可达的引用变量可以被收集,但是收集器并没有被声明。这些不是严格的内存泄漏,但仍然会导致使用内存比通常的内存要高。
什么是内存泄漏
实质上,内存泄漏可以被定义为应用程序不再需要的内存,但由于某种原因,内存不会返回到操作系统或可用内存池中。
编程语言支持多种管理内存的方法。然而,某块内存是否被使用实际上是一个不确定的问题。换句话说,只有开发人员可以清楚一块内存是否可以释放到操作系统又或者不该被释放。
某些编程语言提供了一些特性,帮助开发者处理这些事情。另外一些语言期望开发者能够完全自己去明确地控制内存。维基百科有关于手动和自动内存管理的好文章。
四种常见的 JavaScript 内存泄漏
1:Global variables
JavaScript 以有趣的方式处理未声明的变量:对未声明的变量的引用在全局对象内创建一个新变量。在浏览器中,全局对象就是 window。换种说法:
function foo (arg) {
bar = "some text" ;
}
等价于:
function foo (arg ) {
window .bar = "some text" ;
}
如果 bar 被假定为仅仅在函数 foo 的作用域范围内持有对变量的引用,但是你却忘记了使用 var 来声明它,那么就会创建一个意外的全局变量。
在这个例子中,泄漏一个简单的字符串不会有太大的伤害,但肯定会变得更糟的。
可以通过另一种方式创建意外的全局变量:
function foo () {
this .var1 = "potential accidental global" ;
}
foo();
为了防止这些错误的发生,可以在 JavaScript 文件开头添加 “use strict”,使用严格模式。这样在严格模式下解析 JavaScript 可以防止意外的全局变量。
即使我们讨论了如何预防意外全局变量的产生,但是仍然会有很多代码用显示的方式去使用全局变量。这些全局变量是无法进行垃圾回收的(除非将它们赋值为 null 或重新进行分配)。特别是用来临时存储和处理大量信息的全局变量非常值得关注。如果你必须使用全局变量来存储大量数据,那么,请确保在使用完之后,对其赋值为 null 或者重新分配。
2:被忘记的 Timers 或者 callbacks
在 JavaScript 中使用 setInterval 非常常见。
大多数库都会提供观察者或者其它工具来处理回调函数,在他们自己的实例变为不可达时,会让回调函数也变为不可达的。对于 setInterval,下面这样的代码是非常常见的:
var serverData = loadData();
setInterval(function ( ) {
var renderer = document .getElementById('renderer' );
if (renderer) {
renderer.innerHTML = JSON .stringify(serverData);
}
}, 5000 );
这个例子阐述着 timers 可能发生的情况:计时器会引用不再需要的节点或数据。
renderer 可能在将来会被移除,使得 interval 内的整个块都不再被需要。但是,interval handler 因为 interval 的存活,所以无法被回收(需要停止 interval,才能回收)。如果 interval handler 无法被回收,则它的依赖也不能被回收。这意味着 serverData——可能存储了大量数据,也不能被回收。在观察者模式下,重要的是在他们不再被需要的时候显式地去删除它们(或者让相关对象变为不可达)。
过去,特别是某些浏览器(IE6)无法管理循环引用。如今,大多数浏览器会在被观察的对象不可达时对 observer handlers 进行回收,即使 listener 没有被显式的移除。但是,明确地删除这些 observers 仍然是一个很好的做法。例如:
var element = document.getElementById('launch-button' );
var counter = 0 ;
function onClick(event) {
counter++;
element.innerHtml = 'text ' + counter;
}
element .addEventListener('click' , onClick);
// Do stuff
element .removeEventListener('click' , onClick);
element .parentNode.removeChild(element );
// Now when element goes out of scope,
// both element and onClick will be collected even in old browsers // that don't handle cycles well.
如今,现代浏览器(包括 IE 和 Edge)都使用的是现代垃圾回收算法,可以检测这些循环依赖并正确的处理它们。换句话说,让一个节点不可达,可以不必而在调用 removeEventListener。
框架和库,例如 jQuery ,在处理掉节点之前会删除 listeners (使用它们特定的 API)。这些由库的内部进了处理,确保泄漏不会发生。即使是在有问题的浏览器下运行,如。。。。IE6。
3:闭包
JavaScript 开发的一个关键方面就是闭包:一个可以访问外部(封闭)函数变量的内部函数。由于 JavaScript 运行时的实现细节,可以通过以下方式泄漏内存:
var theThing = null ;
var replaceThing = function ( ) {
var originalThing = theThing;
var unused = function ( ) {
if (originalThing)
console .log("hi" );
};
theThing = {
longStr : new Array (1000000 ).join('*' ),
someMethod : function ( ) {
console .log("message" );
}
};
};
setInterval(replaceThing, 1000 );
这个代码片段做了一件事:每次调用 replaceThing 时,theThing 都会获得一个新对象,它包含一个大的数组和一个新的闭包(someMethod)。同时,变量 unused 保留了一个拥有 originalThing 引用的闭包(前一次调用 theThing 赋值给了 originalThing)。已经有点混乱了吗?重要的是,一旦一个作用域被创建为闭包,那么它的父作用域将被共享 。
在这个例子中,创建闭包 someMethod 的作用域是于 unused 共享的。unused 拥有 originalThing 的引用。尽管 unused 从来都没有使用,但是 someMethod 能够通过 theThing 在 replaceThing 之外的作用域使用(例如全局范围)。并且由于 someMethod 和 unused 共享 闭包范围,unused 的引用将强制保持 originalThing 处于活动状态(两个闭包之间共享整个作用域)。这样防止了垃圾回收。 当这段代码重复执行时,可以观察到内存使用量的稳定增长。当 GC 运行时,也没有变小。实质上,引擎创建了一个闭包的链接列表(root 就是变量 theThing),并且这些闭包的作用域中每一个都有对大数组的间接引用,导致了相当大的内存泄漏,如下图:
这个问题由 Meteor 团队发现的,他们有一篇伟大的文章,详细描述了这个问题。
4:DOM 引用
有时候,在数据结构中存储 DOM 结构是有用的。假设要快速更新表中的几行内容。将每行 DOM 的引用存储在字典或数组中可能是有意义的。当这种情况发生时,就会保留同一 DOM 元素的两份引用:一个在 DOM 树种,另一个在字典中。如果将来某个时候你决定要删除这些行,则需要让两个引用都不可达。
var elements = {
button : document .getElementById('button' ),
image : document .getElementById('image' )
};
function doStuff ( ) {
elements.image.src = 'http://example.com/image_name.png' ;
}
function removeImage ( ) {
document .body.removeChild(document .getElementById('image' ));
}
还有一个额外的考虑,当涉及 DOM 树内部或叶子节点的引用时,必须考虑这一点。假设你在 JavaScript 代码中保留了对 table 特定单元格()的引用。有一天,你决定从 DOM 中删除该 table,但扔保留着对该单元格的引用。直观地来看,可以假设 GC 将收集除了该单元格之外所有的内容。实际上,这不会发生的:该单元格是该 table 的子节点,并且 children 保持着对它们 parents 的引用。也就是说,在 JavaScript 代码中对单元格的引用会导致整个表都保留在内存中的。保留 DOM 元素的引用时,需要仔细考虑。
==============================
原文地址:传送门 作者:Alexander Zlatkov
你可能感兴趣的:(前端工程师学习笔记,javascript)
移动端城市区县二级联动选择功能实现包
good2know
本文还有配套的精品资源,点击获取简介:本项目是一套为移动端设计的jQuery实现方案,用于简化用户在选择城市和区县时的流程。它包括所有必需文件:HTML、JavaScript、CSS及图片资源。通过动态更新下拉菜单选项,实现城市到区县的联动效果,支持数据异步加载。开发者可以轻松集成此功能到移动网站或应用,并可基于需求进行扩展和优化。1.jQuery移动端解决方案概述jQuery技术简介jQuery
用代码生成艺术字:设计个性化海报的秘密
本文围绕“用代码生成艺术字:设计个性化海报的秘密”展开,先概述代码生成艺术字在海报设计中的独特价值,接着介绍常用的代码工具(如HTML、CSS、JavaScript等),详细阐述从构思到实现的完整流程,包括字体样式设计、动态效果添加等,还分享了提升艺术字质感的技巧及实际案例。最后总结代码生成艺术字的优势,为设计师提供打造个性化海报的实用指南,助力提升海报设计的独特性与吸引力,符合搜索引擎SEO标准
为什么学习Web前端一定要掌握JavaScript?
web前端学习指南
为什么学习Web前端一定要掌握JavaScript?在前端的世界里,没有什么是JavaScript实现不了的,关于JS有一句话:凡是可以用JavaScript来写的应用,最终都会用JavaScript,JavaScript可运行在所有主要平台的所有主流浏览器上,也可运行在每一个主流操作系统的服务器端上。现如今我们在为网站写任何一个主要功能的时候都需要有懂能够用JavaScript写前端的开发人员。
Vue CSR 到 Nuxt 3 SSR 迁移:技术实现与问题解决实录
二倍速播放
前端 vue.js
1.迁移动机与技术选型1.1CSR架构的局限性基于Vue3和Vite构建的客户端渲染(CSR)单页应用(SPA)提供了良好的开发体验和用户交互流畅性。但是其核心局限在于:搜索引擎优化(SEO):初始HTML响应仅包含一个根div元素,实际内容由JavaScript在浏览器端动态生成。虽然主流搜索引擎(如Google)能够执行部分JavaScript,但其抓取效率和稳定性不如直接获取完整HTML。非
12. 什么是事件委托
yqcoder
前端面试-CSS css 面试
总结事件委托(EventDelegation)是JavaScript中一种重要的事件处理机制,它利用了事件冒泡的特性,将事件的处理程序绑定到父元素或祖先元素上,而不是直接绑定到具体的子元素上。什么是事件委托?事件冒泡:在DOM中,事件通常会从触发元素开始,然后逐级向上冒泡到其父元素、祖先元素,直到window对象。核心思想:事件委托的核心思想是利用事件冒泡机制,在父元素上监听事件,而不是在每个子元
关于前端的性能优化
性能优化主要涵盖了以下四个方面:(tip:仅代表个人总结,如有不当,还希望看到的大佬多多指示)减少网络请求:合并文件、使用CDN、启用缓存。优化资源加载:代码分割、懒加载、图片压缩。提升渲染性能:减少重绘回流、防抖节流、使用WebWorker。监控和迭代:定期使用工具检测性能,持续优化。一、网络层面优化减少HTTP请求合并文件:将多个CSS或JavaScript文件合并成一个,减少请求次数。使用C
时间组件库Day.js那些事
前端小白花
javascript 开发语言 ecmascript
一、简介1.什么是Day.jsDay.js是一个轻量级,易于使用的JavaScript日期库,提供了强大的日期和时间处理功能,与Moment.js的API设计相似,但具有更高的性能和更小的体积。Day.js官网https://day.js.org/docs/zh-CN/installation/installation2.优势a.特点轻量级:Dayjs的压缩后大小只有2KB左右,远小于Moment
JavaScript正则表达式去除括号但保留内容与去除括号与内容
Selicens
javascript 正则表达式
项目上碰到一个需求,是取多个递增文件的文件名,类似于test(1).txt、test(2).txt,但是不需要括号,只要test1、test2这种格式,最开始想到的办法就是js里的replace替换,先上一个比较笨但是也能实现效果的例子letname="test(1).txt"letdata=name.split('.')[0].replace('(','').replace(')','')con
网络安全第14集
不灭锦鲤
web安全 安全
前言:小迪安全14集,这集重点内容:0、什么是js渗透测试?在javascript中也存在变量和函数,存在可控变量和函数就有可能存在在漏洞,js开发的web应用和php、java开发的区别是,js能看得到的源代码,php看不到,但是风险就是未授权访问、配置信息泄露(加密算法、key秘钥等),源代码看得到,存在更多的url泄露,从而可能会出现未授权访问,从url,前提:web应用可以采用前端语言或后
25年不倒的“犀牛书“:为什么《JavaScript权威指南第7版》仍是程序员的案头圣经?
阿蒙Armon
javascript 开发语言 ecmascript
25年不倒的"犀牛书":为什么《JavaScript权威指南第7版》仍是程序员的案头圣经?当一本技术书能连续畅销25年,历经7次迭代仍稳坐领域第一梯队,它必然藏着超越时代的硬实力。《JavaScript权威指南(原书第7版)》就是这样一部传奇——豆瓣9.4分的封神之作,程序员口中的"犀牛书",从网景时代到ES2020,它始终是JavaScript开发者的终极参考书。如果你还在为原型链、闭包、异步编
什么是JSON,如何与Java对象转化
doublez234
java json spring spring boot
JSON概念JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。它易于人阅读和编写,同时也易于机器解析和生成。JSON基于JavaScript(ECMAScript(欧洲计算机协会制定的js规范))编程语言的一个子集,但它是一种独立于语言的数据格式,被广泛应用于各种编程语言和平台之间的数据交换。JSON的主要特点:轻量级:JSON格式非常简洁,只包含必要的数据信
APP开发入门:了解主流的编程语言
agi大模型
Python 职业与职场 程序员 开发语言 数据分析 编程语言
前言在过去的几年里,有许多程序员开始学习和使用编程语言。这其中包括C、C++、Java和Python。尽管有许多语言可供选择,但大多数程序员都会选择最容易学习的编程语言。如今,有很多编程语言供选择。程序员们在学习这些语言时可以自由地选择他们喜欢的方式,因为他们的目标是构建任何软件,而不仅仅是创建一个应用程序。你可以在Linux上学习C/C++、Java、Python、C#或JavaScript,你
探秘CommonJS:Node.js模块化核心解析
CommonJS是JavaScript的模块化规范,主要应用于服务器端环境(尤其是Node.js),其核心目标是解决代码组织、依赖管理和作用域隔离问题。以下是其核心要点:一、核心特性同步加载模块通过require()同步加载并执行,后续代码需等待模块加载完成后执行,适用于I/O快速的服务器环境(如本地文件读取)。作用域隔离每个文件视为独立模块,模块内定义的变量、函数默认私有(不污染全局作用域),仅
壹脉销客AI电子名片源码核心架构
为什么选择源码部署AI电子名片?在数字化转型浪潮中,越来越多的企业意识到拥有自主可控的电子名片系统的重要性。源码部署相比SaaS服务具有三大核心优势:数据完全自主-客户信息存储在企业自有服务器深度定制自由-可根据业务需求二次开发长期成本优化-一次部署永久使用壹脉销客AI电子名片源码核心架构壹脉销客提供的企业级电子名片解决方案采用前后端分离架构:前端技术栈(小程序端)javascript//小程序a
vue 进入一个页面,然后离开这个页面他就重新加载
Java&Develop
vue vue
vue进入一个页面,然后离开这个页面他就重新加载这个代码导致的注释即可window.location.reload();window.location.reload()是JavaScript中的一个方法,用于强制刷新当前页面(重新加载页面内容)。其作用类似于用户手动点击浏览器的刷新按钮,但可以通过代码精确触发。核心作用:刷新页面重新加载当前显示的文档(即重新请求当前URL的资源)。可选参数控制缓存
[python][flask]flask静态资源
在Flask中,静态资源(如图片、CSS文件、JavaScript文件等)通常存储在项目的static文件夹中。Flask会自动为静态资源提供服务,使得你可以通过URL访问这些文件。以下是关于Flask中静态资源的使用方法和一些高级配置。1.默认静态文件夹Flask默认会将项目根目录下的static文件夹作为静态资源目录。例如,如果你的项目结构如下:my_flask_app/│├──app.py├
JavaScript对象与Math对象完全指南
hui函数
Javascript javascript 前端 开发语言
JavaScript对象与Math对象完全指南对象基础概念与操作对象是什么?数据集合:包含相关数据和功能的容器结构组成:属性:描述对象特征的变量(名词性)方法:对象可执行的操作(动词性,本质是函数)对象创建与访问//创建对象letperson={ //属性 name:"张三", age:28, profession:"软件工程师", //方法 introduce(){ return`大家好,我
深入理解JavaScript作用域与编译过程
君子心理
作用域 编译 JavaScript 变量提升 闭包
背景简介在编程领域,作用域和编译过程是理解语言机制的关键概念。JavaScript作为一种广泛使用的语言,其作用域规则和编译机制尤其值得我们深入探讨。本文将基于《你不懂JS》系列书籍中的相关内容,解析JavaScript的作用域系统、函数闭包以及编译过程,帮助读者获得更深层次的理解。作用域是什么?在JavaScript中,作用域定义了变量和函数的可访问范围。编写程序时,我们会频繁使用变量来存储和操
掌握JavaScript对象与函数:深入理解原型与作用域
土城三富
JavaScript 对象 原型链 函数 作用域
掌握JavaScript对象与函数:深入理解原型与作用域背景简介在探索JavaScript的世界时,我们经常遇到对象和函数这两个核心概念。对象是JavaScript中最为基本的结构之一,而函数则是实现代码复用、封装和模块化的主要工具。本文将基于给定的书籍章节内容,深入探讨对象的更新机制、原型继承以及函数的多样性及其调用模式,同时分享对全局变量使用的思考。更新对象在JavaScript中,对象的属性
JavaScript函数使用模式与作用域的深入解析
JavaScript函数使用模式与作用域的深入解析JavaScript作为一门灵活且功能强大的编程语言,其函数的使用和作用域的特性是学习和开发中的关键点。本篇博客将深入解析JavaScript函数的几种使用模式,以及作用域的重要概念。构造器模式在JavaScript中,函数可以作为构造器(constructor)使用,当用new关键字调用时,函数会返回一个新对象。为了区分构造器函数和其他普通函数,
掌握JavaScript函数和作用域:提高代码复用性
捕风捉你
javascript 开发语言 ecmascript
在JavaScript编程中,函数是一个核心概念,它不仅能帮助我们将代码组织得更加清晰,还能提高代码的复用性。理解函数的定义与调用、掌握作用域的概念,对于编写高效和可维护的代码至关重要。本文将通过创建一个计时器应用的案例,帮助你全面掌握JavaScript中的函数和作用域知识。任务目标通过本教程,你将学习并掌握:函数的声明与调用函数表达式的使用作用域的概念及其在函数中的应用闭包的原理及实践学习内容
JavaScript 函数与作用域
前端人类学
JavaScript - 行为 javascript 函数 作用域 闭包 递归 作用域链
Hi,我是布兰妮甜!JavaScript是一种动态类型语言,它支持面向对象编程和函数式编程。函数是JavaScript的核心组成部分之一,而作用域则决定了变量的可见性和生命周期。本文将详细介绍JavaScript中的函数定义、调用、参数传递、闭包、递归以及作用域链的概念。文章目录一、函数基础二、作用域基础三、闭包四、递归五、作用域链六、总结一、函数基础1.定义函数函数声明函数可以通过函数声明的方式
深入理解作用域【JavaScript】
陆仟
Web前端开发 javascript
一、作用域的内部原理JavaScript的作用域机制是理解变量如何被访问和存储的重要概念。下面详细介绍作用域的内部原理,包括编译、执行、查询、嵌套和异常处理这五个步骤。1.编译在JavaScript的执行过程中,首要的步骤是编译。尽管JavaScript是解释性语言,但现代JavaScript引擎(如V8)在执行代码前会先进行编译。编译阶段主要完成以下几项工作:词法分析:将源代码分解成语法单元(t
即便你已经在浏览器中启用了 JavaScript有时网页依然可能出现功能失效、内容加载不完整或按钮点击无反应等问题。这些问题通常由 JavaScript 冲突
即便你已经在浏览器中启用了JavaScript有时网页依然可能出现功能失效、内容加载不完整或按钮点击无反应等问题。这些问题通常由JavaScript冲突、浏览器设置不当或插件干扰等原因引起。作为HostEase的技术人员我将为你提供一系列简单有效的JavaScript故障排除方法帮助你快速定位并解决这些问题。禁用可能干扰JavaScript的浏览器扩展,广告拦截器,安全插件或某些脚本管理器可能会干
技术文章大纲:Anaconda插件开发挑战赛引言介绍Anaconda在数据科学和PythonUH开发中的重要性
aadwje
eclipse ide
即便你已经在浏览器中启用了JavaScript有时网页依然可能出现功能失效、内容加载不完整或按钮点击无反应等问题。这些问题通常由JavaScript冲突、浏览器设置不当或插件干扰等原因引起。作为HostEase的技术人员我将为你提供一系列简单有效的JavaScript故障排除方法帮助你快速定位并解决这些问题。禁用可能干扰JavaScript的浏览器扩展,广告拦截器,安全插件或某些脚本管理器可能会干
深入分析 Node.js 的 V8 引擎如何在内部处理 JavaScript 代码,包括内存管理和垃圾回收机制。
海派程序猿
node.js javascript 开发语言
各位观众老爷们,晚上好!今天咱们就来聊聊Node.js的大心脏——V8引擎,看看它到底是怎么把咱们写的JavaScript代码给“消化”掉的。别害怕,今天咱不搞那些生涩难懂的学院派理论,尽量用大白话,外加一些“栗子”,保证让你听得津津有味。V8引擎:JavaScript的超级翻译官首先,简单介绍一下V8。V8是Google开发的高性能JavaScript和WebAssembly引擎,用C++写的。
Tailwind CSS 响应式设计实战指南
qcidyu
用户体验 代码优化 移动优先 网站布局 前端开发 Tailwind CSS 响应式设计
title:TailwindCSS响应式设计实战指南date:2024/6/13updated:2024/6/13author:cmdragonexcerpt:这篇文章介绍了如何运用TailwindCSS框架创建响应式网页设计,涵盖博客、电商网站及企业官网的布局实例,包括头部导航、内容区域、侧边栏、页脚及轮播图等组件的响应式实现。同时,探讨了与JavaScript框架集成、CSS预处理器配合、设计
JavaScript核心概念全解析
目录1.作用域(1)局部作用域(2)全局作用域2.垃圾回收(1)引用计数法(2)标记清除法3.闭包(1)作用(2)风险4.变量提升(1)var(2)let和const(3)const5.函数提升(1)函数声明(2)函数表达式6.函数参数(1)动态参数(2)剩余参数(3)展开运算符7.必须加分号的两种情况(1)立即执行函数(2)使用数组的时候8.箭头函数(1)特点9.Symbol10.生成器函数11
IntelliJ IDEA 高效开发指南:从基础操作到高级技巧
zqmgx13291
intellij-idea java ide
一、IDEA概述与环境配置1.1IDEA的核心优势智能代码辅助:基于上下文的代码补全(Ctrl+Space)、方法参数提示、错误实时检测全栈开发支持:内置Java/Python/JavaScript等20+语言支持,框架集成(SpringBoot/Vue/React)工具链集成:版本控制(Git/SVN)、数据库(MySQL/PostgreSQL)、容器(Docker/K8s)一站式开发性能优化:
【前端】JavaScript 的事件循环 (Event Loop)
不懂可否
前端 前端 javascript 开发语言
JavaScript的事件循环(EventLoop)是其实现异步编程的核心机制,即使JS是单线程语言,它也能高效处理I/O、网络请求、计时器等非阻塞操作。以下是其工作原理的精要解析:核心概念单线程执行JS引擎(如V8)只能顺序执行一个任务。异步行为需要靠宿主环境(浏览器/Node.js)提供的事件循环调度。任务队列(TaskQueue)所有异步操作完成后对应的回调函数会进入队列等待执行。队列类型包
Java 并发包之线程池和原子计数
lijingyao8206
Java计数 ThreadPool 并发包 java线程池
对于大数据量关联的业务处理逻辑,比较直接的想法就是用JDK提供的并发包去解决多线程情况下的业务数据处理。线程池可以提供很好的管理线程的方式,并且可以提高线程利用率,并发包中的原子计数在多线程的情况下可以让我们避免去写一些同步代码。
这里就先把jdk并发包中的线程池处理器ThreadPoolExecutor 以原子计数类AomicInteger 和倒数计时锁C
java编程思想 抽象类和接口
百合不是茶
java 抽象类 接口
接口c++对接口和内部类只有简介的支持,但在java中有队这些类的直接支持
1 ,抽象类 : 如果一个类包含一个或多个抽象方法,该类必须限定为抽象类(否者编译器报错)
抽象方法 : 在方法中仅有声明而没有方法体
package com.wj.Interface;
[房地产与大数据]房地产数据挖掘系统
comsci
数据挖掘
随着一个关键核心技术的突破,我们已经是独立自主的开发某些先进模块,但是要完全实现,还需要一定的时间...
所以,除了代码工作以外,我们还需要关心一下非技术领域的事件..比如说房地产
&nb
数组队列总结
沐刃青蛟
数组队列
数组队列是一种大小可以改变,类型没有定死的类似数组的工具。不过与数组相比,它更具有灵活性。因为它不但不用担心越界问题,而且因为泛型(类似c++中模板的东西)的存在而支持各种类型。
以下是数组队列的功能实现代码:
import List.Student;
public class
Oracle存储过程无法编译的解决方法
IT独行者
oracle 存储过程
今天同事修改Oracle存储过程又导致2个过程无法被编译,流程规范上的东西,Dave 这里不多说,看看怎么解决问题。
1. 查看无效对象
XEZF@xezf(qs-xezf-db1)> select object_name,object_type,status from all_objects where status='IN
重装系统之后oracle恢复
文强chu
oracle
前几天正在使用电脑,没有暂停oracle的各种服务。
突然win8.1系统奔溃,无法修复,开机时系统 提示正在搜集错误信息,然后再开机,再提示的无限循环中。
无耐我拿出系统u盘 准备重装系统,没想到竟然无法从u盘引导成功。
晚上到外面早了一家修电脑店,让人家给装了个系统,并且那哥们在我没反应过来的时候,
直接把我的c盘给格式化了 并且清理了注册表,再装系统。
然后的结果就是我的oracl
python学习二( 一些基础语法)
小桔子
pthon 基础语法
紧接着把!昨天没看继续看django 官方教程,学了下python的基本语法 与c类语言还是有些小差别:
1.ptyhon的源文件以UTF-8编码格式
2.
/ 除 结果浮点型
// 除 结果整形
% 除 取余数
* 乘
** 乘方 eg 5**2 结果是5的2次方25
_&
svn 常用命令
aichenglong
SVN 版本回退
1 svn回退版本
1)在window中选择log,根据想要回退的内容,选择revert this version或revert chanages from this version
两者的区别:
revert this version:表示回退到当前版本(该版本后的版本全部作废)
revert chanages from this versio
某小公司面试归来
alafqq
面试
先填单子,还要写笔试题,我以时间为急,拒绝了它。。时间宝贵。
老拿这些对付毕业生的东东来吓唬我。。
面试官很刁难,问了几个问题,记录下;
1,包的范围。。。public,private,protect. --悲剧了
2,hashcode方法和equals方法的区别。谁覆盖谁.结果,他说我说反了。
3,最恶心的一道题,抽象类继承抽象类吗?(察,一般它都是被继承的啊)
4,stru
动态数组的存储速度比较 集合框架
百合不是茶
集合框架
集合框架:
自定义数据结构(增删改查等)
package 数组;
/**
* 创建动态数组
* @author 百合
*
*/
public class ArrayDemo{
//定义一个数组来存放数据
String[] src = new String[0];
/**
* 增加元素加入容器
* @param s要加入容器
用JS实现一个JS对象,对象里有两个属性一个方法
bijian1013
js对象
<html>
<head>
</head>
<body>
用js代码实现一个js对象,对象里有两个属性,一个方法
</body>
<script>
var obj={a:'1234567',b:'bbbbbbbbbb',c:function(x){
探索JUnit4扩展:使用Rule
bijian1013
java 单元测试 JUnit Rule
在上一篇文章中,讨论了使用Runner扩展JUnit4的方式,即直接修改Test Runner的实现(BlockJUnit4ClassRunner)。但这种方法显然不便于灵活地添加或删除扩展功能。下面将使用JUnit4.7才开始引入的扩展方式——Rule来实现相同的扩展功能。
1. Rule
&n
[Gson一]非泛型POJO对象的反序列化
bit1129
POJO
当要将JSON数据串反序列化自身为非泛型的POJO时,使用Gson.fromJson(String, Class)方法。自身为非泛型的POJO的包括两种:
1. POJO对象不包含任何泛型的字段
2. POJO对象包含泛型字段,例如泛型集合或者泛型类
Data类 a.不是泛型类, b.Data中的集合List和Map都是泛型的 c.Data中不包含其它的POJO
 
【Kakfa五】Kafka Producer和Consumer基本使用
bit1129
kafka
0.Kafka服务器的配置
一个Broker,
一个Topic
Topic中只有一个Partition() 1. Producer:
package kafka.examples.producers;
import kafka.producer.KeyedMessage;
import kafka.javaapi.producer.Producer;
impor
lsyncd实时同步搭建指南——取代rsync+inotify
ronin47
1. 几大实时同步工具比较 1.1 inotify + rsync
最近一直在寻求生产服务服务器上的同步替代方案,原先使用的是 inotify + rsync,但随着文件数量的增大到100W+,目录下的文件列表就达20M,在网络状况不佳或者限速的情况下,变更的文件可能10来个才几M,却因此要发送的文件列表就达20M,严重减低的带宽的使用效率以及同步效率;更为要紧的是,加入inotify
java-9. 判断整数序列是不是二元查找树的后序遍历结果
bylijinnan
java
public class IsBinTreePostTraverse{
static boolean isBSTPostOrder(int[] a){
if(a==null){
return false;
}
/*1.只有一个结点时,肯定是查找树
*2.只有两个结点时,肯定是查找树。例如{5,6}对应的BST是 6 {6,5}对应的BST是
MySQL的sum函数返回的类型
bylijinnan
java spring sql mysql jdbc
今天项目切换数据库时,出错
访问数据库的代码大概是这样:
String sql = "select sum(number) as sumNumberOfOneDay from tableName";
List<Map> rows = getJdbcTemplate().queryForList(sql);
for (Map row : rows
java设计模式之单例模式
chicony
java设计模式
在阎宏博士的《JAVA与模式》一书中开头是这样描述单例模式的:
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 单例模式的结构
单例模式的特点:
单例类只能有一个实例。
单例类必须自己创建自己的唯一实例。
单例类必须给所有其他对象提供这一实例。
饿汉式单例类
publ
javascript取当月最后一天
ctrain
JavaScript
<!--javascript取当月最后一天-->
<script language=javascript>
var current = new Date();
var year = current.getYear();
var month = current.getMonth();
showMonthLastDay(year, mont
linux tune2fs命令详解
daizj
linux tune2fs 查看系统文件块信息
一.简介:
tune2fs是调整和查看ext2/ext3文件系统的文件系统参数,Windows下面如果出现意外断电死机情况,下次开机一般都会出现系统自检。Linux系统下面也有文件系统自检,而且是可以通过tune2fs命令,自行定义自检周期及方式。
二.用法:
Usage: tune2fs [-c max_mounts_count] [-e errors_behavior] [-g grou
做有中国特色的程序员
dcj3sjt126com
程序员
从出版业说起 网络作品排到靠前的,都不会太难看,一般人不爱看某部作品也是因为不喜欢这个类型,而此人也不会全不喜欢这些网络作品。究其原因,是因为网络作品都是让人先白看的,看的好了才出了头。而纸质作品就不一定了,排行榜靠前的,有好作品,也有垃圾。 许多大牛都是写了博客,后来出了书。这些书也都不次,可能有人让为不好,是因为技术书不像小说,小说在读故事,技术书是在学知识或温习知识,有
Android:TextView属性大全
dcj3sjt126com
textview
android:autoLink 设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web/email/phone/map/all) android:autoText 如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输
tomcat虚拟目录安装及其配置
eksliang
tomcat配置说明 tomca部署web应用 tomcat虚拟目录安装
转载请出自出处:http://eksliang.iteye.com/blog/2097184
1.-------------------------------------------tomcat 目录结构
config:存放tomcat的配置文件
temp :存放tomcat跑起来后存放临时文件用的
work : 当第一次访问应用中的jsp
浅谈:APP有哪些常被黑客利用的安全漏洞
gg163
APP
首先,说到APP的安全漏洞,身为程序猿的大家应该不陌生;如果抛开安卓自身开源的问题的话,其主要产生的原因就是开发过程中疏忽或者代码不严谨引起的。但这些责任也不能怪在程序猿头上,有时会因为BOSS时间催得紧等很多可观原因。由国内移动应用安全检测团队爱内测(ineice.com)的CTO给我们浅谈关于Android 系统的开源设计以及生态环境。
1. 应用反编译漏洞:APK 包非常容易被反编译成可读
C#根据网址生成静态页面
hvt
Web .net C# asp.net hovertree
HoverTree开源项目中HoverTreeWeb.HVTPanel的Index.aspx文件是后台管理的首页。包含生成留言板首页,以及显示用户名,退出等功能。根据网址生成页面的方法:
bool CreateHtmlFile(string url, string path)
{
//http://keleyi.com/a/bjae/3d10wfax.htm
stri
SVG 教程 (一)
天梯梦
svg
SVG 简介
SVG 是使用 XML 来描述二维图形和绘图程序的语言。 学习之前应具备的基础知识:
继续学习之前,你应该对以下内容有基本的了解:
HTML
XML 基础
如果希望首先学习这些内容,请在本站的首页选择相应的教程。 什么是SVG?
SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
SVG 用来定义用于网络的基于矢量
一个简单的java栈
luyulong
java 数据结构 栈
public class MyStack {
private long[] arr;
private int top;
public MyStack() {
arr = new long[10];
top = -1;
}
public MyStack(int maxsize) {
arr = new long[maxsize];
top
基础数据结构和算法八:Binary search
sunwinner
Algorithm Binary search
Binary search needs an ordered array so that it can use array indexing to dramatically reduce the number of compares required for each search, using the classic and venerable binary search algori
12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!
刘星宇
c 面试
12个C语言面试题,涉及指针、进程、运算、结构体、函数、内存,看看你能做出几个!
1.gets()函数
问:请找出下面代码里的问题:
#include<stdio.h>
int main(void)
{
char buff[10];
memset(buff,0,sizeof(buff));
ITeye 7月技术图书有奖试读获奖名单公布
ITeye管理员
活动 ITeye 试读
ITeye携手人民邮电出版社图灵教育共同举办的7月技术图书有奖试读活动已圆满结束,非常感谢广大用户对本次活动的关注与参与。
7月试读活动回顾:
http://webmaster.iteye.com/blog/2092746
本次技术图书试读活动的优秀奖获奖名单及相应作品如下(优秀文章有很多,但名额有限,没获奖并不代表不优秀):
《Java性能优化权威指南》