从HTML敲击乐了解开发流程

模块化职责分离:前端工程化的基础

  • 专业性:CSS 专注于视觉表现(布局、颜色、字体等),JS 专注于行为交互(事件响应、数据处理等),HTML 专注于内容结构,三者各司其职,符合 "单一职责原则",避免样式与逻辑混杂导致的代码混乱。

  • 可维护性:当需求变更时(如调整按钮样式或修改点击逻辑),开发者可直接定位到对应的 CSS 或 JS 文件修改,无需在混合代码中查找,降低维护成本。

  • 可扩展性:模块化结构支持 "组件化复用",例如多个页面共用的导航栏样式可抽离为单独的 CSS 文件,通用交互逻辑(如表单验证)可封装为 JS 模块,后续新增页面时直接引入即可,提升开发效率。

  • 引入规范

    • CSS 通过 <link><head> 中引入,确保浏览器解析 HTML 结构时能同步加载并解析样式,避免页面先显示 "无样式的毛坯房" 再突然渲染样式(减少 "闪屏" 体验)。
    • JS 通过 <script><body> 底部引入,是因为 JS 执行时可能需要操作 DOM 元素(如获取按钮、修改内容),放在底部可确保 HTML 结构先解析完成,避免因 "元素未加载" 导致的报错;同时,JS 加载和执行会阻塞 HTML 解析(传统同步加载方式),放在底部可优先保证页面静态内容的快速展示,提升首屏加载体验(现代开发中可通过 async/defer 进一步优化加载逻辑)。
    • 网站的渲染效率十分重要,即使是快 0.01 秒也有意义,潜在的网站闪屏会很大的影响客户对产品的体验。而先加载静态样式 HTML (毛坯房) 和 CSS (样式) 会很大的解决这个问题。也就是先加载静态页面,然后再加载 js 代码。JS 在页面 body 的最底部,因为这样才能先加载整个页面再加载 JS 的行为

浏览器的执行逻辑:前端性能优化的依据

浏览器加载 HTML5 应用的过程是 "渐进式解析与渲染" 的过程:

  • 首先下载 HTML 文件,从上到下解析标签,构建 DOM 树(页面结构);
  • 遇到 <link> 标签时,并行下载 CSS 并解析,构建 CSSOM 树(样式规则);
  • DOM 树与 CSSOM 树结合生成渲染树(Render Tree),浏览器根据渲染树计算元素位置和样式,最终绘制到屏幕上(这一步即 "页面可见")。
  • 当解析到 <body> 底部的 <script> 时,DOM 已基本构建完成,JS 可安全操作元素,同时避免了对 DOM 解析的阻塞,确保 "静态页面先展示,交互逻辑后加载"------ 这符合前端 "快速呈现内容" 的核心目标,因为用户对页面的第一感知是 "能否看到内容",而非 "能否交互"。

简言之,HTML5 Web 应用的开发规范,本质上是通过 "结构语义化、职责模块化、加载有序化",实现 "开发高效、维护便捷、用户体验流畅" 的目标,而浏览器的执行机制则是这些规范设计的底层依据。

JS 的执行逻辑 - 敲击乐的键盘行为初步:

javascript 复制代码
/* 页面的最底部,在静态页面执行后再执行 */
/* document整个文档,添加了一个时间监听 */
/* 首要渲染界面 html+css,不需要js参与 */
/* 文档加载完后在执行 */
// DOM文档结构
// script会阻塞HTML的下载
document.addEventListener('DOMContentLoaded',function(){
    //页面加载完后在执行
    //可以获得页面元素,添加事件监听器等
    //添加事件监听
    function playSound(event){
        //  事件对象,在事件发生时会给回调函数
        //  keyCode按下键的编码
​
        console.log(event.keyCode,'///////////')
        let keyCode = event.keyCode;
       let element = document.querySelector('.key[data-key="'+ keyCode +'"]');
        //
        console.log(element);
        // 动态DOM编程
        element.classList.add('playing');
    }
    //事件监听触发回调函数
    window.addEventListener('keydown', playSound)
});

设计方法之代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它通过引入一个 "代理对象" 来控制对原始对象的访问。代理对象可以在不改变原始对象接口的前提下,为其提供额外的功能(如权限控制、日志记录、延迟加载等),同时屏蔽了原始对象的直接访问。

先来看一段代码:

xml 复制代码
<script>
        /* 面向对象思想 */
        /* 表现力的JSON 对象字面量 */
        /* 对象自变量 */
        // let变量 关键字
        // key vau1e 格式
        // typeof   object  
        let zzp = {
            name: '杨探花',     //字符串   string
            hometown:'上饶鄱阳',
            age: 18,           //number  不适合计算   数值类型
            sex: '男',
            hobbies:['学习','乒乓球','探花'],  //对象 
            isSingle: false,
            job: null,
            sendFlower: function(target){
                target.receiveFlower(zzp);
            }
        }
        let a;
        let xm = {
            xq: 30,
            name: '小美',
            hometown: '赣州',
            receiveFlower: function(sender){
                console.log('小美收到了'+sender.name+'花');
                if(this.xq < 80){
                    console.log('不约,我们不合适');
                }else{
                    console.log('我们去硕果吧!');
                }
​
            }
        }
        let xh = {
            name : '小红',
            hometown: '上饶',
            receiveFlower: function(sender){
                /* js定时器 */
                setTimeout(function(){
                    xm.xq=90;
                    xm.receiveFlower(sender);
                },3000)
                /* console.log('小红收到了'+sender.name+'花');
                xm.receiveFlower(sender); */
                /* if (sender.name==='杨探花'){
                    console.log('让我们在一起吧...')
                } */
            }
​
        }
    </script>

让我们从送花这个日常的场景来代入:

日常生活中,杨探花 zzp 打算给小美 xm 送花,但没有调用 xm 的 receive 方法,反而通过小红来代理送花。

scss 复制代码
// 杨探花送花给小红(代理),而非直接送给小美(真实主题)
zzp.sendFlower(xh);

小红作为代理,做了两件关键的 "代理工作":

  • 拦截并处理请求 :小红接收花后,没有自己决定是否约会,而是通过setTimeout延迟 3 秒,修改了小美(真实主题)的xq值(从 30 改为 90),再调用小美自己的receiveFlower方法。
  • 控制对真实主题的访问: 代理 小红 xh 通过对 小美 xm 心情值 xq 的修改间接影响了结果。

代理模式的核心目的

  • 代理(小红)在不改变真实主题(小美)接口(receiveFlower方法)的前提下,为其添加了额外操作(延迟、修改状态)。
  • 代理控制了对真实主题的直接访问,杨探花无需知道小美是否会同意,只需通过代理传递请求即可。
总结

这段代码中,小红(xh)作为代理,隔离了杨探花和小美直接交互,并在中间层完成了延迟处理和状态调整,完全符合代理模式 "通过代理对象控制对真实对象的访问,并添加额外逻辑" 的核心思想。这类似于生活中 "找朋友帮忙牵线搭桥" 的场景,朋友就是代理,最终决策仍由目标对象(小美)完成。

JavaScript 数据类型:构建交互世界的基石

在 JavaScript 的世界里,数据类型是构建一切逻辑的基础。它们如同建筑中的砖瓦,决定了程序如何存储、处理和传递信息。JavaScript 定义了六种基本数据类型,每种类型都有其独特的特性和用途,共同支撑起复杂的交互逻辑。

字符串(string)

是最直观的数据类型,用于表示文本信息。无论是用户输入的用户名、页面上的标题,还是接口返回的描述性内容,都以字符串形式存在。它可以用单引号、双引号或反引号包裹,其中反引号支持多行文本和变量嵌入,为模板字符串提供了极大便利。字符串的不可变性是其重要特性 ------ 一旦创建便无法修改,任何看似修改的操作实际都是生成了新的字符串。

数值(number)

统一处理整数和浮点数,消除了其他语言中 int 与 float 的严格区分。这种设计简化了数值运算,但也带来了精度问题,比如 0.1+0.2 的结果并非精确的 0.3。

布尔值(boolean)

是逻辑判断的核心,仅有 true 和 false 两个值。它在条件语句、循环控制中扮演关键角色,决定程序的执行路径。看似简单的布尔值背后,隐藏着 JavaScript 独特的 "真值" 与 "假值" 概念 ------ 除了 false、0、""、null、undefined 和 NaN 外,其他值在逻辑判断中都被视为 true。

对象(object)

是 JavaScript 的核心概念,用于存储键值对集合。它可以包含字符串、数值等基本类型,也能嵌套其他对象或函数,从而构建复杂的数据结构。数组、日期、正则表达式等都是特殊的对象类型。对象的引用传递特性需要特别注意:当把对象赋值给变量时,变量存储的是内存地址而非实际数据,这意味着多个变量可能指向同一个对象,修改其中一个会影响所有引用。

空值(null)

表示 "故意缺少值",常被用于主动清空变量的引用。它是一个独立类型,typeof 运算符检测时却会返回 "object",这是语言设计的历史遗留问题。与 null 不同,未定义(undefined)表示 "值不存在",通常出现在未初始化的变量、函数未返回值、对象不存在的属性等场景中。

这六种数据类型构成了 JavaScript 的基本数据体系,其中字符串、数值、布尔值、null、undefined 属于原始类型,而对象属于引用类型,其值存储在堆内存中,变量仅保留引用地址。理解这种差异是掌握 JavaScript 内存管理的关键。

在实际开发中,数据类型的转换是高频操作。JavaScript 会根据上下文自动进行类型转换,比如字符串与数值相加时会自动转为字符串拼接。但过度依赖隐式转换容易引发 bug,因此显式转换(如 Number ()、String ()、Boolean ())更值得推荐。

下图为undefined和null的区别与辨析

维度 undefined null
含义 自然未定义(被动状态) 主动清空(主动操作)
类型检测 typeof 返回 "undefined" typeof 返回 "object"(Bug)
数值转换 转为 NaN 转为 0
使用场景 系统默认的 "无值" 状态 开发者主动设置的 "空值" 状态
相关推荐
烟袅5 小时前
JavaScript 中的 null 与 undefined:你真的搞懂它们的区别了吗?
javascript
有点笨的蛋5 小时前
“花”点心思学代理:JavaScript中的对象与中介艺术
javascript
Hilaku5 小时前
一个函数超过20行? 聊聊我的函数式代码洁癖
前端·javascript·架构
不会算法的小灰5 小时前
JavaScript 核心知识学习笔记:给Java开发者的实战指南
javascript·笔记·学习
crary,记忆6 小时前
Angular如何让整个项目的所有页面能够整体缩小一定的比例?
javascript·ecmascript·angular.js
Mintopia6 小时前
🤖 算法偏见修正:WebAI模型的公平性优化技术
前端·javascript·aigc
江城开朗的豌豆7 小时前
小程序与H5的“握手言和”:无缝嵌入与双向通信实战
前端·javascript·微信小程序
你的电影很有趣7 小时前
lesson73:Vue渐进式框架的进化之路——组合式API、选项式对比与响应式新范式
javascript·vue.js
江城开朗的豌豆7 小时前
小程序静默更新?用户却无感?一招教你“强提醒”
前端·javascript·微信小程序