JavaScript基础详解
1. 书写语法与输出语句
1.1 基本书写规则
JavaScript的书写语法相对灵活,但遵循一些基本规范能让代码更易读:
// 推荐写法:使用分号结尾(虽然JS有自动分号插入机制)
let name = "张三";
console.log(name);// ✅ 也可以:不使用分号(依赖ASI机制)但不推荐
let age = 25
console.log(age)// 🚨 注意:某些情况下省略分号会导致问题
let a = 1
[1, 2, 3].forEach(n => console.log(n)) // ❌ 会报错!
// 正确写法:
let a = 1;
[1, 2, 3].forEach(n => console.log(n)); // ✅
关键点:
-
JavaScript是大小写敏感的(
name
和Name
是不同的变量) -
建议使用分号结尾,避免潜在问题
-
注释支持:
//
单行注释 和/* */
多行注释
1.2 输出语句的四种方式
方式1:console.log() - 控制台输出 ⭐
// 最常用的调试方法
console.log("Hello, JavaScript!"); // 输出:Hello, JavaScript!
console.log(100 + 200); // 输出:300
console.log("结果是:", 42, true); // 输出:结果是: 42 true// 其他console方法
console.warn("这是一个警告"); // ⚠️ 黄色警告
console.error("这是一个错误"); // ❌ 红色错误
console.table([{name: "李四", age: 20}]); // 表格形式输出
方式2:alert() - 浏览器弹窗
alert("欢迎来到我的网站!"); // 会阻塞页面执行,直到用户点击确定
特点: 只能显示字符串,会将其他类型转换为字符串。
方式3:document.write() - 网页内容输出
document.write("<h1>Hello World</h1>");
document.write("当前时间:" + new Date());
⚠️ 注意: 页面加载完成后调用会覆盖整个页面内容!
方式4:innerHTML - 修改元素内容
<div id="demo">旧的内容</div><div id="result"></div><script>// 获取元素并修改其HTML内容document.getElementById("demo").innerHTML = "新的内容";document.getElementById("result").innerHTML = "<strong>计算结果:100</strong>";</script>
2. 变量声明与使用
2.1 三种声明方式对比
JavaScript有三种声明变量的关键字:var
、let
、const
var - 老式声明(ES5及之前)
var userName = "王五";
var age = 30;
var age = 35; // ✅ 允许重复声明(这是个坑!)console.log(userName); // 输出:王五// ⚠️ var的作用域问题
function testVar() {var x = 10;if (true) {var x = 20; // 同一个变量!console.log(x); // 输出:20}console.log(x); // 输出:20(不是10!)
}
var的问题:
-
没有块级作用域(只有函数作用域)
-
允许重复声明
-
存在变量提升(hoisting)
let - 现代块级作用域变量(ES6+)⭐
let score = 85;
// let score = 90; // ❌ 报错:不允许重复声明if (true) {let score = 95; // 这是新的块级变量console.log(score); // 输出:95
}
console.log(score); // 输出:85// 块级作用域示例for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出:3 3 3}for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出:0 1 2}
// 如果用var,会输出:3 3 3
const - 常量声明(ES6+)⭐
const PI = 3.14159;
// PI = 3.14; // ❌ 报错:不能重新赋值const user = {name: "赵六",age: 28
};
// user = {}; // ❌ 报错:不能重新赋值
user.age = 29; // ✅ 可以修改对象的属性
console.log(user); // 输出:{ name: "赵六", age: 29 }// 数组也是一样
const colors = ["red", "blue"];
colors.push("green"); // ✅ 可以修改数组内容
console.log(colors); // 输出:["red", "blue", "green"]
2.2 命名规范
// ✅ 推荐的命名方式
let firstName = "John"; // 小驼峰命名法(变量)
const MAX_COUNT = 100; // 全大写+下划线(常量)
function getUserInfo() {} // 小驼峰命名法(函数)// ❌ 不推荐
let first_name = "John"; // 下划线命名(不是JS习惯)
let FirstName = "John"; // 大驼峰(通常用于类名)// 规则:
// - 只能包含字母、数字、下划线、美元符号
// - 不能以数字开头
// - 不能使用关键字(let、if、function等)
最佳实践建议:
-
优先使用
const
,只有需要重新赋值时才用let
-
避免使用
var
(除非维护老代码) -
使用有意义的变量名
3. 数据类型详解
JavaScript有8种数据类型,分为基本类型(7种)和引用类型(1种)。
3.1 基本数据类型(Primitive Types)
3.1.1 Number - 数值类型
// JavaScript只有一种数值类型(不区分整数和浮点数)
let integer = 42;
let float = 3.14;
let negative = -100;
let scientific = 2.5e6; // 2500000(科学计数法)// 特殊数值
let infinity = Infinity; // 无穷大
let negInfinity = -Infinity; // 负无穷大
let notANumber = NaN; // Not a Number// 示例
console.log(10 / 0); // Infinity
console.log("abc" * 2); // NaN
console.log(typeof NaN); // "number" (NaN也是number类型!)
3.1.2 String - 字符串类型
let str1 = "双引号字符串";
let str2 = '单引号字符串';
let str3 = `反引号字符串`; // 模板字符串(下一章详解)// 字符串特性
let name = "JavaScript";
console.log(name.length); // 10(长度属性)
console.log(name[0]); // "J"(可以像数组一样访问)
console.log(name.toUpperCase()); // "JAVASCRIPT"// 字符串是不可变的
let greeting = "Hello";
// greeting[0] = "h"; // ❌ 无效操作
greeting = "hello"; // ✅ 只能重新赋值
3.1.3 Boolean - 布尔类型
let isStudent = true;
let hasLicense = false;// 常用于条件判断
if (isStudent) {console.log("学生票价");
}// 逻辑运算
console.log(true && false); // false
console.log(true || false); // true
console.log(!true); // false
3.1.4 Undefined - 未定义
let username;
console.log(username); // undefined
console.log(typeof username); // "undefined"function test() {// 没有return语句
}
console.log(test()); // undefinedlet obj = {name: "Tom"};
console.log(obj.age); // undefined(访问不存在的属性)
3.1.5 Null - 空值
let data = null; // 明确表示"空"或"无"
console.log(typeof null); // "object" 🚨 这是JS的一个历史Bug!// null vs undefined
console.log(null == undefined); // true(值相等)
console.log(null === undefined); // false(类型不同)
3.1.6 Symbol - 符号类型(ES6+)
let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false(每个Symbol都是唯一的)// 主要用于对象属性的唯一标识
let user = {[id1]: "用户ID"
};
3.1.7 BigInt - 大整数(ES2020+)
let bigNumber = 9007199254740991n; // 在数字后加n
let anotherBig = BigInt("9007199254740991");console.log(bigNumber + 1n); // 9007199254740992n
// console.log(bigNumber + 1); // ❌ 报错:不能混合BigInt和Number运算
3.2 引用数据类型(Reference Types)
Object - 对象类型
// 对象字面量
let person = {name: "李明",age: 25,isStudent: true,hobbies: ["读书", "跑步"],sayHi: function() {console.log("你好!");}
};console.log(person.name); // "李明"
console.log(person["age"]); // 25
person.sayHi(); // "你好!"// 数组(特殊的对象)
let numbers = [1, 2, 3, 4, 5];
console.log(typeof numbers); // "object"
console.log(Array.isArray(numbers)); // true// 函数(也是对象)
function add(a, b) {return a + b;
}
console.log(typeof add); // "function"
3.3 类型检测-typeof关键字
// typeof 运算符
console.log(typeof 42); // "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(Array.isArray([])); // true
console.log([] instanceof Array); // true
console.log(Object.prototype.toString.call([])); // "[object Array]"
4. 反引号(模板字符串)的使用
ES6引入的模板字符串(Template Literals)是JavaScript最实用的特性之一!🚀
4.1 基本语法
// 普通字符串 vs 模板字符串
let name = "小明";
let age = 20;// ❌ 老方法:拼接字符串
let msg1 = "我叫" + name + ",今年" + age + "岁";// ✅ 新方法:模板字符串
let msg2 = `我叫${name},今年${age}岁`;console.log(msg2); // "我叫小明,今年20岁"
4.2 表达式插值
let a = 10;
let b = 20;// 可以在${}中执行任何JavaScript表达式
console.log(`${a} + ${b} = ${a + b}`); // "10 + 20 = 30"
console.log(`5的平方是:${5 ** 2}`); // "5的平方是:25"// 调用函数
function getDiscount(price) {return price * 0.8;
}
let price = 100;
console.log(`原价:${price}元,折后:${getDiscount(price)}元`);
// "原价:100元,折后:80元"// 三元运算符
let score = 85;
console.log(`考试结果:${score >= 60 ? '及格' : '不及格'}`);
// "考试结果:及格"
4.3 多行字符串
// ❌ 老方法:需要使用转义符或拼接
let html1 = "<div>\n" +" <h1>标题</h1>\n" +" <p>内容</p>\n" +"</div>";// ✅ 新方法:直接换行
let html2 = `
<div><h1>标题</h1><p>内容</p>
</div>
`;console.log(html2);
// 输出保留所有空格和换行
小提醒:如果使用老方法需要将 “ ” 进行转义
4.4 嵌套模板字符串
let students = [{ name: "张三", score: 85 },{ name: "李四", score: 92 },{ name: "王五", score: 78 }
];let html = `
<ul>${students.map(s => `<li>${s.name}: ${s.score}分 ${s.score >= 90 ? '🌟优秀' : ''}</li>`).join('')}
</ul>
`;console.log(html);
// 输出:
// <ul>
// <li>张三: 85分 </li>
// <li>李四: 92分 🌟优秀</li>
// <li>王五: 78分 </li>
// </ul>
4.5 标签模板(高级用法)
// 自定义模板处理函数
function highlight(strings, ...values) {return strings.reduce((result, str, i) => {return result + str + (values[i] ? `<strong>${values[i]}</strong>` : '');}, '');
}let product = "iPhone";
let price = 999;
let result = highlight`商品:${product},价格:${price}元`;
console.log(result);
// "商品:<strong>iPhone</strong>,价格:<strong>999</strong>元"
5. 运算符与类型转换
5.1 算术运算符
let a = 10, b = 3;console.log(a + b); // 13(加法)
console.log(a - b); // 7(减法)
console.log(a * b); // 30(乘法)
console.log(a / b); // 3.3333...(除法)
console.log(a % b); // 1(取余)
console.log(a ** b); // 1000(幂运算,ES2016+)// 自增自减
let count = 5;
console.log(count++); // 5(先使用后加)
console.log(count); // 6
console.log(++count); // 7(先加后使用)
5.2 赋值运算符
let x = 10;
x += 5; // 等同于 x = x + 5
x -= 3; // 等同于 x = x - 3
x *= 2; // 等同于 x = x * 2
x /= 4; // 等同于 x = x / 4
x %= 3; // 等同于 x = x % 3
x **= 2; // 等同于 x = x ** 2
5.3 比较运算符
// == vs ===(重要!)
console.log(5 == "5"); // true(值相等,会进行类型转换)
console.log(5 === "5"); // false(值和类型都要相等)console.log(null == undefined); // true
console.log(null === undefined); // false// 其他比较
console.log(10 > 5); // true
console.log(10 >= 10); // true
console.log(10 != "10"); // false(会类型转换)
console.log(10 !== "10"); // true(严格不等)// ⚠️ 特殊情况
console.log(NaN == NaN); // false(NaN不等于任何值,包括自己!)
console.log(NaN === NaN); // false
console.log(isNaN(NaN)); // true(正确的检测方法)
5.4 逻辑运算符
let age = 25;
let hasID = true;// && 与运算(全真才真)
console.log(age >= 18 && hasID); // true// || 或运算(有真即真)
console.log(age < 18 || hasID); // true// ! 非运算(取反)
console.log(!hasID); // false// 短路运算
let result = null || "默认值"; // "默认值"
let value = "输入" && "处理"; // "处理"// ?? 空值合并运算符(ES2020+)
let config = null;
console.log(config ?? "默认配置"); // "默认配置"
console.log(0 ?? "默认值"); // 0(只有null和undefined才返回右边)
5.5 类型转换详解
5.5.1 转换为字符串
// 方法1:String()函数
let num = 123;
console.log(String(num)); // "123"
console.log(String(true)); // "true"
console.log(String(null)); // "null"// 方法2:toString()方法
console.log(num.toString()); // "123"
console.log((true).toString()); // "true"
// null.toString(); // ❌ 报错// 方法3:拼接空字符串(隐式转换)
console.log(num + ""); // "123"
console.log(true + ""); // "true"
5.5.2 转换为数值
// 方法1:Number()函数
console.log(Number("123")); // 123
console.log(Number("12.5")); // 12.5
console.log(Number("123abc")); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN// 方法2:parseInt()和parseFloat()
console.log(parseInt("123")); // 123
console.log(parseInt("123.45")); // 123(只取整数部分)
console.log(parseInt("123abc")); // 123(解析到非数字停止)
console.log(parseFloat("12.5")); // 12.5
console.log(parseFloat("12.5.6")); // 12.5// 方法3:一元加号运算符(隐式转换)
console.log(+"123"); // 123
console.log(+true); // 1
console.log(+"abc"); // NaN
5.5.3 转换为布尔值
// Boolean()函数
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
console.log(Boolean(NaN)); // false
console.log(Boolean({})); // true
console.log(Boolean([])); // true// 记忆口诀:以下6个值转换为false,其他都是true
// 0, "", null, undefined, NaN, false// 双重取反(隐式转换)
console.log(!!"hello"); // true
console.log(!!0); // false
5.5.4 隐式类型转换陷阱 ⚠️
// 加号的特殊性
console.log(1 + 2); // 3(数值相加)
console.log("1" + 2); // "12"(字符串拼接)
console.log(1 + "2"); // "12"(字符串拼接)
console.log(1 + 2 + "3"); // "33"(先算1+2=3,再"3"+"3"="33")
console.log("1" + 2 + 3); // "123"(全部转字符串)// 其他运算符会尝试转为数值
console.log("5" - 2); // 3
console.log("5" * "2"); // 10
console.log("10" / "2"); // 5
console.log("5" > 3); // true// 对象转换
console.log([1, 2] + [3, 4]); // "1,23,4"
console.log({} + []); // "[object Object]"// 最佳实践:显式转换避免Bug
let userInput = "25";
let age = Number(userInput); // ✅ 明确转换
// let age = userInput - 0; // ❌ 隐式转换,不推荐
5.6 运算符优先级
// 优先级从高到低:
// 1. 括号 ()
// 2. 一元运算符 !, ++, --, typeof
// 3. 算术运算符 **, *, /, %, +, -
// 4. 比较运算符 >, <, >=, <=, ==, ===
// 5. 逻辑运算符 &&, ||
// 6. 赋值运算符 =, +=, -=// 示例
console.log(2 + 3 * 4); // 14(不是20)
console.log((2 + 3) * 4); // 20(括号改变优先级)
console.log(10 > 5 && 3 < 7); // true
console.log(10 > 5 || 3 > 7 && 1 > 2); // true(&&优先于||)
总结:
这篇文章涵盖了JavaScript的五个基础主题:输出方式、变量声明、数据类型、模板字符串和运算符。
如果你之前用过JAVA,会发现JavaScript在很多地方都比较"随意"——比如弱类型、灵活的类型转换、各种隐式行为。这些特性让JS写起来很快,但也容易踩坑。