返回首页

01-变量与数据类型

分类:01-JavaScript基础核心
发布于:
阅读时间:28 分钟

变量与数据类型

📋 学习目标

  • 掌握JavaScript中三种变量声明方式的区别
  • 理解JavaScript的7种基本数据类型
  • 学会正确使用类型转换
  • 了解变量作用域和提升机制

🎯 核心概念

1. 变量声明方式

JavaScript提供了三种变量声明方式:varletconst,它们有重要的区别:

var 的特点

// 1. 变量提升 - 可以先使用后声明
console.log(name); // undefined,不会报错
var name = "张三";

// 2. 函数作用域 - 只在函数内有效
function test() {
    if (true) {
        var localVar = "局部变量";
    }
    console.log(localVar); // 可以访问
}

// 3. 可以重复声明
var a = 1;
var a = 2; // 允许

let 的特点

// 1. 块级作用域 - 只在代码块内有效
if (true) {
    let blockVar = "块级变量";
}
// console.log(blockVar); // 报错:blockVar is not defined

// 2. 暂时性死区 - 必须先声明后使用
// console.log(letVar); // 报错:Cannot access 'letVar' before initialization
let letVar = "let变量";

// 3. 不允许重复声明
let b = 1;
// let b = 2; // 报错:Identifier 'b' has already been declared

const 的特点

// 1. 声明时必须初始化
// const constant; // 报错:Missing initializer in const declaration

// 2. 值不能重新赋值
const PI = 3.14159;
// PI = 3.14; // 报错:Assignment to constant variable

// 3. 对于引用类型,可以修改属性
const obj = { name: "对象" };
obj.name = "修改后的对象"; // 允许
// obj = {}; // 报错:Assignment to constant variable

2. 数据类型详解

JavaScript有7种基本数据类型和1种引用类型:

基本数据类型

// 1. Number - 数字
let num = 42;
let floatNum = 3.14;
let infinity = Infinity;
let notANumber = NaN;

// 2. String - 字符串
let str1 = "双引号字符串";
let str2 = '单引号字符串';
let str3 = `模板字符串,可以嵌入变量:${num}`;

// 3. Boolean - 布尔值
let isTrue = true;
let isFalse = false;

// 4. Undefined - 未定义
let undefinedVar;
console.log(undefinedVar); // undefined

// 5. Null - 空值
let nullVar = null;
console.log(typeof nullVar); // "object" (这是一个历史遗留的bug)

// 6. Symbol - 符号(ES6新增)
let sym = Symbol("描述");
let sym2 = Symbol("描述");
console.log(sym === sym2); // false,每个Symbol都是唯一的

// 7. BigInt - 大整数(ES2020新增)
let bigNum = 9007199254740991n;
let bigNum2 = 123n;

引用数据类型

// Object - 对象
let person = {
    name: "张三",
    age: 25,
    greet: function() {
        return `你好,我是${this.name}`;
    }
};

// Array - 数组
let arr = [1, 2, 3, "字符串", { obj: "对象" }];

// Function - 函数
function add(a, b) {
    return a + b;
}

// Date - 日期
let date = new Date();

// RegExp - 正则表达式
let reg = /\d+/g;

3. 类型转换

显式类型转换

// 转换为字符串
String(123); // "123"
String(true); // "true"
String(null); // "null"
String(undefined); // "undefined"

// 转换为数字
Number("123"); // 123
Number("123.45"); // 123.45
Number("123abc"); // NaN
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN

// 转换为布尔值
Boolean(0); // false
Boolean(""); // false
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false
Boolean("false"); // true
Boolean("0"); // true

// parseInt 和 parseFloat
parseInt("123"); // 123
parseInt("123px"); // 123
parseInt("123.45"); // 123
parseFloat("123.45"); // 123.45
parseFloat("123.45px"); // 123.45

隐式类型转换

// 字符串拼接
console.log(1 + "2"); // "12"
console.log("1" + 2); // "12"

// 数字运算
console.log("1" - 2); // -1
console.log("1" * 2); // 2
console.log("1" / 2); // 0.5

// 布尔运算
console.log(1 <mark> true); // true
console.log(0 </mark> false); // true
console.log("" <mark> false); // true

// 严格相等(推荐使用)
console.log(1 </mark>= true); // false
console.log(0 =<mark> false); // false
console.log("" </mark>= false); // false

4. 变量作用域

// 全局作用域
var globalVar = "全局变量";

function outerFunction() {
    // 函数作用域
    var outerVar = "外部函数变量";
    let outerLet = "外部函数let";

    function innerFunction() {
        // 内层函数作用域
        var innerVar = "内部函数变量";
        console.log(globalVar); // 可以访问全局变量
        console.log(outerVar); // 可以访问外部函数变量
        console.log(innerVar); // 可以访问内部变量
    }

    innerFunction();
    // console.log(innerVar); // 报错:无法访问内部变量
}

outerFunction();
// console.log(outerVar); // 报错:无法访问函数内部变量

🔧 实践练习

练习1:变量声明方式对比

// 分析以下代码的输出结果
function testVar() {
    console.log(a); // undefined (变量提升)
    if (true) {
        var a = 1;
        let b = 2;
        const c = 3;
    }
    console.log(a); // 1 (var是函数作用域)
    // console.log(b); // 报错 (let是块级作用域)
    // console.log(c); // 报错 (const是块级作用域)
}

testVar();

练习2:类型转换理解

// 预测输出结果
console.log([] <mark> ![]); // true
console.log([] </mark> []); // false
console.log({} <mark> {}); // false
console.log(NaN </mark> NaN); // false
console.log(NaN === NaN); // false

⚠️ 常见陷阱

1. 变量提升陷阱

// ❌ 错误示例
for (var i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i); // 输出:3, 3, 3
    }, 100);
}

// ✅ 正确做法
for (let i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i); // 输出:0, 1, 2
    }, 100);
}

2. 类型判断陷阱

// ❌ 使用typeof判断数组
console.log(typeof []); // "object"

// ✅ 正确判断数组的方法
console.log(Array.isArray([])); // true
console.log([] instanceof Array); // true
console.log(Object.prototype.toString.call([])); // "[object Array]"

3. null与undefined的区别

// null表示"无值",是显式设置的
let data = null;

// undefined表示"未定义",是默认状态
let data2;
console.log(data2); // undefined

// 类型判断
console.log(typeof null); // "object"
console.log(typeof undefined); // "undefined"

📝 最佳实践

  1. 优先使用const:只有在需要重新赋值时才使用let
  2. 避免使用var:在现代JavaScript开发中不再推荐使用var
  3. 使用严格相等:优先使用=<mark>而不是</mark>
  4. 显式类型转换:避免依赖隐式类型转换,代码更清晰
  5. 合理命名:使用有意义的变量名,遵循命名规范

🎯 小结

  • 掌握了varletconst的区别和使用场景
  • 理解了JavaScript的8种数据类型
  • 学会了显式和隐式类型转换
  • 了解了变量作用域和常见陷阱
  • 掌握了变量声明的最佳实践

下一步学习函数与作用域