JavaScript语法基础

语句和表达式

JavaScript程序由语句(statements)和表达式(expressions)组成:

// 语句:执行某个动作
let x = 5;           // 声明语句
if (x > 0) { }       // 条件语句
for (let i = 0; i < 10; i++) { } // 循环语句

// 表达式:产生值
5 + 3;               // 算术表达式,结果为8
x > 0;               // 比较表达式,结果为true或false
function() { return 42; }(); // 函数表达式,结果为42

分号和自动分号插入(ASI)

// 推荐:显式使用分号
let a = 1;
let b = 2;
console.log(a + b);

// JavaScript会自动插入分号,但可能导致意外结果
let c = 1
let d = 2
console.log(c + d)

// 危险的ASI示例
function getValue() {
  return  // ASI在这里插入分号
    42;   // 这行代码永远不会执行
}
console.log(getValue()); // undefined

// 正确写法
function getValue() {
  return 42;
}

注释

// 单行注释
let x = 5; // 行末注释

/*
多行注释
可以跨越多行
*/

/**
 * JSDoc注释
 * 用于文档生成
 * @param {number} a - 第一个参数
 * @param {number} b - 第二个参数
 * @returns {number} 两数之和
 */
function add(a, b) {
  return a + b;
}

标识符和关键字

// 有效的标识符
let myVariable;
let _privateVar;
let $element;
let userName2;
let 中文变量; // 支持Unicode

// 无效的标识符
// let 2variable;  // 不能以数字开头
// let my-variable; // 不能包含连字符
// let class;      // 不能使用关键字

// JavaScript关键字(不能用作标识符)
// break, case, catch, class, const, continue, debugger, default, delete,
// do, else, export, extends, finally, for, function, if, import, in,
// instanceof, let, new, return, super, switch, this, throw, try, typeof,
// var, void, while, with, yield

数据类型详解

原始数据类型

Number类型

// 整数
let integer = 42;
let negative = -17;
let octal = 0o755;      // 八进制
let hex = 0xFF;         // 十六进制
let binary = 0b1010;    // 二进制

// 浮点数
let float = 3.14;
let scientific = 2.5e6; // 2500000
let tiny = 1.23e-4;     // 0.000123

// 特殊数值
let infinity = Infinity;
let negInfinity = -Infinity;
let notANumber = NaN;

// 数值检查
console.log(Number.isInteger(42));     // true
console.log(Number.isNaN(NaN));        // true
console.log(Number.isFinite(42));      // true
console.log(Number.isFinite(Infinity)); // false

// 数值转换
console.log(Number('123'));    // 123
console.log(Number('123.45')); // 123.45
console.log(Number('abc'));    // NaN
console.log(parseInt('123px')); // 123
console.log(parseFloat('123.45px')); // 123.45

// 数值精度问题
console.log(0.1 + 0.2);        // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false

// 解决精度问题
function isEqual(a, b, epsilon = Number.EPSILON) {
  return Math.abs(a - b) < epsilon;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true

String类型

// 字符串字面量
let single = 'Hello';
let double = "World";
let template = `Hello, World!`;

// 字符串转义
let escaped = 'It\'s a beautiful day';
let newline = 'First line\nSecond line';
let tab = 'Column1\tColumn2';
let unicode = '\u4F60\u597D'; // "你好"

// 模板字符串
let name = 'Alice';
let age = 30;
let message = `Hello, my name is ${name} and I'm ${age} years old.`;

// 多行字符串
let multiline = `
  This is a
  multi-line
  string.
`;

// 标签模板
function highlight(strings, ...values) {
  return strings.reduce((result, string, i) => {
    const value = values[i] ? `<mark>${values[i]}</mark>` : '';
    return result + string + value;
  }, '');
}

let highlighted = highlight`Name: ${name}, Age: ${age}`;

// 字符串方法
let str = 'JavaScript';
console.log(str.length);           // 10
console.log(str.charAt(0));        // 'J'
console.log(str.charCodeAt(0));    // 74
console.log(str.indexOf('Script')); // 4
console.log(str.slice(0, 4));      // 'Java'
console.log(str.substring(0, 4));  // 'Java'
console.log(str.substr(0, 4));     // 'Java' (已废弃)
console.log(str.toLowerCase());     // 'javascript'
console.log(str.toUpperCase());    // 'JAVASCRIPT'

// 字符串搜索和替换
let text = 'The quick brown fox jumps over the lazy dog';
console.log(text.includes('fox'));     // true
console.log(text.startsWith('The'));   // true
console.log(text.endsWith('dog'));     // true
console.log(text.replace('fox', 'cat')); // 替换第一个匹配
console.log(text.replaceAll('the', 'a')); // 替换所有匹配

// 字符串分割和连接
let csv = 'apple,banana,orange';
let fruits = csv.split(',');       // ['apple', 'banana', 'orange']
let joined = fruits.join(' | ');   // 'apple | banana | orange'

// 字符串填充
let num = '5';
console.log(num.padStart(3, '0')); // '005'
console.log(num.padEnd(3, '0'));   // '500'

// 字符串修剪
let whitespace = '  hello world  ';
console.log(whitespace.trim());      // 'hello world'
console.log(whitespace.trimStart()); // 'hello world  '
console.log(whitespace.trimEnd());   // '  hello world'

Boolean类型

// 布尔字面量
let isTrue = true;
let isFalse = false;

// 布尔转换
console.log(Boolean(1));        // true
console.log(Boolean(0));        // false
console.log(Boolean('hello'));  // true
console.log(Boolean(''));       // false
console.log(Boolean(null));     // false
console.log(Boolean(undefined)); // false

// 假值(Falsy values)
let falsyValues = [
  false,
  0,
  -0,
  0n,      // BigInt零值
  '',      // 空字符串
  null,
  undefined,
  NaN
];

falsyValues.forEach(value => {
  console.log(`${value} is ${Boolean(value)}`);
});

// 真值(Truthy values)- 除假值外的所有值
let truthyValues = [
  true,
  1,
  'hello',
  [],      // 空数组
  {},      // 空对象
  function() {}
];

// 逻辑运算符
let a = true;
let b = false;

console.log(a && b);  // false (逻辑与)
console.log(a || b);  // true  (逻辑或)
console.log(!a);      // false (逻辑非)

// 短路求值
let user = null;
let name = user && user.name; // undefined (不会报错)
let defaultName = name || 'Anonymous'; // 'Anonymous'

// 空值合并运算符(ES2020)
let value = null;
let defaultValue = value ?? 'default'; // 'default'
let zeroValue = 0;
let result = zeroValue ?? 'default';   // 0 (不同于 ||)

Undefined和Null

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

function noReturn() {
  // 没有return语句
}
console.log(noReturn()); // undefined

let obj = { a: 1 };
console.log(obj.b); // undefined

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

// 类型检查
console.log(typeof undefined); // 'undefined'
console.log(typeof null);      // 'object' (这是一个历史bug)

// 比较
console.log(undefined == null);  // true  (类型转换)
console.log(undefined === null); // false (严格比较)

// 检查undefined和null
function isNullOrUndefined(value) {
  return value == null; // 同时检查null和undefined
}

function isUndefined(value) {
  return value === undefined;
}

function isNull(value) {
  return value === null;
}

Symbol类型(ES6)

// 创建Symbol
let sym1 = Symbol();
let sym2 = Symbol('description');
let sym3 = Symbol('description');

console.log(sym2 === sym3); // false (每个Symbol都是唯一的)

// Symbol作为对象属性
let obj = {};
let symKey = Symbol('key');
obj[symKey] = 'value';

console.log(obj[symKey]); // 'value'
console.log(Object.keys(obj)); // [] (Symbol属性不可枚举)

// 全局Symbol注册表
let globalSym1 = Symbol.for('global');
let globalSym2 = Symbol.for('global');
console.log(globalSym1 === globalSym2); // true

// 内置Symbol
let arr = [1, 2, 3];
console.log(arr[Symbol.iterator]); // 数组的迭代器

// 自定义迭代器
let iterableObj = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    let data = this.data;
    return {
      next() {
        if (index < data.length) {
          return { value: data[index++], done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

for (let value of iterableObj) {
  console.log(value); // 1, 2, 3
}

BigInt类型(ES2020)

// 创建BigInt
let bigInt1 = 123n;
let bigInt2 = BigInt(123);
let bigInt3 = BigInt('123456789012345678901234567890');

// BigInt运算
let a = 123n;
let b = 456n;
console.log(a + b);  // 579n
console.log(a * b);  // 56088n
console.log(a ** b); // 非常大的数

// BigInt和Number不能混合运算
// console.log(123n + 456); // TypeError
console.log(123n + BigInt(456)); // 579n
console.log(Number(123n) + 456); // 579

// 比较
console.log(123n === 123);   // false
console.log(123n == 123);    // true
console.log(123n > 122);     // true

// 类型检查
console.log(typeof 123n); // 'bigint'

引用数据类型

Object类型

// 对象字面量
let person = {
  name: 'Alice',
  age: 30,
  city: 'New York',
  
  // 方法
  greet() {
    return `Hello, I'm ${this.name}`;
  },
  
  // 计算属性名
  ['full' + 'Name']: 'Alice Johnson'
};

// 属性访问
console.log(person.name);        // 'Alice'
console.log(person['age']);      // 30
console.log(person.greet());     // 'Hello, I'm Alice'

// 动态属性
let prop = 'city';
console.log(person[prop]);       // 'New York'

// 属性操作
person.email = 'alice@example.com'; // 添加属性
delete person.city;                  // 删除属性

// 属性检查
console.log('name' in person);      // true
console.log(person.hasOwnProperty('name')); // true

// 对象方法
let keys = Object.keys(person);     // 获取所有键
let values = Object.values(person); // 获取所有值
let entries = Object.entries(person); // 获取键值对数组

// 对象合并
let defaults = { theme: 'dark', lang: 'en' };
let userPrefs = { theme: 'light' };
let settings = Object.assign({}, defaults, userPrefs);
// 或使用展开运算符
let settings2 = { ...defaults, ...userPrefs };

// 对象冻结和密封
let frozenObj = Object.freeze({ a: 1 });
// frozenObj.a = 2; // 严格模式下会报错

let sealedObj = Object.seal({ a: 1 });
sealedObj.a = 2; // 可以修改现有属性
// sealedObj.b = 3; // 不能添加新属性

Array类型

// 数组创建
let arr1 = [1, 2, 3, 4, 5];
let arr2 = new Array(5);        // 创建长度为5的空数组
let arr3 = new Array(1, 2, 3);  // [1, 2, 3]
let arr4 = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
let arr5 = Array.of(1, 2, 3);   // [1, 2, 3]

// 数组访问和修改
let numbers = [1, 2, 3, 4, 5];
console.log(numbers[0]);    // 1
console.log(numbers.length); // 5
numbers[5] = 6;             // 添加元素
numbers.length = 3;         // 截断数组

// 数组方法 - 修改原数组
let fruits = ['apple', 'banana'];
fruits.push('orange');      // 末尾添加
fruits.unshift('mango');    // 开头添加
let last = fruits.pop();    // 移除末尾元素
let first = fruits.shift(); // 移除开头元素

// splice方法
let colors = ['red', 'green', 'blue', 'yellow'];
colors.splice(1, 2, 'purple', 'pink'); // 从索引1开始删除2个,插入新元素
console.log(colors); // ['red', 'purple', 'pink', 'yellow']

// 数组方法 - 不修改原数组
let nums = [1, 2, 3, 4, 5];
let doubled = nums.map(n => n * 2);        // [2, 4, 6, 8, 10]
let evens = nums.filter(n => n % 2 === 0); // [2, 4]
let sum = nums.reduce((acc, n) => acc + n, 0); // 15
let found = nums.find(n => n > 3);         // 4
let index = nums.findIndex(n => n > 3);    // 3

// 数组搜索
let animals = ['cat', 'dog', 'bird', 'cat'];
console.log(animals.indexOf('cat'));     // 0
console.log(animals.lastIndexOf('cat')); // 3
console.log(animals.includes('dog'));    // true

// 数组排序
let words = ['banana', 'apple', 'cherry'];
words.sort(); // 字典序排序
console.log(words); // ['apple', 'banana', 'cherry']

let numbers2 = [10, 5, 40, 25, 1000, 1];
numbers2.sort((a, b) => a - b); // 数值排序
console.log(numbers2); // [1, 5, 10, 25, 40, 1000]

// 数组连接和分割
let arr6 = [1, 2];
let arr7 = [3, 4];
let combined = arr6.concat(arr7);    // [1, 2, 3, 4]
let spread = [...arr6, ...arr7];     // [1, 2, 3, 4]
let joined = arr6.join('-');         // '1-2'

// 多维数组
let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];
console.log(matrix[1][2]); // 6

// 数组解构
let [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a);    // 1
console.log(b);    // 2
console.log(rest); // [3, 4, 5]

Function类型

// 函数声明
function add(a, b) {
  return a + b;
}

// 函数表达式
const multiply = function(a, b) {
  return a * b;
};

// 箭头函数
const divide = (a, b) => a / b;
const square = x => x * x;
const greet = () => 'Hello!';

// 函数参数
function greetUser(name = 'Guest', greeting = 'Hello') {
  return `${greeting}, ${name}!`;
}

// 剩余参数
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

// 函数作为参数
function operate(a, b, operation) {
  return operation(a, b);
}

console.log(operate(5, 3, add));      // 8
console.log(operate(5, 3, multiply)); // 15

// 高阶函数
function createMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

// 立即执行函数表达式(IIFE)
(function() {
  console.log('IIFE executed!');
})();

// 递归函数
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

// 函数属性和方法
function myFunction() {
  console.log('Hello');
}

console.log(myFunction.name);   // 'myFunction'
console.log(myFunction.length); // 0 (参数个数)

// call, apply, bind
function introduce() {
  return `Hi, I'm ${this.name}`;
}

const person1 = { name: 'Alice' };
const person2 = { name: 'Bob' };

console.log(introduce.call(person1));  // 'Hi, I'm Alice'
console.log(introduce.apply(person2)); // 'Hi, I'm Bob'

const boundIntroduce = introduce.bind(person1);
console.log(boundIntroduce()); // 'Hi, I'm Alice'

类型转换

显式类型转换

// 转换为字符串
let num = 123;
let str1 = String(num);        // '123'
let str2 = num.toString();     // '123'
let str3 = num + '';           // '123'

// 转换为数字
let str = '123';
let num1 = Number(str);        // 123
let num2 = parseInt(str);      // 123
let num3 = parseFloat(str);    // 123
let num4 = +str;               // 123

// parseInt的进制参数
console.log(parseInt('1010', 2));  // 10 (二进制)
console.log(parseInt('FF', 16));   // 255 (十六进制)

// 转换为布尔值
let bool1 = Boolean(1);        // true
let bool2 = !!1;               // true

隐式类型转换

// 字符串连接
console.log('5' + 3);    // '53' (数字转为字符串)
console.log('5' + true); // '5true'
console.log('5' + null); // '5null'

// 数学运算
console.log('5' - 3);    // 2 (字符串转为数字)
console.log('5' * 2);    // 10
console.log('5' / 2);    // 2.5
console.log('5' % 2);    // 1

// 比较运算
console.log('5' == 5);   // true (类型转换)
console.log('5' === 5);  // false (严格比较)
console.log(null == undefined); // true
console.log(null === undefined); // false

// 逻辑运算中的转换
if ('hello') {           // 'hello'转为true
  console.log('Truthy');
}

if (0) {                 // 0转为false
  console.log('This won\'t run');
}

// 对象转换
let obj = {
  valueOf() {
    return 42;
  },
  toString() {
    return 'object';
  }
};

console.log(obj + 1);    // 43 (调用valueOf)
console.log(obj + '');   // '42' (调用valueOf)
console.log(String(obj)); // 'object' (调用toString)

运算符

算术运算符

let a = 10;
let b = 3;

console.log(a + b);  // 13 (加法)
console.log(a - b);  // 7  (减法)
console.log(a * b);  // 30 (乘法)
console.log(a / b);  // 3.333... (除法)
console.log(a % b);  // 1  (取余)
console.log(a ** b); // 1000 (幂运算,ES2016)

// 一元运算符
console.log(+a);     // 10 (一元加)
console.log(-a);     // -10 (一元减)
console.log(++a);    // 11 (前置递增)
console.log(a++);    // 11 (后置递增,返回原值)
console.log(--a);    // 11 (前置递减)
console.log(a--);    // 11 (后置递减,返回原值)

比较运算符

let x = 5;
let y = '5';

console.log(x == y);   // true  (相等,允许类型转换)
console.log(x === y);  // false (严格相等,不允许类型转换)
console.log(x != y);   // false (不等)
console.log(x !== y);  // true  (严格不等)
console.log(x > 3);    // true  (大于)
console.log(x < 10);   // true  (小于)
console.log(x >= 5);   // true  (大于等于)
console.log(x <= 5);   // true  (小于等于)

// 特殊比较
console.log(NaN === NaN);        // false
console.log(Object.is(NaN, NaN)); // true
console.log(+0 === -0);          // true
console.log(Object.is(+0, -0));  // false

逻辑运算符

let a = true;
let b = false;

console.log(a && b);  // false (逻辑与)
console.log(a || b);  // true  (逻辑或)
console.log(!a);      // false (逻辑非)

// 短路求值
let user = { name: 'Alice' };
let name = user && user.name;  // 'Alice'
let defaultName = name || 'Anonymous'; // 'Alice'

// 空值合并运算符(ES2020)
let value = null;
let result = value ?? 'default';  // 'default'
let zero = 0;
let result2 = zero ?? 'default';   // 0 (不同于||运算符)

// 可选链运算符(ES2020)
let user2 = { profile: { name: 'Bob' } };
console.log(user2?.profile?.name);     // 'Bob'
console.log(user2?.profile?.age);      // undefined
console.log(user2?.nonexistent?.name); // undefined (不会报错)

赋值运算符

let x = 10;

x += 5;   // x = x + 5;  结果: 15
x -= 3;   // x = x - 3;  结果: 12
x *= 2;   // x = x * 2;  结果: 24
x /= 4;   // x = x / 4;  结果: 6
x %= 4;   // x = x % 4;  结果: 2
x **= 3;  // x = x ** 3; 结果: 8

// 逻辑赋值运算符(ES2021)
let a = null;
a ||= 'default';  // a = a || 'default'; 结果: 'default'

let b = 'existing';
b ||= 'default';  // b保持'existing'

let c = null;
c ??= 'default';  // c = c ?? 'default'; 结果: 'default'

let d = true;
d &&= false;     // d = d && false; 结果: false

位运算符

let a = 5;  // 二进制: 101
let b = 3;  // 二进制: 011

console.log(a & b);   // 1   (按位与: 001)
console.log(a | b);   // 7   (按位或: 111)
console.log(a ^ b);   // 6   (按位异或: 110)
console.log(~a);      // -6  (按位非)
console.log(a << 1);  // 10  (左移: 1010)
console.log(a >> 1);  // 2   (右移: 10)
console.log(a >>> 1); // 2   (无符号右移)

// 位运算的实际应用
// 检查奇偶性
function isEven(n) {
  return (n & 1) === 0;
}

// 交换两个数(不使用临时变量)
function swap(a, b) {
  a = a ^ b;
  b = a ^ b;
  a = a ^ b;
  return [a, b];
}

本章总结

本章详细介绍了JavaScript的基本语法和数据类型:

  1. 语法基础:学习了语句、表达式、注释、标识符等基本概念
  2. 原始类型:掌握了Number、String、Boolean、Undefined、Null、Symbol、BigInt等类型
  3. 引用类型:深入了解了Object、Array、Function等复杂类型
  4. 类型转换:理解了显式和隐式类型转换的规则
  5. 运算符:学习了各种运算符的使用和优先级

这些基础知识是JavaScript编程的核心,为后续学习函数、对象、异步编程等高级特性奠定了坚实的基础。

下一章我们将学习JavaScript的控制结构和流程控制。