阅读视图
银轮股份:获国际客户定点,预计年销售额1.31亿美元
本田拟从中美进口汽车,以增强日本国内产品销售
三星医疗:子公司签订约9.49亿元海外经营合同
第三篇、基本骨架结构
3.1、基本结构
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>页面标题</title>
</head>
<body>
<!-- 之后内容写这里 -->
</body>
</html>
3.2、结构介绍
-
<!DOCTYPE html>:指定浏览器用 HTML5 规则解析页面,避免怪异模式,必须放在页面首行 -
<html lang="zh_CN"></html>:HTML 文档的唯一根标签,所有内容必须嵌套在其中-
lang(必须)属性:声明网页主语言,辅助工具做语言相关的适配处理- 常用值:
zh-CN(简体中文)、en(英文)
- 常用值:
-
-
<head></head>:存储元信息、资源链接等非可视化内容,支撑网页运行和搜索引擎识别 -
<body></body>:承载所有用户可见的页面内容,是网页呈现的核心载体 -
<!--注释内容-->:注释内容不会被浏览器渲染显示,仅用于开发人员理解代码,可放在 HTML 文档任意位置
3.3、head元素内标签
-
<title>网页标题</title>:定义网页标题(显示在浏览器标签 / 搜索结果),标识网页主题,提升用户识别度,是 SEO 优化的核心要素之一 -
<meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1.0"/>:用于定义网页元数据(字符编码、视口、搜索引擎信息等)-
charset(高频)属性:指定 HTML 文档的字符编码格式(如utf-8),确保浏览器能正确解析页面文字,避免乱码 -
name + content (组合使用)属性:定义各类网页元信息,键值对形式传递-
name="viewport" content="width=device-width, initial-scale=1.0":适配移动端视口,控制页面缩放 -
name="keywords" content="HTML,前端,教程":设置网页关键词,辅助搜索引擎收录 -
name="description" content="HTML基础教程":设置网页描述,展示在搜索结果页
-
-
http-equiv + content (组合使用)属性:模拟 HTTP 响应头,控制网页行为-
http-equiv="refresh" content="5;url=https://www.example.com":5 秒后自动跳转到指定网址
-
-
-
<base href="" target=""/>:定义网页中所有相对 URL 的基准地址 / 默认打开方式;一个文档仅能有一个,且必须放在<head></head>内所有含 URL 的标签(如<a>、<link>)之前-
href(可选)属性:设置所有相对链接的基准 URL,页面中相对路径会拼接该值作为完整地址- 示例:
href="https://www.example.com/assets/",则<a href="img/logo.png">实际指向https://www.example.com/assets/img/logo.png
- 示例:
-
target(可选)属性:定义页面中所有链接的默认打开方式,优先级低于链接自身的target属性- 常用值:
_blank(新窗口打开)、_self(当前窗口打开,默认值)、_parent(父框架打开)、_top(顶层框架打开)
- 常用值:
- 注意:若同时设置
href和target,需写在同一个<base>标签中,不可拆分定义
-
-
<link rel="" href="" type=""/>:在 HTML 文档和外部资源间建立关联,核心用于引入样式、定义网页图标等-
rel(必须)属性:声明当前文档与关联资源的关系类型,浏览器据此识别资源用途-
stylesheet(关联外部 CSS 样式表)、icon(定义网页图标favicon)、preconnect(提前建立与目标域名的连接,优化资源加载速度)
-
-
href(必须)属性:指定关联外部资源的 URL 地址(绝对 / 相对路径均可) -
type(可选)属性:声明资源的 MIME 类型,帮助浏览器识别资源格式,现代浏览器可自动识别,无需手动写-
text/css(CSS 文件)、image/x-icon(图标文件)
-
-
-
<style type="text/css">CSS样式</style>:在网页内部编写 CSS 样式,直接控制页面布局和外观,无需引入外部样式文件-
type(可选)属性:声明样式表类型,HTML5 中默认值为text/css,可省略不写
-
-
<script type="text/javascript">JS代码</script>:引入外部 JS 文件(可单标签写法)或编写内部 JS 代码,实现网页动态交互逻辑-
src(可选)属性:指定外部 JS 文件的 URL 地址(绝对 / 相对路径)(无src时,标签内写内部 JS 代码;有src时,标签内代码无效) -
type(可选)属性:声明脚本类型,HTML5 中默认值为text/javascript,可省略不写;type="module"时,将 JS 作为 ES6 模块解析,支持import/export语法 -
defer(可选)属性:布尔属性,使脚本延迟执行(HTML 解析完后按顺序执行),不阻塞页面渲染 -
async(可选)属性:布尔属性,使脚本异步加载(加载完立即执行),不保证多个脚本的执行顺序 - 注意:无
defer/async时,<script>会阻塞 HTML 解析;操作 DOM 的脚本建议放<body>末尾或加defer
-
-
<noscript>内容</noscript>:当页面依赖 JS 实现核心功能,但用户浏览器关闭了 JS、或使用的是极老旧不支持 JS 的浏览器时,<noscript></noscript>内的内容会显示出来,保证用户能看到基础提示或内容,提升页面兼容性
各标签放置位置速览
-
<title>/<meta>/<base>/<link>:仅能放在<head>中,是网页基础配置,放<body>无效; -
<style>:优先放<head>(避免页面闪屏),也可放<body>(仅局部样式); -
<script>:<head>/<body>都可放:- 放
<head>:需加defer/async(避免阻塞渲染),仅用于初始化代码; - 放
<body>末尾:操作 DOM 首选,不阻塞渲染;
- 放
-
<noscript>:<head>/<body>都可放: - 放
<head>:仅提示 JS 禁用(无可视化内容); - 放
<body>:展示替代内容(如提示文案、静态页面),更常用。
3.4、href和src属性
-
href(Hypertext Reference) :超文本引用,用于建立当前文档与外部资源的「关联关系」,浏览器解析时不会暂停当前文档处理,仅记录关联指向- 核心特点:关联而非嵌入,资源不会替换当前文档内容,只是建立链接
- 常用标签:
<link>(引入 CSS)、<a>(超链接)、<base>(基准地址)
-
src(Source) :资源地址,用于将外部资源「嵌入」当前文档中,浏览器解析时会暂停当前文档处理,直到资源加载 / 执行完成- 核心特点:嵌入并替换,资源会成为文档的一部分,需等待加载执行
- 常用标签:
<script>(引入 JS)、<img>(图片)、<iframe>(内嵌页面)
恒指收涨0.28%,恒生科技指数跌0.69%
从原理到手写:彻底吃透 call / apply / bind 与 arguments 的底层逻辑
引言:为什么我们要“手写”这些 API?
在日常开发中,call、apply、bind 几乎每天都会用到。无论是处理 this 绑定问题、实现函数复用,还是做函数柯里化,它们都是绕不开的基础能力。
但有一个现实问题:
很多人“会用”,但说不清楚为什么这样设计,也不知道边界在哪里。
一旦进入复杂业务场景,比如高阶函数封装、事件回调丢失上下文、React 中函数绑定优化等问题,底层理解不扎实就会成为瓶颈。
本文我们做三件事:
- 手写实现
call / apply / bind - 理解它们的设计哲学与差异
- 彻底讲清楚
arguments的本质与演进
目标不是背代码,而是形成“可迁移的工程认知”。
一、手写 call / apply / bind
1.0 先明确三个 API 的语法
func.call(thisArg, arg1, arg2, ...)
func.apply(thisArg, [argsArray])
const newFunc = func.bind(thisArg, arg1, arg2, ...)
区别非常明确:
| 方法 | 是否立即执行 | 参数形式 | 是否返回函数 |
|---|---|---|---|
| call | 是 | 参数列表 | 否 |
| apply | 是 | 数组 | 否 |
| bind | 否 | 参数列表 | 是 |
核心差异点只有两个:
- 是否立即执行
- 参数如何传递
1.1 手写 call —— 从“执行函数”开始
第一步:给所有函数添加能力
Function.prototype.hycall = function () {
console.log("原型链调用了")
}
function foo() {
console.log("foo函数调用了")
}
foo.hycall()
问题出现了:
只执行了 hycall,没有执行 foo 本身。
我们真正的目标是:
- 谁调用 hycall
- 就执行谁
关键点:
var fn = this
fn()
优化版:
Function.prototype.hycall = function () {
var fn = this
fn()
}
小结
- 给
Function.prototype挂方法 = 所有函数都能用 -
this指向调用 hycall 的函数 -
call的第一能力:立即执行函数
1.2 改变 this 指向 —— 显式绑定的核心
默认调用:
fn() // 默认绑定 → window
我们希望:
foo.hycall({ name: "小吴" })
让 this 指向传入对象。
关键思路:
借助“隐式绑定规则”
thisArg.fn = fn
thisArg.fn()
实现:
Function.prototype.hycall = function (thisArg) {
var fn = this
thisArg.fn = fn
thisArg.fn()
delete thisArg.fn
}
对比原生:
foo.hycall({ name: "小吴" })
foo.call({ name: "why" })
图10-1 call调用会执行函数
为什么这样能生效?
因为:
-
obj.fn()是隐式调用 - 隐式调用优先级 > 默认绑定
- 所以 this 指向 obj
这就是“借鸡生蛋”的核心思想。
1.3 处理基本类型问题
问题:
foo.hycall(123)
报错,因为:
123.fn = fn // 不允许
解决方案:
thisArg = Object(thisArg)
最终优化:
Function.prototype.hycall = function (thisArg) {
var fn = this
thisArg =
thisArg !== null && thisArg !== undefined
? Object(thisArg)
: window
thisArg.fn = fn
var result = thisArg.fn()
delete thisArg.fn
return result
}
图10-4 转化为对象的处理方式结果
小结
- 基本类型会被装箱
- null / undefined 特殊处理
- JS 实现无法做到“完全无痕绑定”
1.4 让 call 支持传参 —— ES6 剩余参数
核心能力:
foo.call(obj, a, b, c)
实现:
Function.prototype.hycall = function (thisArg, ...args) {
var fn = this
thisArg =
thisArg !== null && thisArg !== undefined
? Object(thisArg)
: window
thisArg.fn = fn
var result = thisArg.fn(...args)
delete thisArg.fn
return result
}
示例:
function foo(num1, num2, num3) {
console.log(this, num1 + num2 + num3)
}
foo.hycall("小吴", 500, 20, 1)
为什么 call 必须支持参数?
因为:
- 每次函数调用都会创建新的执行上下文
- 改变 this 必须在“那次调用”里完成
错误方式:
foo.call("why")
foo(500,20,1) // this 失效
这是典型“刻舟求剑”。
1.5 手写 apply
区别只在参数形式。
Function.prototype.myapply = function (thisArg, argArray) {
var fn = this
thisArg =
thisArg !== null && thisArg !== undefined
? Object(thisArg)
: window
thisArg.fn = fn
argArray = argArray || []
var result = thisArg.fn(...argArray)
delete thisArg.fn
return result
}
关键差异:
- call:参数列表
- apply:数组
小结
- apply 更适合参数本来就是数组的场景
- 本质逻辑与 call 一致
- 区别只是“参数结构”
1.6 手写 bind —— 真正的升级版
bind 解决什么问题?
延迟执行 + 参数预设
示例:
function foo(num1, num2, num3, num4) {
console.log(this, num1, num2, num3, num4)
}
三种用法:
var bar = foo.bind("小吴", 10, 20, 30, 40)
bar()
var bar = foo.bind("小吴")
bar(10, 20, 30, 40)
var bar = foo.bind("小吴", 10, 20)
bar(30, 40)
实现思路
- 第一次调用 bind:固定 this + 默认参数
- 返回新函数
- 第二次执行:合并参数再执行
实现:
Function.prototype.mybind = function (thisArg, ...argArray) {
var fn = this
thisArg =
thisArg !== null && thisArg !== undefined
? Object(thisArg)
: window
function proxyFn(...args) {
thisArg.fn = fn
var finalArgs = [...argArray, ...args]
var result = thisArg.fn(...finalArgs)
delete thisArg.fn
return result
}
return proxyFn
}
工程理解
- call:一次性执行
- bind:函数工厂
- bind 本质是“柯里化雏形”
二、认识 arguments
2.1 arguments 是什么?
定义:
类数组对象
特征:
- 有 length
- 可索引访问
- 没有数组原型方法
示例:
function foo() {
console.log(arguments.length)
console.log(arguments[1])
console.log(arguments.callee)
}
foo(10, 20, 30, 40, 50)
2.2 arguments 转数组
三种方式:
Array.prototype.slice.call(arguments)
Array.from(arguments)
[...arguments]
为什么 slice + call 能工作?
我们手写一个 slice:
Array.prototype.hyslice = function (start, end) {
var arr = this
start = start || 0
end = end || arr.length
var newArray = []
for (var i = start; i < end; i++) {
newArray.push(arr[i])
}
return newArray
}
var newArray = Array.prototype.hyslice.call(
["小吴", "why", "JS高级"],
1,
3
)
本质:
强行把 arguments 当作数组的 this
2.3 箭头函数为什么没有 arguments?
箭头函数:
- 不绑定 this
- 不绑定 arguments
- 继承上层作用域
示例:
function foo() {
var bar = () => {
console.log(arguments)
}
return bar
}
var fn = foo(123)
fn()
图10-5 arguments打印结果
设计目的:
- 保持语法简洁
- 强化词法作用域一致性
- 鼓励使用
...rest
三、工程层面的思考
3.1 call / apply / bind 的真实差异
| 能力 | call | apply | bind |
|---|---|---|---|
| 改变 this | ✔ | ✔ | ✔ |
| 立即执行 | ✔ | ✔ | ✘ |
| 返回函数 | ✘ | ✘ | ✔ |
| 参数预设 | ✘ | ✘ | ✔ |
3.2 实战建议
什么时候用 call?
- 立即执行
- 已知完整参数
- 做方法借用
什么时候用 apply?
- 参数已经是数组
- Math.max.apply
什么时候用 bind?
- 事件回调绑定
- React 组件方法绑定
- 部分参数预设
四、复盘与团队落地建议
关键结论
- 显式绑定本质是利用隐式调用规则
- bind 是对 call 的延迟封装
- arguments 是历史产物,优先使用 rest
- 所有 this 问题本质都是“调用方式问题”
团队落地建议
- code review 中严格检查 this 丢失问题
- 优先使用箭头函数 + rest
- 对高阶函数封装做统一规范
- 面试训练时必须能手写实现
理解 API 不等于掌握它。
真正的掌握,是知道:
- 它解决什么问题
- 为什么这样设计
- 在复杂业务里如何避免踩坑
当你可以自己实现一遍,你就真正站在了语言机制这一层,而不只是使用层。
从“雕琢”到“生成”:AIGC正在重塑数字孪生世界
随着AI技术的发展,数字孪生场景中的一些场景构建变得更简单、高效。
下面来看看小编如何借助AIGC进行角色和设备建模,结合Mapmost实现变电场数字孪生平台。
Mapmost变电站数字孪生平台
一、角色建模:全流程 AI 驱动的任务生成与动画模拟
为了让虚拟角色在孪生场景中模拟标准化作业流程,提升平台沉浸感,我们构建了一条从概念到动作的完整AI生成管线:
01、概念具象化阶段
通过即梦等AIGC工具,输入结构化描述指令(如“佩戴安全帽、手持巡检终端的变电站作业人员标准T-pose”),可批量生成符合电力作业规范的角色设计原型。
网站指路:jimeng.jianying.com/ai-tool/hom…
即梦出图
02、模型生成阶段
将AI生成的角色图像导入hyper3d.ai进行3D转化。利用平台自动生成角色模型,并根据效果进行角色网格重新拓扑,得到网格完整、纹理准确的T-pose角色模型。
网站指路:hyper3d.ai/?lang=zh
03 角色绑定阶段
在Mixamo平台中,利用其丰富的标准化动作库与自动绑定技术,为静态模型注入“步行巡视”、“仪表检测”、“异常记录”等预设作业动画。通过动作融合与轨迹编辑,最终生成可沿预定路径执行连续作业任务的动态数字人。
网站指路:www.mixamo.com/#/
mixamo角色绑定
借助Mapmost SDK for WebGL的模型加载接口,可实现人员巡逻路径还原。
Mapmost变电站数字孪生平台
二、设备建模:基于 AI 图像增强的精细化三维建模
设备模型的真实感与场景融合度,直接影响着数字孪生场景的最终视觉表现。为使设备模型与高斯场景实现深度融合,我们采用**“影像增强+AI重建”**的方案,实现真实细节的保留与自然融合。
01、影像增强处理
将设备图输入即梦,通过定向提示词(如“增加油渍沉积效果”、“模拟金属氧化痕迹”、“保留原有logo与铭牌”)生成贴合设备在实际环境中所产生的脏迹图像。
即梦出图
02 智能三维重建
hyper3d基于多视图重建算法,从增强图像中提取精确的几何结构与高分辨率纹理,生成保留真实细节的模型。特别优化了对复杂机械结构、不规则表面的精度保留,满足场景对精细设备1:1还原的需求。
hyper3d建模
03 场景数据融合
使用Mapmost SDK for WebGL加载变电站3DGS模型和生成的设备模型,我们发现,由于生成的模型具备了真实世界中的脏迹效果,因此与高斯模型融合得比较自然。
Mapmost变电站数字孪生平台
AIGC技术日趋成熟,越来越多的工具能帮助我们高效生成场景构建所需的高质量模型,极大降低了数字孪生搭建门槛。希望大家也能结合AIGC和Mapmost产品的能力,构建出更多优秀的数字孪生平台!
立即体验,开始三维开发之旅!
👉 点击访问官网免费试用:
南向资金净卖出额超250亿港元
虎鲸文娱组织升级,董事长樊路远:主动求变,积极拥抱AI
南向资金净卖出额达230亿港元
尊界S800、问界M9首发新一代激光雷达
担心AI冲击就业和经济,英国央行拟开展情景评估并纳入银行压力测试
Step 3.5 Flash登上OpenClaw榜首
南向资金净卖出额达200亿港元
Yuan3.0 Ultra开源
陈昌盛:要加快空域资源的开放和低空经济飞行审批程序的优化简化
印尼就虚假信息传播向Meta发出“严厉警告”
uniapp 抽屉实现左滑
直接上代码
<template>
<view style="height: 100vh;background-color: #fff;" @touchstart="touchStart" @touchend="touchEnd">
<view class="" style="width: 100rpx;height: 100rpx;background-color: red;" @click="showDrawer">点击</view>
<uni-drawer ref="showRight" mode="left" width="320">
<scroll-view style="height: 100%;" scroll-y="true">
</scroll-view>
</uni-drawer>
</view>
</template>
<script>
export default {
data() {
return {
startX: 0,
endX: 0,
info: {}
}
},
computed: {},
methods: {
touchStart(e) {
this.startX = e.changedTouches[0].clientX;
},
touchEnd(e) {
this.endX = e.changedTouches[0].clientX;
const moveDis = this.startX - this.endX;
console.log(moveDis);
if (moveDis == 0) return;
if(moveDis < -25) {
this.showDrawer();
}
},
showDrawer() {
this.$refs.showRight.open();
},
closeDrawer() {
this.$refs.showRight.close();
},
}
}
</script>
<style scoped lang="scss">
</style>