欢迎光临
我们一直在努力

JavaScript 学习文档(二)

1.JavaScript 基础语法

目录

1.JavaScript 基础语法

变量声明:给数据贴上“标签”

三种声明方式:let、const、var

数据类型:容器里能装什么?

1. 基本类型(值类型):存储的是实际的值

2. 引用类型:存储的是对内存中对象的引用(地址)

3. 基本类型包装对象

4. 类型检测:如何知道一个值是什么类型?

5. 类型转换:数据之间的“变身”术

隐式转换(自动转换)

显式转换(手动转换)

6. ToPrimitive 抽象操作(对象转原始类型)

运算符:对数据进行操作的符号

1. 算术运算符

2. 比较运算符

3. 逻辑运算符

4. 位运算符(直接操作整数在内存中的二进制位)

5. 赋值运算符与复合赋值

控制流:决定代码的执行顺序

1. 条件语句:根据条件选择执行不同的代码

iif…else if…else 语句

三元运算符(条件运算符):简化版的if…else

2. 循环与迭代:重复执行某段代码

基本循环

for循环:适合已知循环次数的情况

while循环:适合不确定循环次数,只关注循环条件的情况

do…while循环:至少会执行一次代码块

循环控制:break 和 continue

break、continue 和 return 的区别

高级迭代循环

for…in循环:遍历对象的可枚举属性(包括原型链上的)

for…of循环:遍历可迭代对象(数组、字符串、Map、Set等)的值

for…in vs for…of

函数基础:可重复使用的代码块

1. 函数声明与函数表达式

函数声明:会提升(可以在声明前调用)

函数表达式:不会提升,必须先定义后调用

箭头函数(ES6新增):更简洁的函数表达式语法

函数声明提升 vs 函数表达式不提升

2. 箭头函数

无参数:必须使用圆括号

单个参数:可以省略圆括号

多个参数:必须使用圆括号

函数体有多条语句:必须使用大括号

返回对象字面量:需要用小括号包裹对象

箭头函数的this指向问题

3. 参数:传递给函数的输入

默认参数(ES6)

剩余参数(ES6):收集不定数量的参数到一个数组中

命名参数(通过对象解构实现)

4. 返回值与递归

递归的基本要素

基准条件(Base Case)

递归条件(Recursive Case)

递归的注意事项

基本代码规范与注释风格

1. 代码风格建议

2. 注释风格

单行注释示例

多行注释示例

JSDoc风格注释示例(推荐用于函数)

注意事项


变量声明:给数据贴上“标签”

变量就像一个容器或一个标签,用来存储各种信息(数字、文字、复杂对象等),方便在程序中反复使用和修改。

声明一个变量,就像创建一个带名字的盒子,你可以在里面放东西,也可以随时更换。

三种声明方式:let、const、var

声明方式

特点

一句话理解

适用场景

let

块级作用域,可重复赋值,不允许重复声明,存在暂时性死区csdn.net

像一次性贴纸,贴上后可以撕下来重贴,但不能在同一位置贴两次。

当你需要一个值会改变的变量时。

const

块级作用域,声明后必须立即赋值,不能再重新赋值(基本类型),属性可以修改(引用类型),不允许重复声明,存在暂时性死区csdn.net

像带锁的保险箱,一旦锁上(声明并赋值),就不能再换别的东西,但箱子里的文件(属性)还是可以改的。

当你需要一个常量,或者一个不会改变引用但内容可变的变量(如对象、数组)时。

var

函数作用域,可重复声明,变量提升(在声明前可用,值为undefined),没有块级作用域

像老式黑板,可以随意擦写,但在任何地方都能看到它(作用域),且可能会出现写之前先擦的情况(变量提升)。

现代开发中尽量避免使用,主要存在于老旧代码中。

默认使用 const,当需要重新赋值时再使用 let,尽量避免使用 var。

这样能避免许多潜在的作用域问题,让代码更安全、更易读。

数据类型:容器里能装什么?

JavaScript 的数据类型分为两大类:基本类型和引用类型。

这决定了数据在内存中如何存储和操作。

1. 基本类型(值类型):存储的是实际的值

类型

描述

示例

注意

Undefined

变量已声明但未赋值

let a; console.log(a); // undefined

表示缺少值

Null

表示一个空的、不存在的对象引用

let b = null; console.log(b); // null

表示有意为之的空值

Boolean

布尔值,表示真或假

let isTrue = true; let isFalse = false;

主要用于条件判断

Number

数字(整数或浮点数)

let age = 25; let price = 3.14;

Infinity(无穷大)、-Infinity(无穷小)、NaNNot a Number,非数值)

BigInt

ES2020新增,用于表示任意大的整数

let bigNum = 9007199254740991n;

数字末尾加 n,或使用 BigInt() 构造函数

String

字符串(文本),用单引号'、双引号"或反引号`包裹

let name = 'Alice'; let message = "Hello";

转义字符:\\n换行、\\t制表符、\\\\反斜杠本身、\\'单引号等

Symbol

ES6新增,表示独一无二的值

let sym = Symbol('description');

常用于对象属性名,防止冲突

2. 引用类型:存储的是对内存中对象的引用(地址)

类型

描述

示例

Object

对象,包含属性和方法的集合

let person = { name: 'Bob', age: 30 };

Array

数组,有序的列表,可存储任意类型数据

let colors = ['red', 'green', 'blue'];

Function

函数,一段可重复执行的代码块

function greet() { console.log('Hi!'); }

3. 基本类型包装对象

当你尝试对基本类型值(如字符串、数字、布尔值)调用方法或访问属性时,JavaScript 会临时创建一个包装对象,操作完成后立即销毁。

这是为了方便地操作基本类型。

let str = "hello";

console.log(str.length); // 5

// 临时创建了 String 包装对象,访问了 length 属性,然后销毁

let num = 123.456;

console.log(num.toFixed(2)); // "123.46"

// 临时创建了 Number 包装对象,调用了 toFixed() 方法,然后销毁

let bool = true;

console.log(bool.toString()); // "true"

// 临时创建了 Boolean 包装对象,调用了 toString() 方法,然后销毁

⚠️ 注意:不要手动创建包装对象(如 new String("text")),这会导致类型判断混乱(typeof new String("text") 返回 "object",而 typeof "text" 返回 "string")。直接使用基本类型值即可,JavaScript 会自动处理包装。

4. 类型检测:如何知道一个值是什么类型?

方法

描述

返回值示例

适用场景

typeof

返回一个字符串,表示操作数的数据类型csdn.net

typeof 42 → "number" typeof "Hello" → "string" typeof true → "boolean" typeof undefined → "undefined" typeof null → "object" (历史遗留问题) typeof Symbol('sym') → "symbol" typeof 123n → "bigint" typeof {} → "object" typeof [] → "object" typeof function(){} → "function"

快速判断基本类型(除 null 外)和函数。

instanceof

检查构造函数的 prototype 属性是否出现在对象的原型链中csdn.net

[] instanceof Array → true {} instanceof Object → true function(){} instanceof Function → true new Date() instanceof Date → true

判断引用类型的具体类型(如数组、日期、自定义对象实例)。

Object.prototype.toString.call()

返回一个表示该对象的字符串,格式为 "[object Type]"segmentfault.com+2

Object.prototype.toString.call([]) → "[object Array]" Object.prototype.toString.call({}) → "[object Object]" Object.prototype.toString.call(null) → "[object Null]" Object.prototype.toString.call(undefined) → "[object Undefined]" Object.prototype.toString.call(123) → "[object Number]"

最准确、最可靠的类型检测方法,能准确区分所有内置类型和自定义类型。

类型检测示例

let num = 42;

let str = "Hello";

let bool = true;

let und = undefined;

let nul = null;

let obj = {};

let arr = [];

let func = function(){};

let date = new Date();

typeof

console.log(typeof num); // "number"

console.log(typeof str); // "string"

console.log(typeof bool); // "boolean"

console.log(typeof und); // "undefined"

console.log(typeof nul); // "object" (注意这个历史遗留问题)

console.log(typeof obj); // "object"

console.log(typeof arr); // "object"

console.log(typeof func); // "function"

instanceof

console.log(arr instanceof Array); // true

console.log(obj instanceof Object); // true

console.log(date instanceof Date); // true

Object.prototype.toString.call() 

console.log(Object.prototype.toString.call(num)); // "[object Number]"

console.log(Object.prototype.toString.call(str)); // "[object String]"

console.log(Object.prototype.toString.call(bool)); // "[object Boolean]"

console.log(Object.prototype.toString.call(und)); // "[object Undefined]"

console.log(Object.prototype.toString.call(nul)); // "[object Null]"

console.log(Object.prototype.toString.call(arr)); // "[object Array]"

console.log(Object.prototype.toString.call(obj)); // "[object Object]"

console.log(Object.prototype.toString.call(func)); // "[object Function]"

console.log(Object.prototype.toString.call(date)); // "[object Date]"

5. 类型转换:数据之间的“变身”术

隐式转换(自动转换)

场景

转换规则

示例

算术运算(除+外)

将非Number类型转换为Number

'10' – 5 → 5 (字符串转数字) '10' * 2 → 20 (字符串转数字) true – 1 → 0 (布尔转数字true=1) null – 1 → -1 (null转数字null=0) undefined – 1 → NaN (undefined转数字undefined=NaN)

+ 运算

字符串拼接优先:如果一侧是String,则另一侧也转为String进行拼接;否则进行数值相加

'1' + 1 → '11' (字符串拼接) 1 + true → 2 (true转数字1) 1 + null → 1 (null转数字0) 1 + undefined → NaN (undefined转数字NaN) '1' + '1' → '11' (字符串拼接) 1 + 1 → 2 (数值相加)

== 比较

先进行类型转换,再比较值(但不推荐使用,推荐使用===

1 == '1' → true (字符串转数字) null == undefined → true (它们被视为相等) 0 == false → true (false转数字0) '' == false → true (空字符串转数字0, false转数字0) [] == 0 → true (数组转数字0)

这就像一个“自动翻译器”,在不同类型的值进行运算或比较时,它会自动将它们转换为同一类型。

但有时会“翻译错”,导致意想不到的结果。

显式转换(手动转换)

方法

描述

示例

Number()

将值转换为数字

Number('123') → 123 Number('123abc') → NaN (无法转换) Number('') → 0 (空字符串转0) Number(true) → 1 Number(false) → 0 Number(null) → 0 Number(undefined) → NaN

String()

将值转换为字符串

String(123) → "123" String(true) → "true" String(null) → "null" String(undefined) → "undefined" String({}) → "[object Object]" String([1,2,3]) → "1,2,3"

Boolean()

将值转换为布尔值

Boolean(123) → true Boolean('hello') → true Boolean([]) → true Boolean({}) → true Boolean(0) → false Boolean('') → false Boolean(null) → false Boolean(undefined) → false Boolean(NaN) → false Boolean(false) → false

parseInt() / parseFloat()

从字符串中解析出整数或浮点数

parseInt('123abc') → 123 parseFloat('123.45abc') → 123.45 parseInt('abc123') → NaN (开头无法解析) parseInt('10', 2) → 2 (第二个参数是进制,解析二进制字符串)

toString()

将值转换为字符串(除null/undefined外)

(123).toString() → "123" true.toString() → "true" [1,2,3].toString() → "1,2,3" {}.toString() → "[object Object]" // null.toString() // 报错 // undefined.toString() // 报错

这就像“手动指定翻译目标”,更可控、更安全。

隐式转换示例

console.log(5 + '5'); // "55" (字符串拼接)

console.log(5 – '5'); // 0 (数值相减)

console.log('10' > '2'); // false (字符串比较,按字典序)

console.log(10 > '2'); // true (数字比较,字符串转数字)

console.log(null == undefined); // true

console.log(0 == false); // true

console.log('' == false); // true

显式转换示例

console.log(String(123)); // "123"

console.log(Number('123')); // 123

console.log(Boolean('hello')); // true

console.log(parseInt('123abc')); // 123

console.log(parseFloat('123.45abc')); // 123.45

console.log((123).toString()); // "123"

6. ToPrimitive 抽象操作(对象转原始类型)

当对象需要转换为原始类型(数字、字符串、布尔)时,JavaScript 会调用内部的 ToPrimitive 抽象操作。

其规则如下:

如果对象有 Symbol.toPrimitive 方法,优先调用该方法。

否则,根据预期类型(hint):

  • Hint "number"(如数学运算)
  • 先调用 valueOf(),如果返回原始值则使用;
  • 否则调用 toString(),如果返回原始值则使用;
  • 否则报错。
    • Hint "string"(如字符串拼接)
  • 先调用 toString(),如果返回原始值则使用;
  • 否则调用 valueOf(),如果返回原始值则使用;
  • 否则报错。
  • const obj = {

      valueOf() { return 10; },

      toString() { return '20'; }

    };

    console.log(obj + 5); // 15 (hint为"number",使用valueOf返回的10)

    console.log(String(obj)); // "20" (hint为"string",使用toString返回的"20")

    运算符:对数据进行操作的符号

    运算符就像“操作员”,对变量和值进行操作并产生结果。

    1. 算术运算符

    运算符

    描述

    示例

    +

    加法 / 字符串拼接

    10 + 5 → 15 'Hello' + ' World' → 'Hello World'

    减法

    10 – 5 → 5

    *

    乘法

    10 * 5 → 50

    /

    除法

    10 / 5 → 2

    %

    取模(求余数)

    10 % 3 → 1 (10除以31)

    ++

    自增(i++ 是先使用再加1++i 是先加1再使用)

    let i = 5; console.log(i++); // 5 let j = 5; console.log(++j); // 6

    自减(i– 是先使用再减1–i 是先减1再使用)

    let i = 5; console.log(i–); // 5 let j = 5; console.log(–j); // 4

    2. 比较运算符

    运算符

    描述

    示例

    ==

    相等(会进行类型转换,不推荐使用)

    5 == '5' → true

    ===

    严格相等(不进行类型转换,推荐使用)

    5 === '5' → false 5 === 5 → true

    !=

    不相等(会进行类型转换)

    5 != '5' → false

    !==

    严格不相等(不进行类型转换)

    5 !== '5' → true 5 !== 5 → false

    >

    大于

    10 > 5 → true

    <

    小于

    5 < 10 → true

    >=

    大于或等于

    10 >= 5 → true

    <=

    小于或等于

    5 <= 10 → true

    始终使用 === 和 !==,除非你非常明确自己需要隐式类型转换的行为。这能避免许多潜在的bug。

    3. 逻辑运算符

    运算符

    描述

    短路行为

    示例

    &&

    逻辑与(AND

    如果第一个操作数是假值,则返回第一个操作数;否则返回第二个操作数。

    true && true → true true && false → false 0 && 'hello' → 0 (0是假值,直接返回0) 'hello' && 'world' → 'world' (hello是真值,返回world)

    ||

    逻辑或(OR

    如果第一个操作数是真值,则返回第一个操作数;否则返回第二个操作数。

    true || false → true false || true → true 'hello' || 'world' → 'hello' (hello是真值,直接返回hello) '' || 'world' → 'world' (空字符串是假值,返回world)

    !

    逻辑非(NOT

    返回操作数的布尔取反值。

    !true → false !false → true !0 → true !'hello' → false

    ??

    空值合并运算符ES2020新增)

    如果左侧操作数是null  undefined,则返回右侧操作数;否则返回左侧操作数cnblogs.com+2

    null ?? 'default' → 'default' undefined ?? 'default' → 'default' 0 ?? 'default' → 0 (0不是nullundefined) '' ?? 'default' → '' (空字符串不是nullundefined) false ?? 'default' → false (false不是nullundefined)

    ?.

    可选链运算符ES2020新增)

    允许安全地访问嵌套对象属性,如果链中的任何引用是 null  undefined,则短路返回 undefined,而不会抛出错误cnblogs.com+2

    const adventurer = { name: 'Alice', cat: { name: 'Dinah' } }; adventurer.dog?.name → undefined (dog不存在,返回undefined,不报错) adventurer.someNonExistentMethod?.() → undefined (方法不存在,返回undefined,不报错)

    逻辑运算符的“短路”行为

    逻辑运算符的“短路”行为非常重要,它意味着:

    • &&:如果第一个操作数是假值,第二个操作数根本不会被求值(因为结果已经确定为假)。
    • ||:如果第一个操作数是真值,第二个操作数根本不会被求值(因为结果已经确定为真)。
    使用 || 设置默认值(但要注意0和空字符串会被认为是假值)

    function greet(name) {

      name = name || 'Guest'; // 如果name是假值(如'', 0, null, undefined),则使用'Guest'

      console.log('Hello, ' + name);

    }

    greet(); // Hello, Guest

    greet('Alice'); // Hello, Alice

    使用 ?? 更精确地设置默认值(只处理null和undefined)

    function greet(name) {

      name = name ?? 'Guest'; // 只有当name是null或undefined时,才使用'Guest'

      console.log('Hello, ' + name);

    }

    greet(); // Hello, Guest

    greet(''); // Hello,  (空字符串被保留)

    greet(0); // Hello, 0 (数字0被保留)

    4. 位运算符(直接操作整数在内存中的二进制位)

    运算符

    描述

    示例

    &

    按位与(AND

    5 & 3 → 1 (二进制: 101 & 011 = 001)

    |

    按位或(OR

    5 | 3 → 7 (二进制: 101 | 011 = 111)

    ^

    按位异或(XOR

    5 ^ 3 → 6 (二进制: 101 ^ 011 = 110)

    ~

    按位非(NOT

    ~5 → -6 (二进制取反)

    <<

    左移(各二进位全部左移若干位)

    5 << 1 → 10 (二进制: 101 << 1 = 1010 = 十进制10)

    >>

    右移(各二进位全部右移若干位,正数高位补0,负数高位补1

    5 >> 1 → 2 (二进制: 101 >> 1 = 010 = 十进制2)

    >>>

    无符号右移(各二进位全部右移若干位,高位始终补0

    5 >>> 1 → 2 (二进制: 101 >>> 1 = 010 = 十进制2)

    注意:位运算符会将操作数转换为32位整数,然后进行操作,结果也是一个32位整数。对于非常大的数字,这可能会导致精度丢失。位运算符主要用于底层操作、性能优化等场景。

    5. 赋值运算符与复合赋值

    运算符

    描述

    等同于

    =

    赋值

    let x = 10;

    +=

    加并赋值

    x += 5 → x = x + 5

    -=

    减并赋值

    x -= 5 → x = x – 5

    *=

    乘并赋值

    x *= 5 → x = x * 5

    /=

    除并赋值

    x /= 5 → x = x / 5

    %=

    取模并赋值

    x %= 5 → x = x % 5

    **=

    幂并赋值(ES6

    x **= 2 → x = x ** 2

    <<=

    左移并赋值

    x <<= 2 → x = x << 2

    >>=

    右移并赋值

    x >>= 2 → x = x >> 2

    >>>=

    无符号右移并赋值

    x >>>= 2 → x = x >>> 2

    &=

    按位与并赋值

    x &= 3 → x = x & 3

    |=

    按位或并赋值

    x |= 3 → x = x | 3

    ^=

    按位异或并赋值

    x ^= 3 → x = x ^ 3

    let x = 10;

    x += 5; // x = 10 + 5 = 15

    x = 2; // x = 15  2 = 30

    console.log(x); // 30

    控制流:决定代码的执行顺序

    控制流语句就像“交通指挥灯”或“岔路口的指示牌”,决定代码执行哪条路径。

    1. 条件语句:根据条件选择执行不同的代码

    if…else if…else 语句

    let score = 85;

    if (score >= 90) {

      console.log('优秀!');

    } else if (score >= 80) {

      console.log('良好!'); // 输出这个

    } else if (score >= 60) {

      console.log('及格!');

    } else {

      console.log('不及格!');

    }

    三元运算符(条件运算符):简化版的if…else

    // 条件 ? 表达式1 (条件为真时执行) : 表达式2 (条件为假时执行)

    let grade = score >= 60 ? '及格' : '不及格';

    console.log(grade); // "及格"

    // switch 语句:用于基于不同条件执行不同代码(特别适合枚举值)

    let day = 'Monday';

    switch (day) {

      case 'Monday':

        console.log('星期一');

        break; // 遇到break则跳出switch,继续执行后面的代码

      case 'Tuesday':

        console.log('星期二');

        break;

      case 'Wednesday':

        console.log('星期三');

        break;

      default: // 相当于else

        console.log('其他');

    }

    2. 循环与迭代:重复执行某段代码

    循环就像“唱片机或跑步机,反复做同一件事。

    基本循环
    for循环:适合已知循环次数的情况

    for (let i = 0; i < 5; i++) {

      console.log('for循环:当前数字是:' + i);

    }

    // 输出:

    // for循环:当前数字是:0

    // for循环:当前数字是:1

    // for循环:当前数字是:2

    // for循环:当前数字是:3

    // for循环:当前数字是:4

    while循环:适合不确定循环次数,只关注循环条件的情况

    let j = 0;

    while (j < 3) {

      console.log('while循环:' + j);

      j++;

    }

    // 输出:

    // while循环:0

    // while循环:1

    // while循环:2

    do…while循环:至少会执行一次代码块

    let k = 0;

    do {

      console.log('do-while循环:' + k);

      k++;

    } while (k < 3);

    // 输出:

    // do-while循环:0

    // do-while循环:1

    // do-while循环:2

    循环控制:break 和 continue

    语句

    作用

    适用循环

    示例

    break

    立即终止当前循环csdn.net+1

    for, while, do…while, for…in, for…of

    javascript for (let i = 0; i < 10; i++) { if (i === 5) { break; // i等于5时,终止循环 } console.log(i); } // 输出: 0, 1, 2, 3, 4

    continue

    跳过当前循环迭代的剩余代码,立即开始下一次迭代csdn.net+1

    for, while, do…while, for…in, for…of

    javascript for (let i = 0; i < 5; i++) { if (i % 2 === 0) { continue; // i是偶数时,跳过当前迭代 } console.log(i); } // 输出: 1, 3

    break、continue 和 return 的区别

    语句

    作用范围

    示例

    break

    终止当前循环switch语句

    javascript for (let i = 0; i < 10; i++) { if (i === 5) { break; // 终止循环 } console.log(i); }

    continue

    跳过当前循环迭代

    javascript for (let i = 0; i < 5; i++) { if (i % 2 === 0) { continue; // 跳过当前迭代 } console.log(i); }

    return

    从函数中返回一个值,并终止函数的执行(如果在循环中,也会终止整个函数)csdn.net

    javascript function findFirstPositive(numbers) { for (let i = 0; i < numbers.length; i++) { if (numbers[i] > 0) { return numbers[i]; // 找到第一个正数,立即返回并终止函数 } } return -1; }

    break和continue只影响当前所在的循环。

    如果存在嵌套循环,它们只影响包含它们的那一层循环。

    // 嵌套循环中的break和continue

    for (let i = 0; i < 2; i++) {

      console.log('外层循环 i:', i);

      for (let j = 0; j < 3; j++) {

        if (j === 1) {

          break; // 只终止内层循环

        }

        console.log('  内层循环 j:', j);

      }

    }

    // 输出:

    // 外层循环 i: 0

    //   内层循环 j: 0

    // 外层循环 i: 1

    //   内层循环 j: 0

    高级迭代循环
    for…in循环:遍历对象的可枚举属性(包括原型链上的)

    // 注意:不推荐用于遍历数组,顺序可能不保证

    const person = {

      name: 'Alice',

      age: 30,

      job: 'Developer'

    };

    for (const key in person) {

      console.log(key + ': ' + person[key]);

    }

    // 输出:

    // name: Alice

    // age: 30

    // job: Developer

    for…of循环:遍历可迭代对象(数组、字符串、Map、Set等)的值

    // 注意:不能遍历普通对象

    const colors = ['red', 'green', 'blue'];

    for (const color of colors) {

      console.log(color);

    }

    // 输出:

    // red

    // green

    // blue

    // 遍历字符串

    const str = "hello";

    for (const char of str) {

      console.log(char);

    }

    // 输出:

    // h

    // e

    // l

    // l

    // o

    for…in vs for…of

    特性

    for…in

    for…of

    遍历目标

    对象的可枚举属性(键)

    可迭代对象的值(如数组、字符串、MapSetargumentsNodeList等)

    遍历内容

    key

    value

    适用场景

    遍历对象属性

    遍历数组、字符串等迭代器对象

    顺序

    不一定按顺序(对于数组)

    按顺序

    原型链

    会遍历原型链上的可枚举属性

    只遍历对象自身的可迭代属性

    示例

    javascript const obj = {a:1, b:2}; for (const key in obj) { console.log(key); // 输出: a, b }

    javascript const arr = [1, 2, 3]; for (const value of arr) { console.log(value); // 输出: 1, 2, 3 }

    • 遍历数组:for…of 或 forEach、map、filter 等数组方法;
    • 遍历对象:for…in 或 Object.keys()/Object.values()/Object.entries()。

    函数基础:可重复使用的代码块

    函数就像“机器”或“工具”,你给它一些输入(参数),它就经过内部处理,然后给你一个输出(返回值)。

    定义一次,可以多次调用,大大提高了代码的复用性和可维护性。

    1. 函数声明与函数表达式

    函数声明:会提升(可以在声明前调用)

    function sayHello(name) {

      console.log('Hello, ' + name + '!');

    }

    sayHello('Alice'); // Hello, Alice!

    函数表达式:不会提升,必须先定义后调用

    const sayGoodbye = function(name) {

      console.log('Goodbye, ' + name + '!');

    };

    sayGoodbye('Bob'); // Goodbye, Bob!

    箭头函数(ES6新增):更简洁的函数表达式语法

    特性

    箭头函数

    普通函数

    语法

    (params) => { statements }  param => expression

    function(params) { statements }

    this绑定

    没有自己的this,会捕获其所在上下文的thiscsdn.net+2

    有自己的this,取决于如何调用(谁调用它,this就指向谁)

    arguments对象

    没有arguments对象,可以使用剩余参数代替

    有自己的arguments对象

    new调用

    不能作为构造函数使用(不能用new调用)

    可以作为构造函数使用

    super调用

    没有super

    super(用于调用父类方法)

    yield

    不能使用yield关键字(不能用作生成器函数)

    可以使用yield(用作生成器函数)

    const sayHi = (name) => {

      console.log('Hi, ' + name + '!');

    };

    sayHi('Charlie'); // Hi, Charlie!

    函数声明提升 vs 函数表达式不提升

    函数声明会被“提升”到当前作用域的顶部,可以在函数声明之前调用它。

    sayHello(); // Hello! (可以调用)

    function sayHello() {

      console.log('Hello!');

    }

    函数表达式(包括箭头函数)不会被提升,必须先定义,然后才能调用。

    // sayGoodbye(); // ❌ 报错: sayGoodbye is not a function

    const sayGoodbye = function() {

      console.log('Goodbye!');

    };

    sayGoodbye(); // Goodbye!

    2. 箭头函数

    箭头函数是ES6引入的更简洁的函数书写方式,但它与普通函数也有一些重要区别。

    无参数:必须使用圆括号

    const greet = () => console.log('Hello!');

    单个参数:可以省略圆括号

    const double = num => num*2;

    多个参数:必须使用圆括号

    const add = (a, b) => a + b;

    函数体有多条语句:必须使用大括号

    const describe = (name, age) => {

      console.log('Name:', name);

      console.log('Age:', age);

    };

    返回对象字面量:需要用小括号包裹对象

    const createPerson = (name, age) => ({ name, age });

     // 等同于: return { name, age };

    箭头函数的this指向问题

    const person = {

      name: 'Alice',

      regularFunc: function() {

        console.log(this.name); // "Alice" (this指向person对象)

      },

      arrowFunc: () => {

        console.log(this.name); // undefined (this指向定义时的上下文,这里是全局或window,没有name属性)

      }

    };

    person.regularFunc(); // Alice

    person.arrowFunc(); // undefined

    3. 参数:传递给函数的输入

    默认参数(ES6)

    // 为参数设置默认值

    function greet(name = 'Guest', greeting = 'Hello') {

      console.log(greeting + ', ' + name + '!');

    }

    greet(); // Hello, Guest!

    greet('Alice'); // Hello, Alice!

    greet('Bob', 'Hi'); // Hi, Bob!

    剩余参数(ES6):收集不定数量的参数到一个数组中

    // 使用…args收集所有剩余参数

    function sum(…args) {

      return args.reduce((total, current) => total + current, 0);

    }

    console.log(sum(1, 2, 3)); // 6

    console.log(sum(1, 2, 3, 4, 5)); // 15

    // 剩余参数必须放在最后

    function describePerson(name, …hobbies) {

      console.log('Name:', name);

      console.log('Hobbies:', hobbies);

    }

    describePerson('Alice', 'reading', 'coding', 'traveling');

    // Name: Alice

    // Hobbies: [ 'reading', 'coding', 'traveling' ]

    命名参数(通过对象解构实现)

    // 通过对象解构实现命名参数,使代码更清晰

    function createUser({ name, age = 30, isAdmin = false }) {

      return {

        name,

        age,

        isAdmin

      };

    }

    const user = createUser({ name: 'Alice', age: 25 });

    console.log(user); // { name: 'Alice', age: 25, isAdmin: false }

    4. 返回值与递归

    // 函数返回值:如果没有显式返回,则返回undefined

    function add(a, b) {

      return a + b; // 返回计算结果

    }

    const sum = add(5, 3);

    console.log(sum); // 8

    // 没有return语句的函数

    function sayHello() {

      console.log('Hello!'); // 这条语句会执行

      // 没有return,隐式返回undefined

    }

    const result = sayHello();

    console.log(result); // undefined

    // 递归函数:函数调用自身

    function factorial(n) {

      if (n === 0 || n === 1) {

        return 1; // 基准条件:结束递归

      } else {

        return n  factorial(n – 1); // 递归条件:调用自身

      }

    }

    console.log(factorial(5)); // 120 (5  4  3  2  1)

    递归的基本要素
    基准条件(Base Case)

    一个或多个可以直接求解而无需递归的情况,用于终止递归。例如上面factorial函数中的n === 0 || n === 1。

    递归条件(Recursive Case)

    将问题分解为更小的、与原问题形式相同的问题,并调用自身来求解这些子问题。例如上面factorial函数中的n  factorial(n – 1)。

    递归的注意事项

    确保基准条件能够被触发,否则会导致无限递归,引发“栈溢出”(Stack Overflow)错误。

    递归调用的参数必须向基准条件逼近。

    // 无限递归的例子(会导致栈溢出)

    function infiniteRecursion() {

      return infiniteRecursion(); // 没有基准条件

    }

    // infiniteRecursion(); // ❌ RangeError: Maximum call stack size exceeded

    基本代码规范与注释风格

    代码规范就像“语法和拼写规则”,而注释就像“课文中的解释说明”。它们都为了让你的代码更容易被别人(以及未来的自己)理解和维护。

    1. 代码风格建议

    规则

    建议

    好的例子

    不好的例子

    缩进

    使用2个空格4个空格(不要混用Tab和空格

    javascript function add(a, b) { return a + b; }

    javascript function add(a,b){return a+b;}

    命名

    变量和函数使用驼峰命名法(camelCase);常量使用全大写+下划线UPPER_SNAKE_CASE);类使用帕斯卡命名法(PascalCase

    let userName = 'Alice'; const MAX_SIZE = 100; class UserService {}

    let user_name = 'Alice'; const maxsize = 100; class userService {}

    空行

    在函数之间、逻辑块之间添加空行,增加可读性

    javascript function a() {} <br><br> function b() {}

    javascript function a(){} function b(){}

    分号

    虽然JavaScript有自动分号插入(ASI机制,但建议始终使用分号,避免潜在问题

    javascript let x = 5;

    javascript let x = 5 (在某些情况下可能导致问题)

    字符串

    优先使用单引号(')或反引号(`),双引号也可以,但要保持一致

    javascript let str = 'hello';

    javascript let str = "hello" (混用)

    比较

    始终使用严格相等===和严格不相等!==

    javascript if (x === 5) {}

    javascript if (x == 5) {}

    大括号

    始终使用大括号包裹代码块,即使只有一条语句(不要省略大括号)

    javascript if (true) { console.log('yes'); }

    javascript if (true) console.log('yes');

    2. 注释风格

    单行注释示例

    let userName = 'Alice'; // 用户名

    多行注释示例

    /**

      *这是一个多行注释

      *可以写很多行

      *通常用于解释一段复杂的逻辑

    */

    JSDoc风格注释示例(推荐用于函数)

    /**

      * 根据用户ID获取用户信息

      * @param {number} userId – 用户ID

      * @returns {Object|null} 用户对象或null(如果未找到)

      * @example

      * const user = getUserById(1);

      * console.log(user.name); // 输出用户名

     */

    function getUserById(userId) {

      // …实现代码

    }

    注意事项
  • 解释“为什么”,而不是“是什么”(代码本身已经说了“是什么”)。
  • 保持注释最新,过时的注释比没有注释更糟糕。
  • 避免不必要的注释,如果代码本身已经很清晰,就不需要注释。
  • 对复杂的算法、临时解决方案、重要的业务逻辑进行注释。
  • 赞(0)
    未经允许不得转载:171主机测评 » JavaScript 学习文档(二)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址