JavaScript学习笔记

发布于:2025-06-16 ⋅ 阅读:(20) ⋅ 点赞:(0)

JS基础

检测当前运行环境

console.log(typeof window === 'undefined' ? 'Node' : 'Browser');

进阶做法:用 globalThis

console.log(globalThis.window ? 'Browser' : 'Node');

globalThis 是所有环境都存在的统一顶级对象;在 Node 里 globalThis.windowundefined,在浏览器里指向 window 本身。

浏览器端 JavaScript组成:(3个部分)

组成 作用 核心接口 Demo
ECMAScript 语言本体 (语法 + 内建对象) Array, Promise Math.random()
DOM (Document Object Model) 操作页面元素 document.querySelector, Element.classList js document.body.style.background='lavender';
BOM (Browser Object Model) 操作浏览器窗口/历史/地址 location, history, navigator js alert(location.href);
Node Demo:读文件并返回大小
//  size.js
//运行命令 :node size.js Test111.txt
import { statSync } from 'fs';
import { resolve } from 'path';

const file = resolve(process.argv[2]);
const { size } = statSync(file);
console.log(`File size: ${size} bytes`);

输出:

File size: 57 bytes

文件不存在

node size.js nofile.txt

会抛出错误并终止执行:

Error: ENOENT: no such file or directory, stat '/F:zyx/nofile.txt'

未提供参数 (process.argv[2]undefined就会有这个问题)

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined

JS语法

变量声明 let / const / var

要点:

  • letconst 拥有块级作用域,存在「暂时性死区」(TDZ),禁止在声明前访问。

  • const 声明后不可重新赋值,但若值是对象,其属性仍可变。

  • var 具函数作用域并会变量提升,容易造成混淆,通常仅维护旧代码时使用。

{
  console.log(typeof value);   // ⚠️ ReferenceError(TDZ),这就是在声明之前访问了,声明在下一句!
  let value = 42;
  const PI = 3.1416;
  // PI = 3;       // ⚠️ TypeError: Assignment to constant variable
}

在进入花括号后,value 处于 TDZ,尝试访问即抛错。

PI 一旦赋值后不可再次赋值。

输出:(TDZ声明前访问)

ReferenceError: Cannot access 'value' before initialization

数据类型

要点:

  • 基本数据类型:number (含 NaNInfinity)、stringbooleanundefinednullsymbolbigint
  • 引用数据类型:ObjectArrayFunction、自定义对象……)
  • 注意:内置对象 Function、Array、Date、RegExp、Error 等都是属于 Object 类型。也就是说,除了那七种基本数据类型之外,其他的,都称之为 Object 类型。
console.log(typeof null);       // 为何是 "object"?
console.log(typeof 10n);        // "bigint"
console.log(typeof Symbol());   // "symbol"

早期实现遗留导致 typeof null 返回 "object"

Symbol() 生成独一无二的标识符,用于对象私有键。

基本数据类型举例

var a = 23;
var b = a;

a++;

console.log(a); // 打印结果:24
console.log(b); // 打印结果:23

a 和 b 都是基本数据类型,让 b 等于 a,然后改变 a 的值之后,发现 b 的值并没有被改变

引用数据类型举例

var obj1 = new Object();
obj1.name = 'smyh';

// 让 obj2 等于 obj1
var obj2 = obj1;

// 修改 obj1 的 name 属性
obj1.name = 'vae';

console.log(obj1.name); // 打印结果:vae
console.log(obj2.name); // 打印结果:vae

obj1 和 obj2 都是引用数据类型,让 obj2 等于 obj1,然后修改 obj1.name 的值之后,发现 obj2.name 的值也发生了改变

栈内存和堆内存

JS 中,所有的变量都是保存在栈内存中的。

基本数据类型

基本数据类型的值,**直接保存在栈内存中。**值与值之间是独立存在,修改一个变量不会影响其他的变量。

引用数据类型

对象是保存到堆内存中的。每创建一个新的对象,就会在堆内存中开辟出一个新的空间;而变量保存了对象的内存地址(对象的引用),保存在栈内存当中。如果两个变量保存了同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。

这一点和py是很像的。

Undefined:未定义类型

Undefined 类型的值只有一个,就是 undefind。比如 var a = undefined

使用 typeof 检查一个 undefined 值时,会返回 undefined。

undefined 的出现有以下几种情况:

  • 变量已声明,未赋值(未初始化),一个变量如果只声明了,但没有赋值,此时它的值就是 undefined
  • 变量未声明(未定义),如果你从未声明一个变量,就去使用它,则会报错(这个大家都知道);此时,如果用 typeof 检查这个变量时,会返回 undefined
  • 函数无返回值时(在定义一个函数时,如果末尾没有 return 语句,那么,其实就是 return undefined。)
  • 调用函数时,未传参

调用函数时,如果没有传实参,那么,对应形参的值就是 undefined。

function foo(name) {
    console.log(name);
}

foo(); // 调用函数时,未传参。执行函数后的打印结果:undefined

实际开发中,如果调用函数时没有传参,我们可以根据需要给形参设置一个默认值:

function foo(name) {
    name = name || 'qianguyihao';
}

foo();

等学习了 ES6 之后,上方代码也可以这样写:

function foo(name = 'qianguyihao') {}

foo();
Null:空对象

如果你想定义一个变量用来保存引用类型(也就是对象),但是还不确定放什么内容,这个时候,可以在初始化时将其赋值为 null。

从语义上讲,null表示一个空对象,所以使用 typeof 检查一个 null 值时,会返回 object。举例:

var myObj = null;
cosole.log(typeof myObj); // 打印结果:object

undefined 实际上是由 null 衍生出来的,所以null == undefined的结果为 true。null === undefined 的结果是 false。它们虽然相似,但还是有区别的,其中一个区别是,和数字运算时:

  • 10 + null 结果为 10。
  • 10 + undefined 结果为 NaN。

运算符

  • 算数:+ - * / % **
  • 比较:=== !== > < >= <=(务必用全等 ===
  • 逻辑:&& || !,含短路行为
  • 三元:condition ? A : B
  • 模板字符串:用反引号 ```, 可内插 ${…}

Demo

const score = 75;
const ok = score > 60 ? 'pass' : 'fail';
const msg = `Result: ${ok}, score = ${score}`;
console.log(msg);
  • score > 60 为真,三元返回 'pass'
  • 模板字符串直接插入变量,无需拼接。

输出

Result: pass, score = 75

流程控制

条件:if…else, switch

循环:for(索引)、for…in(枚举键)、for…of(遍历可迭代对象)

break / continue 控制跳出或跳过。

Demo

const arr = ['a', 'b', 'c'];
for (const val of arr) {
  if (val === 'b') continue;
  console.log(val);          // 打印 'a' 和 'c'
}
  • for…of 直接拿值;当遇到 'b'continue 跳过本轮。

输出

a
c

函数

  • 声明式:有函数提升
  • 表达式 / 箭头函数:在赋值后才能调用
  • 默认参数与剩余参数 ...args
  • 箭头函数不绑定自己的 this / arguments

Demo

const sum = (...ns) => ns.reduce((a, b) => a + b, 0);
console.log(sum(1, 2, 3, 4));    // 10

解释

  • ...ns 收集任意个参数生成数组。
  • reduce 累加得到总和。

输出

10

作用域与闭包

  • JS 使用词法作用域(静态作用域)
  • 闭包 = 函数 + 其引用的外部变量,即便外部函数已返回。

Demo

function makeCounter() {
  let count = 0;
  return () => ++count;
}

const inc = makeCounter();
console.log(inc()); // 1
console.log(inc()); // 2
  • inc 始终持有对 count 的引用形成闭包,累加状态得以保留。

输出

1
2

对象

  • 字面量简写:{x} 等价于 {x: x}
  • 计算属性:['prop' + i]: value
  • 方法简写:say() {}
  • 可选链:obj?.child?.name 防止空值报错。

Demo

const x = 5;
const o = {
  x,                    // 简写
  ['y' + 1]: 6,         // 计算属性名 y1
  say() { return this.x }
};
console.log(o.y1, o.say()); // 6 5

输出

6 5

数组

  • 高阶函数:map, filter, reduce
  • 解构、扩展 ...
  • Array.isArray(obj) 判断。

Demo

const raw = [1, 2, 3, 4];
const squares = raw.map(n => n ** 2);     // [1,4,9,16]
const evens = raw.filter(n => n % 2 === 0); // [2,4]
const total = raw.reduce((a, b) => a + b, 0); // 10
const [head, ...rest] = raw; // 解构
console.log(squares, evens, total, head, rest);

输出

[ 1, 4, 9, 16 ] [ 2, 4 ] 10 1 [ 2, 3, 4 ]

模块化

  • ES Module(浏览器 / Node ≥ v14 原生支持)
    • export const foo = …; / export default …;
    • import foo, { bar } from './lib.js';
  • CommonJS(旧版 Node)
    • module.exports = …; / const foo = require('./lib');

Demo (ESM)

// math.js
export const add = (a, b) => a + b;

// main.mjs
import { add } from './math.js';
console.log(add(2, 3));   // 5

输出

5

异步基础

  • 回调 → Promiseasync/await 是演进路线。
  • 静态方法:Promise.all, Promise.race
  • await 只能在 async 函数或顶级 module 中使用。

Demo

function delay(ms) {
  return new Promise(res => setTimeout(res, ms));
}

(async () => {
  console.time('t');
  await delay(500);
  console.timeEnd('t');      // ≈ 500ms
})();
  • delay 返回在指定毫秒后解决的 Promise。
  • await 暂停执行,确保时序易读。

输出

t: 500.XXXms

错误处理

  • try / catch / finally 捕获同步 & await 抛出的异常。
  • 自定义错误类继承 Error

Demo

class BadInputError extends Error {
  constructor(msg) { super(msg); this.name = 'BadInputError'; }
}

function parseJson(str) {
  if (typeof str !== 'string') throw new BadInputError('Need string');
  return JSON.parse(str);
}

try {
  parseJson(42);
} catch (e) {
  console.error(e.name, e.message);   // BadInputError Need string
} finally {
  console.log('done');
}

输出

BadInputError Need string
done

网站公告

今日签到

点亮在社区的每一天
去签到