深究JS底层原理
一、JS中八种数据类型判断方法
在JavaScript中,数据类型分为两大类:基本(原始)数据类型和引用(对象)数据类型。
基本数据类型(Primitive Data Types)
基本数据类型是表示简单的数据片段,它们是直接存储在变量中的数据。JavaScript中的基本数据类型有以下几种:
- String - 表示文本数据,例如
"Hello, World!"。 - Number - 表示整数和浮点数,例如
42和3.14。 - Boolean - 表示逻辑值
true或false。 - Undefined - 表示未定义的值,即变量已声明但未初始化时的值。
- Null - 表示空值或者不存在的对象。在JavaScript中,
null是一个表示“无”的对象,转为数值时为0。 - Symbol (ES6新增) - 表示独一无二的值,常用于创建对象的私有成员。
- BigInt (ES2020新增) - 表示非常大的整数。
基本数据类型的值是不可变的,也就是说,一旦创建,就不能更改。如果对基本数据类型的变量进行操作,实际上是创建了一个新的变量或值。
引用数据类型(Reference Data Types)
引用数据类型表示的是数据的集合,它们存储的是对数据的引用(内存地址),而不是数据本身。在JavaScript中,最常见的引用数据类型是对象(Object),还包括以下几种:
- Object - 表示一组无序的键值对,例如
{name: "Alice", age: 25}。 - Array - 表示一组有序的数据集合,例如
[1, 2, 3, 4]。 - Function - 表示函数,JavaScript中的函数是一等公民,可以作为对象使用。
- Date - 表示日期和时间。
- RegExp - 表示正则表达式。
引用数据类型的值是可变的,这意味着可以改变它们的内容而不改变它们的身份。例如,可以向对象添加属性或修改数组中的元素。
基本数据类型与引用数据类型的区别
以下是一些基本数据类型和引用数据类型之间的关键区别:
- 存储方式:基本数据类型的值直接存储在变量中,而引用数据类型存储的是内存地址。
- 赋值:基本数据类型赋值时是传递值,而引用数据类型赋值时是传递引用。
- 比较:基本数据类型比较的是值,而引用数据类型比较的是引用地址。
- 参数传递:在函数中,基本数据类型作为参数传递时,传递的是值的副本;引用数据类型传递的是引用地址。
理解这些差异对于编写高效和正确的JavaScript代码非常重要。
八种数据类型判断方式









二、NaN








三、数值千分位的六种方法
1.format with array

(number + '') 是一种常见的类型转换技巧,它将数字 number 转换为字符串。无论 number 是什么数字,加上一个空字符串 '' 后,结果都会是一个字符串形式的 number。
function format_with_array(number) {// 转为字符串,并按照.拆分var arr = (number + '').split('.');// 整数部分再拆分var int = arr[0].split('');// 小数部分var fraction = arr[1] || '';// 返回的变量var r = "";var len = int.length;// 倒叙并遍历int.reverse().forEach(function (v, i) {// 非第一位并且是位值是3的倍数, 添加 ","if (i !== 0 && i % 3 === 0) {r = v + "," + r;} else {// 正常添加字符r = v + r;}})// 整数部分和小数部分拼接return r + (!!fraction ? "." + fraction : '');
}const print = console.log;
print(format_with_array(938765432.02));938765432.02
-
这行代码首先通过var arr = (number + '').split('.');number + ''将数字number转换为字符串。这是因为split方法是字符串的方法,不能直接在数字上使用。
然后使用split('.')方法将字符串按照小数点(.)分割成两部分,结果存储在数组arr中。如果number是一个整数,那么arr将只有一个元素,即整数部分;如果number是一个小数,那么arr将有两个元素,第一个元素是整数部分,第二个元素是小数部分。 -
这行代码将var int = arr[0].split('');arr数组中的第一个元素(即整数部分)再次使用split('')方法进行分割。由于没有指定分隔符,实际上是将整数部分的每个字符分割成一个单独的字符串,并将结果存储在数组int中。例如,如果整数部分是"123",那么int将是["1", "2", "3"]。 -
这行代码尝试获取var fraction = arr[1] || '';arr数组中的第二个元素(即小数部分)。如果arr只有一个元素(即number是一个整数),那么arr[1]将是undefined。
使用逻辑或运算符||,如果arr[1]是undefined(即没有小数部分),则将fraction设置为一个空字符串''。如果存在小数部分,则fraction将是小数部分的字符串。
return r + (!!fraction ? "." + fraction : '');
-
r +:这是字符串拼接的开始,将数字r转换为字符串并准备拼接。 -
!!fraction:这是双重逻辑非操作符,用于将fraction转换为布尔值。如果fraction是非空字符串、非零数字或任何“真值”对象,则!!fraction将为true;如果fraction是空字符串、零、null、undefined或任何“假值”,则!!fraction将为false。 -
? "." + fraction : '':这是一个条件(三元)运算符,它根据!!fraction的结果来决定返回的值。如果!!fraction为true(即fraction有值),则返回"." + fraction,即小数点加上fraction的值;如果!!fraction为false(即fraction没有值或为假值),则返回空字符串''。
整体来看,这段代码的作用是:
如果 fraction 有值,那么返回的字符串将是 r 后面跟着一个小数点和 fraction 的值。如果 fraction 没有值或为假值,那么返回的字符串就只是 r 转换成的字符串。
2.format with substring

function format_with_substring(number) {// 数字转字符串, 并按照 .分割var arr = (number + '').split('.');var int = arr[0] + '';var fraction = arr[1] || '';// 多余的位数var f = int.length % 3;// 获取多余的位数,f可能是0, 即r可能是空字符串var r = int.substring(0, f);// 每三位添加","和对应的字符for (var i = 0; i < Math.floor(int.length / 3); i++) {r += ',' + int.substring(f + i * 3, f + (i + 1) * 3)}//多余的位数,上面if (f === 0) {r = r.substring(1);}// 整数部分和小数部分拼接return r + (!!fraction ? "." + fraction : '');
}const print = console.log;
print(format_with_substring(938765432.02));
3.format with mod

function format_with_mod(number) {var n = number; // 将传入的参数 number 赋值给变量 n,用于后续计算,保留原始数值不变。var r = ""; // 初始化一个空字符串 r,用于存储格式化后的结果。var temp; // 声明一个变量 temp,用于暂存计算过程中的中间值。do {mod = n % 1000; // 计算 n 除以 1000 的余数,即取 n 的最后三位数字(包括小数部分)。n = n / 1000; // 将 n 除以 1000,即每次循环处理掉 n 的最后三位数字。temp = ~~mod; // 使用双按位非操作符(~~)来取整,去除 mod 的小数部分,获取整数部分。// 以下代码用于构造格式化字符串:// 如果 n 大于等于 1,说明还有更多的数字需要处理,因此使用 padStart(3, "0") 来确保 temp 是三位数字,不足部分用 "0" 填充。// 如果 r 已经有内容,则在 temp 前面加上 ",",否则直接使用 temp。r = (n >= 1 ? `${temp}`.padStart(3, "0") : temp) + (!!r ? "," + r : "");} while (n >= 1); // 当 n 大于等于 1 时,继续循环,直到 n 小于 1。var strNumber = number + ""; // 将数字 number 转换为字符串,以便后续查找小数点位置。var index = strNumber.indexOf("."); // 查找小数点的位置。// 如果存在小数点(index >= 0),则将原始数字的小数部分添加到格式化字符串 r 的末尾。if (index >= 0) {r += strNumber.substring(index);}return r; // 返回格式化后的字符串。
}const print = console.log; // 将 console.log 方法赋值给变量 print,便于后续使用。
print(format_with_mod(38765432.02)); // 调用 format_with_mod 函数并打印结果。
4.format with regex

const print = console.log;
print(/hello (?=[a-z]+)/.test("hello a"));
print(/hello (?=[a-z]+)/.test("hello 1"));
function format_with_regex(number) {var reg = /\d{1,3}(?=(\d{3})+$)/g;return (number + '').replace(reg, '$&,');
}// 987, 654, 321// const print = console.log;
// print(format_with_regex(987654321));function format_with_regex(number) {var reg = /\d{1,3}(?=(\d{3})+$)/g;return (number + '').replace(reg, function(match, ...args){ console.log(match, ...args);return match + ','});
}
format_with_regex(987654321)// function format_with_regex(number) {
// var reg = /(\d)(?=(?:\d{3})+$)/g
// return (number + '').replace(reg, '$1,');
// }
5.format with toLocaleString

function format_with_toLocaleString(number, minimumFractionDigits, maximumFractionDigits) {minimumFractionDigits = minimumFractionDigits || 2;maximumFractionDigits = (maximumFractionDigits || 2);maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);return number.toLocaleString("en-us", {maximumFractionDigits: maximumFractionDigits || 2,minimumFractionDigits: minimumFractionDigits || 2})
}function format_with_toLocaleString(number) {return number.toLocaleString("en-us")
}const print = console.log;
print(format_with_toLocaleString(938765432.02));
6.Intl.NumberFormat
function format_with_Intl(number, minimumFractionDigits, maximumFractionDigits) {minimumFractionDigits = minimumFractionDigits || 2;maximumFractionDigits = (maximumFractionDigits || 2);maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);return new Intl.NumberFormat('en-us', {maximumFractionDigits: maximumFractionDigits || 2,minimumFractionDigits: minimumFractionDigits || 2}).format(number)
}// 使用默认配置选项
// function format_with_Intl(number) {
// return new Intl.NumberFormat('en-us').format(number)
// }const print = console.log;
print(format_with_Intl(938765432.02));
7.效果对比
对比一下这六种方法的性能
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>数字千分位</title>
</head><body><div style="text-align:center"><p><input type="number" value="5000" id="textCount" /></p><p><input type="button" onclick="executeTest()" value="测试" /><input type="button" onclick="javascript:document.getElementById('messageEl').innerHTML=''" value="清除" /></p></div><div id="messageEl" style="width: 300px;margin: auto;"></div><script>function format_with_array(number) {var arr = (number + '').split('.');var int = arr[0].split('');var fraction = arr[1] || '';var r = "";var len = int.length;int.reverse().forEach(function(v, i) {if (i !== 0 && i % 3 === 0) {r = v + "," + r;} else {r = v + r;}})return r + (!!fraction ? "." + fraction : '');}</script><script>function format_with_substring(number) {var arr = (number + '').split('.');var int = arr[0] + '';var fraction = arr[1] || '';var f = int.length % 3;var r = int.substring(0, f);for (var i = 0; i < Math.floor(int.length / 3); i++) {r += ',' + int.substring(f + i * 3, f + (i + 1) * 3)}if (f === 0) {r = r.substring(1);}return r + (!!fraction ? "." + fraction : '');}</script><script>function format_with_mod(number) {var n = number;var r = "";var temp;var mod;do {mod = n % 1000;n = n / 1000;temp = ~~mod;r = (n > 1 ? `${temp}`.padStart(3, "0") : temp) + (!!r ? "," + r : "")} while (n > 1)var strNumber = number + "";var index = strNumber.indexOf(".");if (index > 0) {r += strNumber.substring(index);}return r;}</script><script>function format_with_regex(number) {var reg = /(\d{1,3})(?=(\d{3})+(?:$|\.))/g;// var reg = /(\d)(?=(?:\d{3})+$)/g//var reg = /\d{1,3}(?=(\d{3})+$)/g;return (number + '').replace(reg, '$1,');}</script><script>// function format_with_toLocaleString(number, minimumFractionDigits, maximumFractionDigits) {// minimumFractionDigits = minimumFractionDigits || 2;// maximumFractionDigits = (maximumFractionDigits || 2);// maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);// return number.toLocaleString("en-us", {// maximumFractionDigits: maximumFractionDigits || 2,// minimumFractionDigits: minimumFractionDigits || 2// })// }function format_with_toLocaleString(number) {return number.toLocaleString("en-us")}</script><script>// function format_with_Intl(number, minimumFractionDigits, maximumFractionDigits) {// minimumFractionDigits = minimumFractionDigits || 2;// maximumFractionDigits = (maximumFractionDigits || 2);// maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);// return new Intl.NumberFormat('en-us', {// maximumFractionDigits: maximumFractionDigits || 2,// minimumFractionDigits: minimumFractionDigits || 2// }).format(number)// }const format = new Intl.NumberFormat('en-us');function format_with_Intl(number) {return format.format(number)}</script><script>function getData(count) {var data = new Array(count).fill(0).map(function(i) {var rd = Math.random();var r = rd * Math.pow(10, Math.trunc(Math.random() * 12));if (rd > 0.5) {r = ~~r;}return r})return data;}function test(data, fn, label) {var start = performance.now();for (var i = 0; i < data.length; i++) {fn(data[i]);}var time = performance.now() - start;message((fn.name || label) + ":" + time.toFixed(2) + "ms");}function executeTest() {var data = getData(+textCount.value);test(data, format_with_array);test(data, format_with_mod);test(data, format_with_substring);test(data, format_with_regex);test(data, format_with_toLocaleString);test(data, format_with_Intl);message("-------------------")}function message(msg) {var el = document.createElement("p");el.innerHTML = msg;messageEl.appendChild(el);}</script></body></html>


三、[]+[],{}+{},[]+{},{}+[]


相关文章:
深究JS底层原理
一、JS中八种数据类型判断方法 在JavaScript中,数据类型分为两大类:基本(原始)数据类型和引用(对象)数据类型。 基本数据类型(Primitive Data Types) 基本数据类型是表示简单的数…...
数据分析-41-时间序列预测之机器学习方法XGBoost
文章目录 1 时间序列1.1 时间序列特点1.1.1 原始信号1.1.2 趋势1.1.3 季节性和周期性1.1.4 噪声1.2 时间序列预测方法1.2.1 统计方法1.2.2 机器学习方法1.2.3 深度学习方法2 XGBoost2.1 模拟数据2.2 生成滞后特征2.3 切分训练集和测试集2.4 封装专用格式2.5 模型训练和预测3 参…...
json转java对象 1.文件读取为String 2.String转为JSONObject 3.JSONObject转为Class
一.参考王广帅的 服务器起服时的加载 private void readConfigFile(String configDir, Class<?> clazz) throws Exception {String fileName getConfigFileName(clazz);File configFile new File(configDir, fileName);// 读取所有的行,因此,应…...
基于卷积神经网络的农作物病虫害识别系统(pytorch框架,python源码)
更多图像分类、图像识别、目标检测等项目可从主页查看 功能演示: 基于卷积神经网络的农作物病虫害检测(pytorch框架)_哔哩哔哩_bilibili (一)简介 基于卷积神经网络的农作物病虫害识别系统是在pytorch框架下实现的…...
ETLCloud异常问题分析ai功能
在数据处理和集成的过程中,异常问题的发生往往会对业务运营造成显著影响。为了提高ETL(提取、转换、加载)流程的稳定性与效率,ETLCloud推出了智能异常问题分析AI功能。这一创新工具旨在实时监测数据流动中的潜在异常,自…...
【1】 Kafka快速入门-从原理到实践
文章目录 🔍 一、引言📜 二、Kafka 的历史🏗️ 三、Kafka 的核心结构🖥️ (一)Broker📋 (二)Topic📄 (三)Partition📤 (四)Producer📥 (五)Consumer🐒 (六)Zookeeper💡 四、Kafka 的重点概念📨 (一)消息📏 (二)偏移量(Offset)🔄 (…...
go语言中的map类型详解
在Go语言中,map是一种内建的数据结构,提供了键值对(key-value)的存储方式。map通常用于实现快速的查找和关联数组,适合在需要根据键来高效查找值的场景下使用。 基本概念 map是一个无序的集合,它存储了键…...
GBase 8a MPP Cluster V9安装部署
GBase 8a MPP Cluster V9安装部署 安装环境准备 节点角色操作系统地址配置GBASE版本gbase01.gbase.cnGCWARE,COOR,DATACentOS 7.9192.168.20.1422C4GGBase 8a MPP Cluster V9 9.5.3.28.12gbase02.gbase.cnGCWARE,COOR,DATACentOS 7.9192.168.20.1432C4GGBase 8a MPP Cluster …...
静态库、动态库、framework、xcframework、use_frameworks!的作用、关联核心SDK工程和测试(主)工程、设备CPU架构
1.1库的概念 库:程序代码的集合,编译好的二进制文件加上头文件供使用,共享程序代码的一种方式。 1.2库的分类 根据开源情况分为:开源库(能看到具体实现)、闭源库(只公开调用的的接口…...
C++ | Leetcode C++题解之第552题学生出勤记录II
题目: 题解: class Solution { public:static constexpr int MOD 1000000007;vector<vector<long>> pow(vector<vector<long>> mat, int n) {vector<vector<long>> ret {{1, 0, 0, 0, 0, 0}};while (n > 0) {…...
网站架构知识之Ansible(day020)
1.Ansible架构 Inventory 主机清单:被管理主机的ip列表,分类 ad-hoc模式: 命令行批量管理(使用ans模块),临时任务 playbook 剧本模式: 类似于把操作写出脚本,可以重复运行这个脚本 2.修改配置 配置文件:/etc/ansible/ansible.cfg 修改配置文件关闭主机Host_key…...
K8s使用nfs
改动点 ip和路径改为自己的 --- apiVersion: v1 kind: ServiceAccount metadata:name: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: nfs-client --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata:nam…...
【大数据学习 | kafka高级部分】kafka的kraft集群
首先我们分析一下zookeeper在kafka中的作用 zookeeper可以实现controller的选举,并且记录topic和partition的元数据信息,帮助多个broker同步数据信息。 在新版本中的kraft模式中可以这个管理和选举可以用kafka自己完成,而不再依赖zookeeper。…...
爬虫策略规避:Python爬虫的浏览器自动化
网络爬虫作为一种自动化获取网页数据的技术,被广泛应用于数据挖掘、市场分析、竞争情报等领域。然而,随着反爬虫技术的不断进步,简单的爬虫程序往往难以突破网站的反爬虫策略。因此,采用更高级的爬虫策略,如浏览器自动…...
Hive 实现查询用户连续三天登录记录
标题:Hive 实现查询用户连续三天登录记录 在数据分析和处理中,经常会遇到需要查询特定条件数据的情况。本文将介绍如何使用 Hive 来查询用户连续三天登录的所有数据记录。 一、问题背景 我们有一个用户登录记录表,其中包含用户的登录日期信…...
OceanBase 4.3.3 功能解析:列存副本
OceanBase 从4.3.0 版本开始,引入了列式存储的支持。用户可以根据业务的具体需求,选择创建列存表、行存表或是行列混存表。无论选择哪种表类型,在不同的Zone内,租户使用的副本模式都是一致的。详见官网文档: https://w…...
2.Python解释器
python解释器程序,用来翻译python代码,并提交给计算机执行。 上一篇博客就是安装了python解释器程序 写一个python文件,在文件中写入多行代码并执行: 进入python后,输入exit()命令退出...
鸿蒙与团结引擎c#与ts简单交互
目录 团结中调用ts代码 鸿蒙中调用团结代码 首先在团结创建代码,需要将代码添加到场景物体中 devecoStudio端编写ts代码 在index页面添加一个测试按钮 团结中调用ts代码 团结引擎 - 手册: Call TypeScript plug-in code from C# scripts 注册函数要跟文件名一致 在u…...
Any 的原理以及实现
序言 在 C17 的更新中引入了一个特别有意思的类型,它提供了一种通用的方式来存储任何类型的数据而不需要提前指定类型, 该类型就是 any。 any 允许你将任意类型的数据存储在一个容器中,并且能够在运行时动态地访问该数据。话不多说…...
SQLI LABS | Less-35 GET-Bypass Add Slashes (we dont need them) Integer Based
关注这个靶场的其它相关笔记:SQLI LABS —— 靶场笔记合集-CSDN博客 0x01:过关流程 输入下面的链接进入靶场(如果你的地址和我不一样,按照你本地的环境来): http://localhost/sqli-labs/Less-35/ 话不多说…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...
spring boot使用HttpServletResponse实现sse后端流式输出消息
1.以前只是看过SSE的相关文章,没有具体实践,这次接入AI大模型使用到了流式输出,涉及到给前端流式返回,所以记录一下。 2.resp要设置为text/event-stream resp.setContentType("text/event-stream"); resp.setCharacter…...
数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...
Axure Rp 11 安装、汉化、授权
Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接:https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...
更新 Docker 容器中的某一个文件
🔄 如何更新 Docker 容器中的某一个文件 以下是几种在 Docker 中更新单个文件的常用方法,适用于不同场景。 ✅ 方法一:使用 docker cp 拷贝文件到容器中(最简单) 🧰 命令格式: docker cp <…...
