JavaScript 加载顺序

Javascript 加载顺序 Javascript加载顺序 http://www.benben.cc/blog/?p=9 最近经常看到别人提及Javascript脚本的加载顺序,看完之后虽略有所悟,但古人云"纸上得来终觉浅,绝知此事要躬行。“这句话云的好,所以我决定亲自测试一下,看看浏览器究竟是怎么加载脚本的。 先看html部分的代码: <script>alert("我是html根节点之外的内部脚本");</script> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>js</title> <style type="text/css">body {margin:0;padding:0;}</style> <script>alert("我是头部header里的内部脚本");</script> <script src="header.js"></script> <script src="outer.js"></script> </head> <body> <script>alert("我是页面body里的内部脚本");</script> <script src="body.js"></script> <input type="button" value="绑定事件" onclick="javascript:alert('我是body中的按钮,这是我自己绑定的事件');"></input> </body> </html> <script>alert("我是html根节点之外的内部脚本");</script> 再看header.js中的代码: 1 alert("我是header中src外部引用的脚本"); 接着是outer.js中的代码: document.write('<script type="text/javascript">'); document.write('alert("我是header中通过外部通过document.write生成的脚本")'); //document.write('<script src="outerouter.js"></script>'); document.write('</script>'); 最后是body.js中的代码 1 alert("我是body中src外部引用的脚本"); 代码的输出顺序如下: alert("我是html根节点之外的内部脚本"); alert("我是头部header里的内部脚本"); alert("我是header中src外部引用的脚本"); alert("我是header中通过外部通过document.write生成的脚本"); alert("我是页面body里的内部脚本"); alert("我是body中src外部引用的脚本"); alert("我是html根节点之外的内部脚本"); 最后只有点击按钮才会触发alert(‘我是body中的按钮,这是我自己绑定的事件’); 刚开始看完代码后你觉得加载顺序如何呢?其实很简单,浏览器加载的时候完全是按照自上而下顺序加载的,遇到外部引用就暂时跳出到外部js中执行,执行完毕后返回跳出的位置继续向下执行,而且经测试可以看到,按钮是在body.js执行完毕后才显示在页面中的,这也证实了浏览器是顺序加载的。 这里需要说明两点: 浏览器根节点之外是不允许有任何元素的,在这里我们只是为了判断加载顺序才写了不符合规矩的代码,这一点可以在chrome的调试中看到报错。 outer.js中通过document.write再次引用外部js的那一行我已经做了注释,虽然此方法有许多人证实可行,但是在我的环境下会报脚本错误,而且这样做会引起浏览器加载顺序的不兼容 (详情可见: Javascript加载顺序的BUG) ,因此在实际应用中若非迫不得已还是少用为妙。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 javascript-load-order.md;title 改为「JavaScript 加载顺序」;url 改为 javascript-load-order;旧 url 加入 aliases 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 21216-02-21 · Updated 9096-10-09 · 1 min · 88 words · -

Javascript 重定向 window.location.href / replace / reload()

Javascript 重定向 window.location.href / replace / reload() location.href,可以点击浏览器的后退按钮返回本页。 location.assign(URL) assign() 方法可加载一个新的文档。效果与location.href相当。 location.reload(force) 如果该方法没有规定参数,或者参数是 false,它就会用 HTTP 头 If-Modified-Since 来检测服务器上的文档是否已改变。如果文档已改变,reload() 会再次下载该文档。如果文档未改变,则该方法将从缓存中装载文档。这与用户单击浏览器的刷新按钮的效果是完全一样的。 如果把该方法的参数设置为 true,那么无论文档的最后修改日期是什么,它都会绕过缓存,从服务器上重新下载该文档。这与用户在单击浏览器的刷新按钮时按住 Shift 健的效果是完全一样。 location.replace(newURL) 不能点击浏览区的后退按钮返回本页。 将地址替换成新url,该方法通过指定URL替换当前缓存在历史里 (客户端) 的项目, 因此当使用replace方法之后,你不能通过"前进"和"后 退"来访问已经被替换的URL,这个特点对于做一些过渡页面非常有用! replace() 方法不会在 History 对象中生成一个新的记录。当使用该方法时,新的 URL 将覆盖 History 对象中的当前记录。 http://jun1986.iteye.com/blog/1176909 一、最外层top跳转页面,适合用于iframe框架集 top.window.location.href("${pageContext.request.contextPath}/Login_goBack"); ============================================================================================ 二、window.location.href和window.location.replace的区别 1.window.location.href=“url”: 改变url地址; 三、强制页面刷新 1.window.location.reload(): 强制刷新页面,从服务器重新请求! ============================================================================================ 四、window.location.reload();页面实现跳转和刷新 1 history.go(0) 2 location.reload() 3 location=location 4 location.assign(location) 5 document.execCommand('Refresh') 6 window.navigate(location) 7 location.replace(location) 8 document.URL=location.href 这几个都可以刷新 window.location.reload();刷新 ...

Created 3036-03-03 · Updated 9096-10-09 · 1 min · 156 words · -

JS 正则标志 /g /i /m 的用法

js正则标志/g /i /m的用法 正则的思想都是一样的,但是具体的写法会有所不同,在这里提到的/g,/i,/m在其他的地方也许就不能用了。 一,js正则标志/g,/i,/m说明 1,/g 表示该表达式将用来在输入字符串中查找所有可能的匹配,返回的结果可以是多个。如果不加/g最多只会匹配一个 2,/i 表示匹配的时候不区分大小写 3,/m 表示多行匹配,什么是多行匹配呢?就是匹配换行符两端的潜在匹配。影响正则中的^$符号 二,实例说明 1,/g的用法 查看复制打印? <script type="text/javascript"> str = "tankZHang (231144)"+ "tank ying (155445)"; res = str.match(/tank/); //没有加/g alert(res); //显示一个tank res = str.match(/tank/g); //加了/g alert(res); //显示为tank,tank </script> 2,/i的用法 查看复制打印? <script type="text/javascript"> str = "tankZHang (231144)"+ "tank ying (155445)"; res = str.match(/zhang/); alert(res); //显示为null res = str.match(/zhang/i); //加了/i alert(res); //显示为ZHang </script> 3,/m的用法 查看复制打印? <script type="text/javascript"> var p = /$/mg; var s = '1\n2\n3\n4\n5\n6'; alert(p.test(s)); //显示为true alert(RegExp.rightContext.replace(/\x0A/g, '\\a')); //显示\a2\a3\a4\a5\a6 alert(RegExp.leftContext); //显示为竖的2345 alert(RegExp.rightContext); //显示为6 var p = /$/g; var s = '1\n2\n3\n4\n5\n6'; alert(p.test(s)); //显示为true alert(RegExp.rightContext.replace(/\x0A/g, '\\a')); //什么都不显示 alert(RegExp.leftContext); //显示为竖的123456 alert(RegExp.rightContext); //什么都不显示 var p = /^/mg; var s = '1\n2\n3\n4\n5\n6'; alert(p.test(s)); //显示为true alert(RegExp.rightContext.replace(/\x0A/g, '\\a')); //显示为1\a2\a3\a4\a5\a6 alert(RegExp.leftContext); //显示为竖的12345 alert(RegExp.rightContext); //显示为6 </script> //从上例中可以看出/m影响的^$的分割方式 上面说的三个例子,/i,/g,/m分开来说的,可以排列组合使用的。个人觉得/m没有多大用处 http://blog.51yip.com/jsjquery/1076.html javascript 密码 正则 let testPassword = /^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)(?=.*?[!@#$%^&;*()_=+\-])[a-zA-Z\d!@#$%^&;*()_=+\-]*$/; //判断输入格式 if(testPassword.test(this.passwordText)){ ...密码匹配成功 }else { ...密码匹配失败 } ———————————————— 版权声明:本文为CSDN博主「weixin_42553179」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_42553179/article/details/103045970 ...

Created 10106-03-10 · Updated 9096-10-09 · 1 min · 165 words · -

javascript unit test

javascript unit test http://blog.sina.com.cn/s/blog_6768f2290100ubw5.html 最近由于工作和个人兴趣的关系,有幸研究了一下javascript的unit test,市面上常见且比较易用的javascript的unit test的framework有三个: jsunit, qunit和yuitest,虽然出处不同,但是本质上,使用方法都大同小异。 jsunit: http://www.jsunit.net/ 最早开发自2001年,是第一个实用的javascript的unit test framework (那时候TDD还远未流行) ,其完全遵循junit的xunit pattern, 有setup, teardown, 有testsuit概念,还有若干种assert方法,不过因为其诞生早,对非同步的ajax测试支持不够,因而有市场占有率渐低的趋势。 qunit: http://docs.jquery.com/Qunit 个人极其欣赏的一个framework,隶属于大名鼎鼎的jquery,但是又无需依赖于jquery的库可单独运行, 方法轻量易学,且具有异步测试的功能。可惜在公司没有被官方支持,只能自己玩。 yui test: http://developer.yahoo.com/yui/yuitest/ 著名的yahoo web js toolkit library中的ut子项目,使用方法和qunit极其相似,也具有异步测试功能,在本人公司被官方支持,最大的缺点是使用时要调用其他诸多的yui模块用来显示结果,不够独立。 以下以qunit为例子,介绍这些unit test framework的使用方法: 1 ) 下载qunit的测试驱动程序js文件和对应显示结果用的css文件 (分别为qunit.js 和qunit.css ) 2 ) 将这两个文件保存在某个目录,并在同一目录建立一个简单的html文件,包含该两个文件以及jquery.js 3 ) 将我们需要测试的js代码的文件也包含入该简单html中(该例中为mycode.js)。 4 ) 将我们要测试的js代码的依赖库也加入该html中(如ExtJS或者其他库) 5 ) 在html中添加script的测试代码 (test suit和assert部分) 6 ) 在浏览器中载入该html文件,页面会自动显示运行结果。 值得一提的是,网上有qunit-CLI的项目,其用rhino解释器来代替浏览器做unit test js的运行环境,提高了测试的效率,有兴趣的朋友可以去google搜索看看。 代码如下: mycode.js function (a, b) { return a + b; } test.html <html> <head> <script src="http://code.jquery.com/jquery-latest.js"></script> <script type="text/javascript" src="qunit.js"></script> <!-- js to be tested --> <script type="text/javascript" src="mycode.js"></script> <!-- unit test part --> <script> $(document).ready(function(){ test("a basic test example", function() { var sum = add (1 + 1); equal( sum, "2", "We expect value to be 2" ); }); }); </script> </head> <body> QUnit example test markup, will be hidden </ 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 25256-08-25 · Updated 9096-10-09 · 1 min · 148 words · -

Disable Browser Back Button 禁用浏览器的后退按钮

禁用浏览器的后退按钮 浏览器的后退按钮是AJAX开发时候最让人头疼的一块,有的时候遇到这种问题,实在没有结果的情况下我们只能交给用户去学习适应,本文从缓存、JS跳转等方面阐述了如何绕过此问题,还是很值得我们借鉴的,虽然解释语言是ASP,但估计不会造成理解障碍。如果各位有什么其它的方法,不妨拿出来分享一下: ) 浏览器的后退按钮使得我们能够方便地返回以前访问过的页面,它无疑非常有用。但有时候我们不得不关闭这个功能,以防止用户打乱预定的页面访问次序。本文介绍网络上可找到的各种禁用浏览器后退按钮方案,分析它们各自的优缺点和适用场合。 一、概述 曾经有许多人问起,“怎样才能’禁用’浏览器的后退按钮?",或者"怎样才能防止用户点击后退按钮返回以前浏览过的页面?“在ASP论坛上,这个问题也是问得最多的问题之一。遗憾的是,答案非常简单: 我们无法禁用浏览器的后退按钮。 起先我对于居然有人想要禁用浏览器的后退按钮感到不可思议。后来,看到竟然有那么多的人想要禁用这个后退按钮,我也就释然 (想要禁用的只有后退按钮,不包括浏览器的前进按钮) 。因为在默认情况下,用户提交表单之后可以通过后退按钮返回表单页面 (而不是使用"编辑"按钮!) ,然后再次编辑并提交表单向数据库插入新的记录。这是我们不愿看到的。 因此我就决定要找出避免出现这种情况的方法。我访问了许多网站,参考了这些网站所介绍的各种实现方法。如果你经常访问ASP编程网站,本文所介绍的部分内容你可能已经见到过。本文的任务是把各种可能的方法都介绍给大家,然后找出最好的方法! 二、禁止缓存 在我找到的许多方案中,其中有一种建议禁止页面缓存。具体是使用服务器端脚本,如下所示: <% Response.Buffer = True Response.ExpiresAbsolute = Now() - 1 Response.Expires = 0 Response.CacheControl = "no-cache" %> 这种方法非常有效!它强制浏览器重新访问服务器下载页面,而不是从缓存读取页面。使用这种方法时,编程者的主要任务是创建一个会话级的变量,通过这个变量确定用户是否仍旧可以查看那个不适合通过后退按钮访问的页面。由于浏览器不再缓存这个页面,当用户点击后退按钮时浏览器将重新下载该页面,此时程序就可以检查那个会话变量,看看是否应该允许用户打开这个页面。 例如,假设我们有如下表单: <% Response.Buffer = True Response.ExpiresAbsolute = Now() - 1 Response.Expires = 0 Response.CacheControl = "no-cache" If Len(Session("FirstTimeToPage")) > 0 then ' 用户已经访问过当前页面,现在是再次返回访问。 ' 清除会话变量,将用户重定向到登录页面。 Session("FirstTimeToPage") = "" Response.Redirect "/Bar.asp" Response.End End If ' 如果程序运行到这里,说明用户能够查看当前页面 ' 以下开始创建表单 %> <form method=post action="SomePage.asp"> <input type=submit> </form> 我们借助会话变量FirstTimeToPage检查用户是否是第一次访问当前页面。如果不是第一次 (即Session(“FirstTimeToPage”)包含某个值) ,那么我们就清除会话变量的值,然后把用户重新定向到一个开始页面。这样,当表单提交时 (此时SompePage.asp被打开) ,我们必须赋予FirstTimeToPage一个值。即,在SomePage.asp中我们需要加上下面的代码: ...

Created 6066-01-06 · Updated 9096-10-09 · 1 min · 181 words · -

JavaScript window.onload

JavaScript window.onload JavaScript的window.onload使用: window.onload方法,可以定义html中的onload方法例如: window.onload=function(){ var a = document.getElementById("loading"); a.parentNode.removeChild(a); } 这样就可以通过js代码直接定义这个方法,而不需要象这样定义了<body onload="aaa()"> window.onload方法,可以定义html中的onload方法例如: window.onload=function(){ var a = document.getElementById("loading"); a.parentNode.removeChild(a); } 这样就可以通过js代码直接定义这个方法,而不需要象这样定义了<body onload="aaa()"> 如果<body>标签原来已经定义了onload方法,则可以通过下面的方法,再追加自己的方法: if(window.onload==null){ window.onload=function(){dvwait1.style.display = "none";} }else{ eval("wtempfunction="+window.onload.toString()); window.onload=function(){wtempfunction();dvwait1.style.display = "none";} } 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 window-onload.md;url 改为 window-onload;旧 url 加入 aliases;categories 改为 JavaScript 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 1016-01-01 · Updated 9096-10-09 · 1 min · 58 words · -

inline script 和外链 script

inline script 和外链script 性能 从性能角度来说,inline script 和外链script (<script src="xxx" />) 各有优势。 假设你的script只有很少的几行,写在html内确实省去了一个请求。 不过用外链方式,最好的情况下可以让浏览器从本地缓存中进行一次IO读取——这只会花2ms。如果谁有兴趣的话我可以解释一下什么情况下会完全读本地缓存,什么情况下是HTTP 304,什么情况下会是全新的HTTP 200. 这些不是重点,结论是 js比较少的时候,在页面上写会有性能优势。 但是随着js代码的增加,这个优势越来越小。你需要衡量的东西也会越来越多: 外链js对页面加载速度的影响 内联js对页面加载速度的影响 外链js被缓存后,用户访问多个页面时能节约的加载时间 不同页面,新访问用户的比例 随着js代码的增加,直接在页面上嵌入script的做法获得的收益越来越小 维护性 维护性在我看来是优先于性能要考虑的,放在后面说是因为这方面外链script完胜。如果你在页面上写js,分散的js碎片要么迅速膨胀,要么被遗忘而成为隐患。 所以建议js还是写到单独的js文件里面。 再回到楼主的问题, 是否可以或者应该合并到一处? 是完全可以的,$(function(){}) 里面的function会在DOMReady之后才运行,所以放在哪里都可以 (甚至在你要操作的DOM HTML前面) 是否应该?如果模板是有很多个小模块构成,对应的js文件也尽量和模板放在一起,做模块化的管理。 <!-- module A --> a模块的HTML… </div> <script src="module-a.js"></script> <!-- module B --> b模块的HTML</div> <script src="module-b.js"></script> (sinatra + haml 用惯了,不习惯rails的静态资源管理方式) 实际上上面这个模板,更好的方式是拆分成a、b两个partial模板了 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 inline-external-script.md;title 改为「inline script 和外链 script」;url 改为 inline-external-script;旧 url 加入 aliases;categories 改为 JavaScript 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 9096-10-09 · Updated 9096-10-09 · 1 min · 81 words · -

Cloudflare Workers: 边缘 Serverless 运行环境

Cloudflare Workers 是什么 Cloudflare Workers 是 Cloudflare 提供的 Serverless 运行环境:把一段 JavaScript / TypeScript(也支持 Python 和编译成 WebAssembly 的 Rust、Go 等)部署到 Cloudflare 全球的边缘节点上,请求打到离用户最近的节点时直接在那里执行代码并返回响应,不需要自己管服务器。 和 AWS Lambda 这类传统 FaaS 相比,主要区别在运行时: 对比项 Cloudflare Workers 传统 FaaS(如 Lambda) 隔离方式 V8 Isolate,多个 Worker 共享一个进程 容器 / microVM 冷启动 毫秒级,基本可忽略 百毫秒到秒级 部署位置 全球所有边缘节点 选定的一个或几个 region 运行时 类浏览器的 Web 标准 API(fetch、Request、Response 等),部分兼容 Node.js API 完整的 Node.js / Python 等运行时 限制 CPU 时间、内存(128 MB)、包体积有限制 限制相对宽松 V8 Isolate 是 Chrome 的 JS 引擎里用来隔离不同页面的机制,开销比容器小很多,所以冷启动快、单机能跑大量 Worker;代价是不能运行任意二进制,也不能使用依赖原生模块的 npm 包。 ...

Created 4046-10-04 · Updated 4046-10-04 · 3 min · 500 words · -

Compiled vs Interpreted: 编译型、解释型与脚本语言

背景 教材里常把编程语言分成 编译型(compiled) 和 解释型(interpreted)。二者是一组相对概念,但现代语言大多落在光谱中间,不宜一刀切。 脚本语言(scripting language) 在日常说法里,往往就是解释型一侧的别名,或更窄一点:强调「缩短 edit-compile-link-run、以源码直接跑、做自动化 / 嵌入」的那一类解释型语言。下文先讲编译 / 解释,再单独说脚本。 两种执行路径 类型 典型流程 运行时依赖 编译型 源码 → 编译器 → 机器码 / 本地二进制 → 直接由 OS 加载执行 一般不需要语言自带的解释器;可内嵌 runtime(如 GC) 解释型 源码(或中间表示)由 解释器 边读边执行 必须安装对应解释器 / 运行时 对照: 编译型(AOT): 源码 ──compile──► 本地二进制 ──► 运行 解释型: 源码 ──► 解释器逐句执行 字节码 + VM: 源码 ──compile──► 字节码 ──► 解释 / JIT ──► 机器码 「预编译 / ahead-of-time(AOT)」说的是:运行前就编成可执行形态;日常口语里常与「编译型」混用。注意 C 里的「预编译」有时指 #include / #define 的预处理,那是编译流水线的一步,不是语言分类。 ...

Created 1016-08-01 · Updated 1016-08-01 · 2 min · 395 words · -

React 入门

React 是由 Meta(前 Facebook)开发并开源的 JavaScript UI 库,专注于构建用户界面。它于 2013 年开源,目前已成为最流行的前端技术之一。 react 核心概念 组件(Component) React 的核心单元是组件(Component)。组件是一个返回 UI 描述的函数(或类),可以像拼积木一样组合成复杂的界面。 function Greeting({ name }) { return <h1>Hello, {name}!</h1>; } 组件分为两类: 函数组件:现代 React 的主流写法,配合 Hooks 使用 类组件:早期写法,新项目不推荐使用 JSX JSX 是 JavaScript 的语法扩展,允许在 JS 文件中写类似 HTML 的结构。它不是 HTML,会被编译工具(如 Babel、SWC)编译为 React.createElement() 调用。 const element = <div className="container">Hello</div>; // 编译后等价于: const element = React.createElement("div", { className: "container" }, "Hello"); 详见:JSX 介绍 Props Props(属性)是组件的输入,由父组件传入,在子组件内部是只读的。 function Button({ label, onClick }) { return <button onClick={onClick}>{label}</button>; } // 使用 <Button label="提交" onClick={() => console.log("clicked")} /> State State(状态)是组件内部管理的可变数据。状态变化会触发组件重新渲染。 import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>当前计数:{count}</p> <button onClick={() => setCount(count + 1)}>+1</button> </div> ); } 虚拟 DOM React 在内存中维护一棵虚拟 DOM 树。每次状态更新时,React 通过 Diffing 算法对比新旧虚拟 DOM,计算出最小变更集,再批量更新真实 DOM,从而提升性能。 ...

Created 17176-05-17 · Updated 16166-06-16 · 2 min · 353 words · -

React 状态管理:Zustand、Jotai 与 Redux 对比

什么是状态管理,它解决什么问题 React 的数据流是单向的:数据通过 Props 从父组件流向子组件。这在小型应用中很好用,但随着应用规模扩大,会遇到两个典型痛点: Prop Drilling(属性透传) 同一份数据需要从顶层组件一层一层往下传,中间层组件本身并不使用这个数据,却不得不接收并转发它。组件层级越深,代码越难维护。 App(持有 user 状态) └─ Layout └─ Sidebar └─ UserAvatar(需要 user)← 要传三层 props 跨组件状态同步困难 当两个没有父子关系的组件需要访问同一份数据时,只能把状态提升到它们共同的祖先组件,然后再层层传下去。状态越分散,同步越容易出 bug。 状态管理库的解法 把共享状态提取到组件树之外的独立 Store,任何组件都可以直接订阅和修改,不需要层层传递 Props。 Store(独立于组件树) ↗ ↗ ComponentA ComponentB React 主流状态管理方案对比 库 定位 包大小 学习曲线 Zustand 轻量、直觉式 API ~1 KB 低 Jotai 原子化状态,细粒度订阅 ~3 KB 低 Redux Toolkit 功能完整,适合大型项目 ~20 KB 高 Zustand Zustand 是目前最流行的轻量状态管理库,API 极简,和 Vue 的 Pinia 非常相似。 创建 Store: ...

Created 18186-05-18 · Updated 18186-05-18 · 4 min · 685 words · -

TypeScript

JavaScript vs TypeScript 对比 同样的用户问候功能,JS 和 TS 写法对比: // JavaScript 版本 function greetUser(user) { return "Hello, " + user.name + "! You are " + user.age + " years old."; } const user = { name: "Alice", age: 25 }; console.log(greetUser(user)); // Hello, Alice! You are 25 years old. console.log(greetUser({ name: 42 })); // 不报错,但输出结果异常:Hello, 42! You are undefined years old. // TypeScript 版本 interface User { name: string; age: number; } function greetUser(user: User): string { return `Hello, ${user.name}! You are ${user.age} years old.`; } const user: User = { name: "Alice", age: 25 }; console.log(greetUser(user)); // Hello, Alice! You are 25 years old. console.log(greetUser({ name: 42 })); // ❌ 编译错误:name 应为 string,不能传 number TypeScript 在编写代码时就能发现类型错误,而不是等到运行时出现奇怪的 bug。 ...

Created 13136-06-13 · Updated 17176-05-17 · 3 min · 430 words · -

React 函数组件与类组件

React 有两种组件写法:函数组件(Function Component) 和 类组件(Class Component)。现代 React 项目几乎全面使用函数组件,类组件属于历史遗留写法。 函数组件 函数组件就是一个普通的 JavaScript 函数,接收 Props,返回 JSX。 function Greeting({ name }) { return <h1>Hello, {name}!</h1>; } // 也可以用箭头函数 const Greeting = ({ name }) => <h1>Hello, {name}!</h1>; React 16.8 引入 Hooks 之后,函数组件可以使用状态和生命周期,成为主流写法。 类组件 类组件通过继承 React.Component 实现,必须定义 render() 方法返回 JSX。 import { Component } from "react"; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } 有状态的类组件: class Counter extends Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return ( <div> <p>计数:{this.state.count}</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> +1 </button> </div> ); } } 同一功能的对比 以一个带状态的计数器为例,对比两种写法的差异: 类组件写法: class Counter extends Component { constructor(props) { super(props); this.state = { count: 0 }; this.handleClick = this.handleClick.bind(this); // 必须手动绑定 this } componentDidMount() { document.title = `计数:${this.state.count}`; } componentDidUpdate() { document.title = `计数:${this.state.count}`; } componentWillUnmount() { document.title = "App"; } handleClick() { this.setState({ count: this.state.count + 1 }); } render() { return ( <button onClick={this.handleClick}> 计数:{this.state.count} </button> ); } } 函数组件写法: ...

Created 17176-05-17 · Updated 17176-05-17 · 3 min · 481 words · -

React Hooks 详解

Hook 是 React 16.8 引入的一类特殊函数,命名以 use 开头。它让函数组件拥有了原本只有类组件才有的能力:状态管理、生命周期、跨组件共享逻辑。 为什么需要 Hook React 16.8 之前,函数组件只能做纯渲染,没有状态、没有生命周期。要用这些功能必须写类组件,但类组件存在几个痛点: this 绑定容易出错 生命周期方法(componentDidMount / componentDidUpdate)把不相关的逻辑强行塞在一起 状态逻辑难以在组件之间复用 Hook 彻底解决了这些问题,现代 React 项目基本全面使用函数组件 + Hook。 Hook 使用规则 这两条规则必须严格遵守,否则会导致 Bug。 只在函数组件或自定义 Hook 的顶层调用 Hook,不能在条件语句、循环、嵌套函数中调用 只在 React 函数中调用 Hook,不能在普通 JS 函数中调用 // ❌ 错误:在条件语句中调用 if (condition) { const [value, setValue] = useState(0); } // ✅ 正确:在顶层调用 const [value, setValue] = useState(0); if (condition) { setValue(1); } 内置 Hook useState 管理组件的局部状态。 const [state, setState] = useState(initialValue); state:当前状态值 setState:更新状态的函数,调用后触发重渲染 initialValue:初始值,也可以传入一个函数(懒初始化) import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>计数:{count}</p> <button onClick={() => setCount(count + 1)}>+1</button> <button onClick={() => setCount(prev => prev - 1)}>-1</button> </div> ); } 函数式更新:当新状态依赖上一个状态时,推荐传函数给 setState,避免闭包陷阱: ...

Created 17176-05-17 · Updated 17176-05-17 · 4 min · 675 words · -

JSX 是什么

JSX 解决了什么问题 在 JSX 出现之前,用 JavaScript 描述 UI 结构需要这样写: const el = React.createElement( 'div', { className: 'card' }, React.createElement('h2', null, title), React.createElement('p', null, content), React.createElement('button', { onClick: handleClick }, '确认') ); 嵌套稍深就几乎无法阅读。而人类天然擅长读 HTML 这种树形标签结构。 JSX 解决的核心问题是:让 UI 结构可视化,让开发者用熟悉的标签思维描述界面,同时保留 JavaScript 的全部表达能力。 // JSX 版本,结构一目了然 const el = ( <div className="card"> <h2>{title}</h2> <p>{content}</p> <button onClick={handleClick}>确认</button> </div> ); JSX 是什么 JSX(JavaScript XML)是一种 JavaScript 的语法扩展,允许在 JS 代码里直接写类似 HTML 的标签。 它既不是真正的 HTML,也不是模板引擎,而是 React.createElement() 的语法糖。浏览器不认识 JSX,需要由 Babel 等编译工具在构建阶段将其转换为普通 JavaScript。 // 你写的 JSX const element = <h1 className="title">Hello, {name}</h1>; // Babel 编译后(React 17 之前) const element = React.createElement( 'h1', { className: 'title' }, 'Hello, ', name ); // Babel 编译后(React 17+ 新 JSX Transform) import { jsx as _jsx } from 'react/jsx-runtime'; const element = _jsx('h1', { className: 'title', children: ['Hello, ', name] }); React 17 之后引入了新的 JSX Transform,编译器自动引入 react/jsx-runtime,不再需要在每个文件顶部写 import React from 'react'。 ...

Created 17176-05-17 · Updated 17176-05-17 · 3 min · 597 words · -

React 虚拟 DOM 与 Diff 算法

什么是虚拟 DOM 虚拟 DOM(Virtual DOM)是用 JavaScript 对象来描述真实 DOM 结构的一棵树,存在于内存中,是真实 DOM 的轻量级副本。 内存中的实际结构 React Element 虚拟 DOM 节点是一个普通的 JavaScript 对象(Plain Object),React 内部称它为 React Element,由 React.createElement() 创建。 // 你写的 JSX const el = <div className="box"><h1>Hello</h1></div> // Babel 编译后实际执行的 const el = React.createElement( 'div', { className: 'box' }, React.createElement('h1', null, 'Hello') ) // 返回的对象结构 { $$typeof: Symbol(react.element), // 防 XSS 的安全标记 type: 'div', key: null, ref: null, props: { className: 'box', children: { $$typeof: Symbol(react.element), type: 'h1', key: null, ref: null, props: { children: 'Hello' }, _owner: null, } }, _owner: null, } 树状结构靠 props.children 的引用嵌套形成,多个子节点时 children 是一个数组: div (React Element) └── props.children: [ h1 (React Element) └── props.children: "Hello" p (React Element) └── props.children: "World" ] React Element 只是"描述长什么样"的不可变快照,每次渲染都会重新创建,不会长期驻留内存。 ...

Created 17176-05-17 · Updated 17176-05-17 · 2 min · 401 words · -

javascript 序列化与反序列化

javascript 序列化与反序列化 http://blog.csdn.net/zhangquanok/article/details/13002771 var objP = {}; objP.id = 1; objP.name = 2; objP.sex = 32; JSON.stringify(objP)//序列化 JSON.parse(e); //JSON.parse(e)反序列化

Created 10106-06-10 · Updated 10106-06-10 · 1 min · 19 words · -

Javascript异步编程

Javascript异步编程 http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html 一、回调函数 二、事件监听 三、发布/订阅 四、Promises对象

Created 11116-02-11 · Updated 11116-02-11 · 1 min · 6 words · -

Hammer.js 移动设备触摸手势js库

Hammer.js 移动设备触摸手势js库 hammer.js是一个多点触摸手势库,能够为网页加入Tap、Double Tap、Swipe、Hold、Pinch、Drag等多点触摸事件,免去自己监听底层touchstart、touchmove、touchend事件并且写一大堆判断逻辑的痛苦。hammer.js不但支持触摸屏设备的浏览器,在桌面浏览器上,也能将鼠标的点击当做触摸,方便开发人员在桌面浏览器上调试。这是一个专为触摸手势而生的js库 http://www.cnblogs.com/cydmk/archive/2013/05/12/3073570.html https://github.com/EightMedia http://eightmedia.github.io/hammer.js/

Created 10106-03-10 · Updated 10106-03-10 · 1 min · 7 words · -

js check platform

js check platform <script type="text/javascript"> <!- //平台、设备和操作系统 var system ={ win : false, mac : false, xll : false }; //检测平台 var p = navigator.platform; alert(p); system.win = p.indexOf("Win") == 0; system.mac = p.indexOf("Mac") == 0; system.x11 = (p == "X11") || (p.indexOf("Linux") == 0); //跳转语句 if(system.win||system.mac||system.xll){//转向后台登陆页面 window.location.href="login.jsp"; }else{ window.location.href="wapLojin.jsp"; } -> </script> var isMobile = { Android: function() { return navigator.userAgent.match(/Android/i) ? true : false; }, BlackBerry: function() { return navigator.userAgent.match(/BlackBerry/i) ? true : false; }, iOS: function() { return navigator.userAgent.match(/iPhone|iPad|iPod/i) ? true : false; }, Windows: function() { return navigator.userAgent.match(/IEMobile/i) ? true : false; }, any: function() { return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows()); } }; http://blog.csdn.net/yakson/article/details/9390863 ...

Created 27276-02-27 · Updated 27276-02-27 · 1 min · 112 words · -