Appearance
变量与数据类型
变量是存储数据的容器,数据类型则定义了数据的种类。本章将详细介绍 JavaScript 中的变量声明方式和各种数据类型。
变量声明
JavaScript 中有三种声明变量的方式:var、let 和 const。
var 关键字
var 是 JavaScript 最早期的变量声明方式:
javascript
// 使用 var 声明变量
var name; // 声明变量,未赋值
var age = 25; // 声明并赋值
// var 声明的变量可以重复声明
var name = '张三';
var name = '李四'; // 不会报错,会覆盖之前的值
console.log(name); // 输出:李四
// var 声明的变量有变量提升
console.log(city); // 输出:undefined(不会报错)
var city = '北京'; // 变量提升:声明被提升到作用域顶部
// 等价于:
// var city;
// console.log(city);
// city = '北京';
// var 是函数作用域
function test() {
if (true) {
var message = 'Hello'; // message 在整个函数内都有效
}
console.log(message); // 输出:Hello
}
test();
// console.log(message); // 错误:message 未定义(函数外无法访问)
// var 声明的变量会成为全局对象的属性
var globalVar = '全局变量';
console.log(window.globalVar); // 输出:全局变量(浏览器环境)let 关键字
let 是 ES6 新增的声明方式,解决了 var 的一些问题:
javascript
// 使用 let 声明变量
let name = '张三';
let age = 25;
// let 声明的变量不能重复声明
let city = '北京';
// let city = '上海'; // 错误:不能重复声明
// let 没有变量提升
// console.log(x); // 错误:Cannot access 'x' before initialization
let x = 10;
// let 是块级作用域
if (true) {
let blockVar = '块级变量';
console.log(blockVar); // 输出:块级变量
}
// console.log(blockVar); // 错误:blockVar 未定义
// let 在循环中的应用
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 输出:0, 1, 2(每次循环都是新的 i)
}, 100);
}
// 对比 var
for (var j = 0; j < 3; j++) {
setTimeout(function() {
console.log(j); // 输出:3, 3, 3(同一个 j)
}, 100);
}const 关键字
const 用于声明常量,声明后不能重新赋值:
javascript
// 使用 const 声明常量
const PI = 3.14159;
const MAX_SIZE = 100;
// const 声明时必须初始化
// const x; // 错误:缺少初始化
// const 声明的变量不能重新赋值
const name = '张三';
// name = '李四'; // 错误:不能重新赋值
// const 也是块级作用域
if (true) {
const temp = '临时常量';
console.log(temp); // 输出:临时常量
}
// console.log(temp); // 错误:temp 未定义
// 注意:const 声明的对象,其属性可以修改
const person = {
name: '张三',
age: 25
};
person.name = '李四'; // 允许修改属性
person.city = '北京'; // 允许添加属性
console.log(person); // 输出:{name: '李四', age: 25, city: '北京'}
// person = {}; // 错误:不能重新赋值整个对象
// const 声明的数组,元素可以修改
const colors = ['红', '绿', '蓝'];
colors.push('黄'); // 允许添加元素
colors[0] = '橙色'; // 允许修改元素
console.log(colors); // 输出:['橙色', '绿', '蓝', '黄']
// colors = []; // 错误:不能重新赋值整个数组三种声明方式的区别
javascript
// 对比表格
/*
| 特性 | var | let | const |
|----------------|--------------|--------------|--------------|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 变量提升 | 是 | 否 | 否 |
| 重复声明 | 允许 | 不允许 | 不允许 |
| 重新赋值 | 允许 | 允许 | 不允许 |
| 全局对象属性 | 是 | 否 | 否 |
| 暂时性死区 | 否 | 是 | 是 |
*/
// 最佳实践:
// 1. 默认使用 const
// 2. 需要重新赋值时使用 let
// 3. 避免使用 var
// 示例
const API_URL = 'https://api.example.com'; // 常量用 const
let count = 0; // 需要变化的值用 let
count++;数据类型
JavaScript 有 8 种数据类型,分为原始类型和引用类型。
原始类型(基本类型)
原始类型的值是不可变的,直接存储在栈内存中。
Number 数字类型
javascript
// 整数
let intNum = 42;
let negativeNum = -10;
// 浮点数
let floatNum = 3.14;
let floatNum2 = 0.1;
let floatNum3 = .5; // 等同于 0.5
// 科学计数法
let scientificNum = 2.5e6; // 2500000
let smallNum = 2.5e-3; // 0.0025
// 二进制(ES6)
let binaryNum = 0b1010; // 10
// 八进制
let octalNum = 0o12; // 10(ES6)
let octalNum2 = 012; // 10(严格模式不支持)
// 十六进制
let hexNum = 0xFF; // 255
// 特殊数值
let infinity = Infinity; // 正无穷
let negInfinity = -Infinity; // 负无穷
let notANumber = NaN; // 非数字
// 检测特殊数值
console.log(isFinite(100)); // true
console.log(isFinite(Infinity)); // false
console.log(isNaN(NaN)); // true
console.log(isNaN('hello')); // true(会尝试转换为数字)
console.log(Number.isNaN('hello')); // false(更严格的判断)
// 浮点数精度问题
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// 解决精度问题
function add(num1, num2) {
// 转换为整数计算,再转回小数
const precision = 10;
return (num1 * precision + num2 * precision) / precision;
}
console.log(add(0.1, 0.2)); // 0.3
// 数值范围
console.log(Number.MAX_VALUE); // 最大数值
console.log(Number.MIN_VALUE); // 最小正数值
console.log(Number.MAX_SAFE_INTEGER); // 最大安全整数(9007199254740991)
console.log(Number.MIN_SAFE_INTEGER); // 最小安全整数String 字符串类型
javascript
// 使用单引号
let singleQuote = 'Hello';
// 使用双引号
let doubleQuote = "World";
// 使用模板字符串(ES6)
let template = `Hello, World!`;
// 字符串拼接
let greeting = 'Hello' + ', ' + 'World!';
console.log(greeting); // Hello, World!
// 使用模板字符串拼接
let name = '张三';
let age = 25;
let info = `姓名:${name},年龄:${age}`;
console.log(info); // 姓名:张三,年龄:25
// 模板字符串可以包含表达式
let a = 10;
let b = 20;
console.log(`${a} + ${b} = ${a + b}`); // 10 + 20 = 30
// 模板字符串可以换行
let html = `
<div class="container">
<h1>标题</h1>
<p>内容</p>
</div>
`;
// 转义字符
let escaped = 'He said, "Hello!"'; // 单引号中包含双引号
let escaped2 = "It's a test"; // 双引号中包含单引号
let escaped3 = 'It\'s a test'; // 使用反斜杠转义
let newline = '第一行\n第二行'; // \n 换行
let tab = '列1\t列2'; // \t 制表符
let backslash = '路径:C:\\Users'; // \\ 反斜杠
// 字符串长度
let str = 'Hello';
console.log(str.length); // 5
// 中文字符
let chinese = '你好';
console.log(chinese.length); // 2
// 访问字符
console.log(str[0]); // H
console.log(str.charAt(0)); // H
console.log(str[str.length - 1]); // o(最后一个字符)
// 字符串是不可变的
let s = 'Hello';
// s[0] = 'h'; // 错误:不能修改
s = 'hello'; // 只能重新赋值Boolean 布尔类型
javascript
// 布尔值只有两个值
let isTrue = true;
let isFalse = false;
// 比较运算返回布尔值
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 === 5); // true
console.log(5 !== 3); // true
// 逻辑运算返回布尔值
console.log(true && false); // false
console.log(true || false); // true
console.log(!true); // false
// 条件语句中使用
let age = 18;
if (age >= 18) {
console.log('已成年');
}
// 布尔转换
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean('')); // false
console.log(Boolean('text')); // true
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // falseUndefined 类型
javascript
// undefined 表示变量已声明但未赋值
let x;
console.log(x); // undefined
console.log(typeof x); // undefined
// 函数没有返回值时返回 undefined
function noReturn() {
// 没有返回语句
}
console.log(noReturn()); // undefined
// 访问不存在的属性返回 undefined
let obj = { name: '张三' };
console.log(obj.age); // undefined
// 数组越界访问返回 undefined
let arr = [1, 2, 3];
console.log(arr[10]); // undefined
// 判断 undefined
let value;
if (value === undefined) {
console.log('value 是 undefined');
}
// 注意:undefined 不是保留字,可以被重新赋值(不推荐)
// undefined = 'test'; // 不要这样做Null 类型
javascript
// null 表示"空"或"无"
let empty = null;
console.log(empty); // null
console.log(typeof empty); // object(历史遗留问题)
// null 和 undefined 的区别
// null:表示"没有值",是主动设置的
// undefined:表示"缺少值",是默认状态
let person = null; // 明确表示没有对象
let person2; // 还未赋值
// 判断 null
if (empty === null) {
console.log('empty 是 null');
}
// null 和 undefined 比较
console.log(null == undefined); // true(宽松相等)
console.log(null === undefined); // false(严格相等)
// 转换为数字
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
// 初始化对象时使用 null
let user = null; // 初始化为 null,后续会赋值对象
user = { name: '张三' };Symbol 类型(ES6)
javascript
// Symbol 是 ES6 新增的原始类型,表示唯一的标识符
let sym1 = Symbol();
let sym2 = Symbol('description'); // 可选的描述字符串
// 每个 Symbol 都是唯一的
let sym3 = Symbol('test');
let sym4 = Symbol('test');
console.log(sym3 === sym4); // false(即使描述相同也不相等)
// Symbol 作为对象属性键(保证属性名唯一)
let id = Symbol('id');
let user = {
name: '张三',
[id]: 12345 // 使用计算属性名
};
console.log(user[id]); // 12345
// Symbol 属性不会出现在 for...in 循环中
for (let key in user) {
console.log(key); // 只输出 name
}
// 获取 Symbol 属性
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]
// Symbol.for() 创建全局 Symbol
let globalSym1 = Symbol.for('app.id');
let globalSym2 = Symbol.for('app.id');
console.log(globalSym1 === globalSym2); // true(同一个全局 Symbol)
// 获取 Symbol 的描述
console.log(sym2.description); // descriptionBigInt 类型(ES2020)
javascript
// BigInt 用于表示任意大的整数
// 在数字后面加 n 或使用 BigInt() 函数
// 使用 n 后缀
let bigNum1 = 9007199254740991n;
let bigNum2 = 123456789012345678901234567890n;
// 使用 BigInt() 函数
let bigNum3 = BigInt(9007199254740991);
let bigNum4 = BigInt('123456789012345678901234567890');
// BigInt 运算
console.log(bigNum1 + 1n); // 9007199254740992n
console.log(bigNum1 * 2n); // 18014398509481982n
// BigInt 和 Number 不能混合运算
// console.log(bigNum1 + 1); // 错误
// 需要显式转换
console.log(bigNum1 + BigInt(1)); // 正确
console.log(Number(bigNum1) + 1); // 正确(但可能丢失精度)
// 比较运算
console.log(1n === 1); // false(类型不同)
console.log(1n == 1); // true(宽松相等)
console.log(1n < 2); // true
// typeof 检测
console.log(typeof bigNum1); // bigint引用类型
引用类型的值是可变的,存储在堆内存中,变量保存的是引用地址。
Object 对象
javascript
// 创建对象
let person = {
name: '张三',
age: 25,
city: '北京'
};
// 访问属性
console.log(person.name); // 张三
console.log(person['age']); // 25
// 修改属性
person.age = 26;
person['city'] = '上海';
// 添加新属性
person.job = '工程师';
// 删除属性
delete person.city;
// 检查属性是否存在
console.log('name' in person); // true
console.log(person.hasOwnProperty('name')); // true
// 遍历对象
for (let key in person) {
console.log(key + ': ' + person[key]);
}
// 对象方法
let calculator = {
value: 0,
add: function(num) {
this.value += num;
return this;
},
subtract: function(num) {
this.value -= num;
return this;
},
getValue: function() {
return this.value;
}
};
calculator.add(10).subtract(3);
console.log(calculator.getValue()); // 7Array 数组
javascript
// 创建数组
let arr1 = [1, 2, 3, 4, 5];
let arr2 = new Array(1, 2, 3);
let arr3 = new Array(5); // 创建长度为 5 的空数组
// 访问元素
console.log(arr1[0]); // 1
console.log(arr1[arr1.length - 1]); // 5
// 修改元素
arr1[0] = 10;
// 数组长度
console.log(arr1.length); // 5
// 添加元素
arr1.push(6); // 末尾添加
arr1.unshift(0); // 开头添加
// 删除元素
arr1.pop(); // 删除末尾元素
arr1.shift(); // 删除开头元素
// 数组可以包含不同类型的元素
let mixed = [1, 'hello', true, null, { name: '张三' }, [1, 2, 3]];Function 函数
javascript
// 函数声明
function greet(name) {
return 'Hello, ' + name + '!';
}
// 函数表达式
let greet2 = function(name) {
return 'Hello, ' + name + '!';
};
// 箭头函数(ES6)
let greet3 = (name) => 'Hello, ' + name + '!';
// 调用函数
console.log(greet('张三')); // Hello, 张三!
// 函数是对象
console.log(typeof greet); // function
console.log(greet instanceof Object); // true类型检测
typeof 操作符
javascript
// typeof 返回类型的字符串
console.log(typeof 42); // number
console.log(typeof 3.14); // number
console.log(typeof 'hello'); // string
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof null); // object(历史遗留问题)
console.log(typeof {}); // object
console.log(typeof []); // object
console.log(typeof function(){}); // function
console.log(typeof Symbol()); // symbol
console.log(typeof 10n); // bigint
// typeof 的局限性
// 1. null 返回 object
// 2. 数组返回 object
// 3. 无法区分不同对象类型instanceof 操作符
javascript
// instanceof 检测对象是否是某个构造函数的实例
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
let obj = {};
console.log(obj instanceof Object); // true
console.log(obj instanceof Array); // false
let date = new Date();
console.log(date instanceof Date); // true
// instanceof 的局限性
// 只能用于对象,不能用于原始类型
console.log(42 instanceof Number); // false
console.log('hi' instanceof String); // false更精确的类型检测
javascript
// 使用 Object.prototype.toString
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(getType(42)); // Number
console.log(getType('hello')); // String
console.log(getType(true)); // Boolean
console.log(getType(null)); // Null
console.log(getType(undefined)); // Undefined
console.log(getType({})); // Object
console.log(getType([])); // Array
console.log(getType(function(){})); // Function
console.log(getType(new Date())); // Date
console.log(getType(/regex/)); // RegExp
// 使用 Array.isArray() 检测数组
console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray({})); // false
// 检测 NaN
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false
// 检测有限数字
console.log(Number.isFinite(100)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite('100')); // false类型转换
转换为字符串
javascript
// String() 函数
console.log(String(123)); // '123'
console.log(String(true)); // 'true'
console.log(String(null)); // 'null'
console.log(String(undefined)); // 'undefined'
console.log(String([1, 2, 3])); // '1,2,3'
console.log(String({})); // '[object Object]'
// toString() 方法
console.log((123).toString()); // '123'
console.log(true.toString()); // 'true'
// console.log(null.toString()); // 错误:null 没有 toString 方法
// console.log(undefined.toString()); // 错误
// 字符串拼接
console.log(123 + ''); // '123'
console.log(true + ''); // 'true'
// 模板字符串
console.log(`${123}`); // '123'
console.log(`${true}`); // 'true'转换为数字
javascript
// Number() 函数
console.log(Number('123')); // 123
console.log(Number('123.5')); // 123.5
console.log(Number('')); // 0
console.log(Number('abc')); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
// parseInt() 解析整数
console.log(parseInt('123')); // 123
console.log(parseInt('123.9')); // 123(只取整数部分)
console.log(parseInt('123abc')); // 123(解析到非数字停止)
console.log(parseInt('abc123')); // NaN
console.log(parseInt('10', 2)); // 2(二进制转十进制)
console.log(parseInt('FF', 16)); // 255(十六进制转十进制)
// parseFloat() 解析浮点数
console.log(parseFloat('3.14')); // 3.14
console.log(parseFloat('3.14abc')); // 3.14
console.log(parseFloat('3')); // 3
// 一元加号运算符
console.log(+'123'); // 123
console.log(+'3.14'); // 3.14
console.log(+'abc'); // NaN
// 隐式转换(算术运算)
console.log('123' - 0); // 123
console.log('123' * 1); // 123
console.log('123' / 1); // 123转换为布尔值
javascript
// Boolean() 函数
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean(-1)); // true
console.log(Boolean('')); // false
console.log(Boolean('text')); // true
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean([])); // true
console.log(Boolean({})); // true
// 假值(Falsy Values)
// 以下值转换为布尔值时为 false:
// false, 0, -0, 0n, '', null, undefined, NaN
// 真值(Truthy Values)
// 除了假值以外的所有值都是真值
// 双重否定
console.log(!!1); // true
console.log(!!0); // false
console.log(!!'text'); // true
console.log(!!''); // false
// 条件语句中的隐式转换
let value = 'hello';
if (value) {
console.log('value 是真值');
}对象转换
javascript
// 对象转换为原始值
let obj = {
value: 10,
// valueOf() 方法:返回对象的原始值
valueOf() {
return this.value;
},
// toString() 方法:返回对象的字符串表示
toString() {
return `value: ${this.value}`;
}
};
console.log(obj + 5); // 15(调用 valueOf)
console.log(String(obj)); // value: 10(调用 toString)
// 数组转换为字符串
let arr = [1, 2, 3];
console.log(String(arr)); // '1,2,3'
console.log(arr + ''); // '1,2,3'
// 日期转换为字符串
let date = new Date();
console.log(String(date)); // 'Fri Mar 20 2026 ...'
console.log(Number(date)); // 时间戳(毫秒数)小结
本章学习了 JavaScript 的变量和数据类型:
- 变量声明:var(函数作用域)、let(块级作用域)、const(常量)
- 原始类型:Number、String、Boolean、Undefined、Null、Symbol、BigInt
- 引用类型:Object、Array、Function
- 类型检测:typeof、instanceof、Object.prototype.toString
- 类型转换:转换为字符串、数字、布尔值的方法
下一章我们将学习 运算符,了解 JavaScript 中的各种运算操作。
