当前位置: 首页 > news >正文

面向C++程序员的JavaScript 语法实战学习1

面向C++程序员的 JavaScript 语法实战学习1

前言

谈不上开新坑,笔者最近终于可以仔细的学习JavaScripts和进一步的TypeScripts了,这个系列的博客是打算给一些熟悉C++,正在打算入手学习JavaScripts的朋友阅读的。因此,特别的开了这个系列的博客进行一个简单的记录。

所有的来源都是基于MDN文档学习,放心参考。


这一片,我们大致讲。。。

  1. 注释(Comments)
  2. 变量/函数声明:varletconst、函数声明与函数表达式、提升(hoisting)与 TDZ
  3. JavaScript 的类型系统(Primitive 与 Object)
  4. 常见类型细节与陷阱(null vs undefined、NaN、-0、相等比较)
  5. 常用数据结构:Array、Object、Map、Set、WeakMap、WeakSet、TypedArray 等
  6. 字面量(Literals):数值、字符串、模板、对象、数组、正则、函数/箭头、类、二进制/八进制/十六进制等

注释(Comments)

注释,C++中也有注释。这个没有什么奇淫技巧,甚至可以说,跟C++的完全一致。官方的说:注释用于给代码写说明,不会被 JavaScript 引擎执行。常见三种形式:

  • 单行注释://
// 这是单行注释
let x = 1; // 行尾注释
  • 多行注释:/* ... */
/*多行注释可以跨越多行
*/
  • JSDoc 风格(用于生成文档或给 IDE 提供类型/注释信息):/** ... */
/*** 计算矩形面积* @param {number} w 宽度* @param {number} h 高度* @returns {number} 面积*/
function area(w, h) {return w * h;
}

声明(Declarations)与提升(Hoisting)

变量的声明总是是程序语言设计的第一步。在JavaScript 中常见的声明有变量声明、函数声明、类声明等。我们快速过的重点是理解 varletconst 的区别,以及函数声明 vs 函数表达式的行为。

var:不被推介的全局访问声明

var的产生笔者认为是一种不完备,因为它的作用域是整个函数内甚至是全局的,意味着,这样的代码会神奇的被通过执行而不会产生错误:

console.log(x) // undefined
var x = 2
console.log(x) // 2

你知道的,这就像神秘的访问未初始化变量一般,这也就导致一种很烦人的问题:你也不知道你的同事在哪里搞了一个x出来,甚至还是用var声明的,导致很有可能会造成程序的变量引用错乱,难以排查。

相比之下,let就显然更好一点:

let

let是一种更加现代的声明方式,笔者认为let声明变量才是合理的程序编程行为。它的作用域就跟我们理解的C/C++变量一样,必须声明后访问。

console.log(y)
let y = 3
console.log(y)

这段代码就会触发错误:

ReferenceError: Cannot access 'y' before initializationat Object.<anonymous> (/home/charliechen/js_practice/pr2/var.js:5:13)at Module._compile (node:internal/modules/cjs/loader:1760:14)at Object..js (node:internal/modules/cjs/loader:1893:10)at Module.load (node:internal/modules/cjs/loader:1480:32)at Module._load (node:internal/modules/cjs/loader:1299:12)at TracingChannel.traceSync (node:diagnostics_channel:328:14)at wrapModuleLoad (node:internal/modules/cjs/loader:244:24)at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)at node:internal/main/run_main_module
const

const绑定的值是不可变的,但是他不像C++,会给所有的成员上const,所以这个const只是在说,你没法更新const修饰的变量存储的值,但是存储的东西本身的自身方法或者是成员仍然可以随意使用。或者更加确切的说,js的const是纯粹的禁用了被修饰对象的赋值行为

const obj = { a: 1 };
obj.a = 2; // 合法
obj = {}; // TypeError:不能重新赋值
函数声明 vs 函数表达式

js的函数声明非常的自由,大致的结构是:

function func_name(var1, var2){// do something// return if request// return var_res;
}

function修饰的函数就跟我们的C++函数一样了,你声明且实现了,那就可以在该js文件中随意使用

foo(); // 可以
function foo() { console.log('hi'); }

比起来,采用函数表达式更加像是生成了函数对象,在js中称之为函数表达式(包括箭头函数)

bar(); // TypeError: bar is not a function
var bar = function() {};

或用 let/const

baz(); // ReferenceError(TDZ)
const baz = () => {};

JavaScript 的类型系统(概览)

JavaScript 有两类值:

  • 原始类型(Primitive):UndefinedNullBooleanNumberBigIntStringSymbol
  • 复杂类型(Object):对象、函数(在 JS 中函数就是对象)、数组、日期、正则等(所有非原始值都是对象)

typeof 操作符能返回一些基本类型信息,但有些值得注意:

typeof undefined; // "undefined"
typeof null;      // "object" —— 这是历史遗留的怪癖(注意)
typeof true;      // "boolean"
typeof 123;       // "number"
typeof 1n;        // "bigint"
typeof "abc";     // "string"
typeof Symbol();  // "symbol"
typeof {};        // "object"
typeof [];        // "object"
typeof function(){}; // "function" —— 这是对象的一种特殊返回值

原始类型细节

Number(数字)
  • JS 把整数和浮点数都归为 Number,遵循 IEEE 754 双精度浮点数。
  • 特殊值:NaN(非数)、Infinity-Infinity
  • Number.isNaN(x) 推荐用于判断 NaN,它不会把非数字误判。
  • 常见陷阱:浮点精度问题,如 0.1 + 0.2 !== 0.3
  • -0 的存在:-0 === 0 为真,但 1 / -0 === -Infinity 可用来区分。
BigInt(大整数)
  • 用于表示任意精度的整数,字面量以 n 结尾:123n
  • Number 不可混合运算(会抛出 TypeError),需要显式转换。
const a = 10n;
const b = 5n;
a + b; // 15n
// a + 1; // TypeError
String(字符串)
  • 用单引号、双引号或反引号(模板字符串)。
  • 字符串是不可变的(每次修改都会生成新字符串)。
Boolean(布尔)
  • 两个字面量:true / false
  • 有“真值/假值”概念(参见后文的 truthy/falsy)。
Symbol
  • 用于创建唯一且不可变的标识符,常用于对象属性键以避免命名冲突:
const id = Symbol('id');
const obj = {};
obj[id] = 1;
Null 与 Undefined
  • undefined:变量声明了但未赋值时的默认值;函数没有返回值时返回 undefined
  • null:表示“没有值”或“空值”,通常由程序员显式赋值表示“故意没有值”。
  • typeof null === "object"(历史遗留问题)。
Object(对象)
  • 键值对集合。键(property)可以是字符串或 Symbol(非 Number,数字键会被转为字符串)。
  • 对象可以包含函数(方法)。
  • 常见子类型:Array、Function、Date、RegExp、Map、Set、Promise 等。

常见类型细节与陷阱

相等比较:== vs ===

这个算是大坑了,请注意,非常建议js中直接使用===而不是==,防止导致意外产生

  • ===(严格相等):不进行类型转换,类型不同直接为 false
  • ==(抽象相等):会发生类型转换,有复杂规则,容易导致意外。
0 == false;   // true
0 === false;  // false
'' == 0;      // true
null == undefined; // true
null === undefined; // false
NaN(不是数字)
  • NaN !== NaN(自己不等于自己)
  • Number.isNaN(x) 检测 NaN
  • isNaN(x) 会先尝试把 x 转为数,可能误判(例如 isNaN('hello') 为 true,因为 'hello' 转为数是 NaN)。
Truthy / Falsy(真值与假值)

在布尔上下文中(如 if&&||)下面的值被视为假(falsy),其余为真(truthy):

Falsy 值false, 0, -0, 0n(BigInt 0), ""(空字符串), null, undefined, NaN
其它 都是 truthy(包括空对象 {}、空数组 []

注意:

if ([]) console.log('[] 被视为 truthy'); // 会输出
if ({}) console.log('{} 也是 truthy'); // 会输出
属性访问:点(.) vs 方括号([]
  • 点语法:对象属性必须是有效标识符(不能是数字开头、有空格或特殊字符)。
  • 方括号语法:属性名可以是字符串表达式或变量,支持 Symbol 键。
const key = 'name';
obj[key]; // 通过变量访问
obj['first-name']; // 用方括号访问包含连字符的属性
克隆 / 合并(浅拷贝与深拷贝)
  • 浅拷贝(只拷贝第一层):Object.assign({}, obj){...obj}(展开运算符)
  • 深拷贝:JSON.parse(JSON.stringify(obj))(有局限性,无法复制函数、Symbol、undefined、循环引用),或使用递归/库(如 lodash 的 cloneDeep

常见数据结构(与用法)

Array(数组)
  • 用途:有序集合,索引从 0 开始。
  • 创建:
const a = []; 
const b = [1, 2, 3];
  • 常用方法:push, pop, shift, unshift, slice, splice, map, filter, reduce, forEach, find, findIndex
  • 遍历:forfor...of(元素),for...in(不推荐用于数组——会遍历可枚举属性)
  • 展开与拷贝:[...arr]
  • 注意:数组是对象,可以包含稀疏元素(如 const a = []; a[5] = 10;),长度属性自动更新。

示例:

const arr = [1, 2, 3];
arr.push(4); // [1,2,3,4]
const doubled = arr.map(x => x * 2); // [2,4,6,8]
Object(对象字面量)
  • 创建:{}new Object(),推荐字面量。
  • 属性访问:obj.keyobj['key']
  • 属性操作:Object.keys(obj), Object.values(obj), Object.entries(obj), Object.assign()
  • 属性描述符(高级):Object.defineProperty 可设置 writable, enumerable, configurable 等。

对象字面量新特性(ES6+):

  • 简写属性:{a} 等价 { a: a }
  • 方法简写:{ greet() { ... } }
  • 计算属性名:{ [keyName]: value }

示例:

const name = 'alice';
const obj = {name, // 简写greet() { console.log(`Hello ${this.name}`); } // 方法简写
};
Map(映射)
  • ES6 引入,键可以是任意类型(包括对象)。
  • 有序(按插入顺序)。
  • API:new Map(), map.set(k,v), map.get(k), map.has(k), map.delete(k), map.size
  • 遍历:for (const [k,v] of map) {}

使用场景:当你需要以对象为键或保证插入顺序并高效查找时,用 Map 比普通对象更合适。

Set(集合)
  • ES6 引入,保存唯一值(不重复)。
  • API:new Set(), add, has, delete, size
  • 常用于去重:
const unique = [...new Set([1,2,2,3])]; // [1,2,3]
WeakMap / WeakSet
  • 键(WeakMap)或值(WeakSet)是弱引用,允许垃圾回收(当没有其它引用时)——用于缓存或元数据,避免内存泄漏。
  • size,不可遍历(设计上就是为了隐私与 GC 性能)。
TypedArray(类型化数组)
  • 用于处理大量数值的高性能数组,例如 Int8Array, Uint8Array, Float32Array,常用于 WebGL、文件/二进制数据处理。
  • 与普通数组不同,元素类型固定、长度固定。
其他:Date、RegExp、Promise
  • Date 表示日期时间,注意时区与 Date 的构造字符串差异。
  • RegExp(正则)有字面量 /pattern/flags 与构造 new RegExp('pattern', 'g')
  • Promise 用于异步编程(then/catch/finally,以及 async/await 语法糖)。

字面量(Literals)详细介绍

字面量(literal)是直接写在代码里的固定值表达方式。JavaScript 中字面量形式很多,这里逐一说明并举例。

数字字面量(Numeric literals)

支持多种形式:

  • 十进制:123, 3.14, 0.5, .5
  • 科学计数法:1e3(等于 1000)
  • 十六进制:0xFF(255)
  • 二进制:0b1010(10)
  • 八进制:0o77(63)
  • 分隔符(从 ES2021):可用下划线 _ 改善可读性:1_000_000

例子:

const a = 255;     // 十进制
const b = 0xff;    // 十六进制
const c = 0b1010;  // 二进制
const d = 1_000;   // 可读性分隔符
字符串字面量(String literals)

三种括法:

  • 单引号:'hello'
  • 双引号:"hello"
  • 模板字符串(反引号):hello ${name},支持插值与多行字符串。

字符串常用操作:拼接、模板、长度、索引、slicesubstringreplacesplittoLowerCasetoUpperCase

模板字符串示例:

const name = 'Alice';
const msg = `Hello ${name}, today is ${new Date().toLocaleDateString()}`;
对象字面量(Object literals)

基本形式:

const obj = { a: 1, b: 2 };

高级写法:

  • 简写属性:{ a }
  • 方法简写:{ greet() {} }
  • 计算属性名:{ [key]: value }
  • 可定义 getter/setter:
const o = {_x: 1,get x() { return this._x; },set x(val) { this._x = val; }
};
数组字面量(Array literals)
const arr = [1, 2, 3];

数组解构赋值:

const [a, b] = [1, 2]; // a=1, b=2
const [first, ...rest] = [1,2,3,4]; // rest=[2,3,4]
正则字面量(RegExp literals)

两种创建方式:

  • 字面量:/ab+c/g
  • 构造器:new RegExp('ab+c', 'g') (当 pattern 动态生成时用构造器)

注意:正则字面量在函数或循环中被静态解析,可能被缓存,构造器每次都会创建新实例。

函数字面量(Function literal)
  • 函数声明:function foo() { }(不是字面量,但常见)
  • 函数表达式:const f = function() {}(可匿名)
  • 箭头函数(ES6):const f = (x) => x * 2(没有 thisarguments,不能作为构造函数)

箭头函数示例:

const squares = [1,2,3].map(x => x * x);
类字面量(Class)

类不是严格“字面量”,但可以用类声明或表达式:

class Person {constructor(name) { this.name = name; }greet() { console.log(this.name); }
}

常见问题速查与示例集合

1. 字符串拼接哪种更好?

推荐使用模板字符串:

const name = 'Alice';
const msg = `Hello, ${name}!`;
2. 如何复制数组 / 对象?

浅拷贝:

const arr2 = [...arr];
const obj2 = {...obj};

深拷贝(简单对象,不含函数/Symbol):

const deep = JSON.parse(JSON.stringify(obj));
3. 判断数组:
Array.isArray(x); // 推荐方法
4. 判断对象是否为空:
Object.keys(obj).length === 0;
5. 将类数组(arguments)转为数组:
const args = Array.from(arguments); // 或 [...arguments]
6. 去重数组:
const unique = [...new Set(arr)];
http://www.dtcms.com/a/594263.html

相关文章:

  • 做某网站的设计与实现深圳做网站制作
  • K8S中Ingress的使用
  • 怎么建立微信网站あかねさす少女免费
  • 基于单片机的多波形信号发生器设计
  • JAVA1110 反射 泛型
  • 设计网站大全软件网络营销有哪些功能
  • 余江网站建设河南郑州百姓网
  • 济南莱芜最新消息seo平台是什么意思
  • 银河麒麟高级服务器操作系统V10SP3 2403(X86)PXE服务端部署以及测试
  • 安徽建站优化哪里有八戒八戒在线观看免费完整版
  • 远距离视频传输无线模块:打破空间限制的未来科技
  • Linux网络编程—网络基础概念
  • 硬件基础知识-电容(一)
  • 做网站需要多少钱怎么做网站的百度收录
  • 什么软件可以做网站百度站长平台怎么验证网站
  • 网站建设定制网络营销方式哪些?
  • Python | range数据类型、for循环及应用方式
  • 怎么仿一个复杂的网站wordpress怎么写时间轴
  • HTML5 表单属性详解
  • 官网国产化改造,为何首选PageAdmin CMS?
  • 传感器监测精度:压电 / 温度传感器对心率 / 呼吸信号的捕捉效率测试
  • 十堰优化网站哪家好有免费做推广的网站吗
  • 网站空间如何续费南昌企业建站系统
  • 底层视觉及图像增强-项目实践(十六-0-(4):从“调屏经验”到“AI慧眼【神经网络、卷积】”的思维跃迁):从奥运大屏,到手机小屏,快来挖一挖里面都有什么
  • dede网站安全东莞金融网站建设
  • 网站页面设计尺寸彩云小梦ai写作网站
  • 培训考试系统源码重要吗
  • Swift-GCD和NSOperation
  • 移动硬盘安装Ubuntu系统——Ubuntu与Windows时间不一致(详细版)_002
  • 【计算思维】蓝桥杯STEMA 科技素养考试真题及解析 3