JavaScript基础语法
- 声明
let singleQuoteString = 'Single quote string'let doubleQuoteString = "Double quote string"var name = 'John'; // ES5let tripleQuoteString = `Triple quotestring spanningmultiple lines ${name}`let age = 30; // ES6const isStudent = true; // ES6JavaScript 中声明变量主要有三种方式:var、let 和 const。每种方式都有其特定的使用场景和特点。
1. var
Section titled “1. var”-
特点:
- 可以重新声明和赋值。
- 函数作用域:
var声明的变量在其所在函数内是可见的。 - 存在变量提升(Hoisting):声明会被提升到作用域顶部,但赋值不会。
-
例子:
function example() {console.log(x); // 输出:undefinedvar x = 10;console.log(x); // 输出:10}example();
2. let
Section titled “2. let”-
特点:
- 可以重新赋值,但不能重新声明。
- 块级作用域:
let声明的变量在其所在的代码块内是可见的。 - 没有变量提升,但会存在暂时性死区(Temporal Dead Zone,TDZ)。
-
例子:
function example() {console.log(y); // ReferenceError: y is not definedlet y = 20;console.log(y); // 输出:20}example();
3. const
Section titled “3. const”- 特点:
- 不能重新赋值或重新声明。
- 必须在声明时初始化。
- 块级作用域。
- 常用于声明常量,但对于对象和数组,虽然不能重新赋值,但可以修改其内容。
|数据类型|描述|示例|
|---|---|---|
|原始类型|Primitive Types||
|String|表示文本数据,用单引号或双引号包围的字符序列。|"Hello, World!"|
|Number|表示数字,可以是整数或浮点数。|42 , 3.14|
|Boolean|表示逻辑值,只有两个值:true 或 false。|true , false|
|Undefined|表示未定义的值,变量声明但未赋值时的默认值。|let a; // a 是 undefined|
|Null|表示空值,表示变量没有值。|let b = null;|
|Symbol|表示唯一的、不可变的数据类型,用于对象属性标识。|let sym = Symbol('desc');|
|BigInt|表示任意精度的整数,用于处理大整数。|let bigInt = 12345678901234567890n;|
|对象类型|Object Types||
|Object|集合键值对,所有复杂数据结构的基础。|let obj = { name: 'John', age: 30 };|
|Array|有序集合,元素可以是任何类型。|let arr = [1, 'two', 3];|
|Function|可执行的代码块,定义了特定任务。|function greet() { return 'Hello'; }|
|Date|表示日期和时间。|let date = new Date();|
|Regular expression|正则表达式,用于匹配字符串。|let re = /ab+c/;|
|其他类型|Other Types||
|Null|表示故意缺少值的原始值;typeof null 返回 object 是历史兼容行为。|let empty = null;|
1. String
Section titled “1. String”let greeting = "Hello, World!";console.log(typeof greeting); // "string"2. Number
Section titled “2. Number”let age = 25;let pi = 3.14;console.log(typeof age); // "number"console.log(typeof pi); // "number"3. Boolean
Section titled “3. Boolean”let isActive = true;console.log(typeof isActive); // "boolean"4. Undefined
Section titled “4. Undefined”let x;console.log(typeof x); // "undefined"5. Null
Section titled “5. Null”let y = null;console.log(typeof y); // "object" (这是一个历史遗留问题)6. Symbol
Section titled “6. Symbol”let sym = Symbol("description");console.log(typeof sym); // "symbol"7. BigInt
Section titled “7. BigInt”let bigInt = 12345678901234567890n;console.log(typeof bigInt); // "bigint"8. Object
Section titled “8. Object”let person = { name: "John", age: 30};console.log(typeof person); // "object"9. Array
Section titled “9. Array”let numbers = [1, 2, 3, 4, 5];console.log(typeof numbers); // "object"10. Function
Section titled “10. Function”function greet() { return "Hello";}console.log(typeof greet); // "function"11. Date
Section titled “11. Date”let now = new Date();console.log(typeof now); // "object"12. Regular expression
Section titled “12. Regular expression”let regex = /ab+c/;console.log(typeof regex); // "object"在 JavaScript 中,类型转换是将一种数据类型转换为另一种数据类型的过程。类型转换可以分为两类:显式转换(Explicit Conversion)和隐式转换(Implicit Conversion)。
1. 显式类型转换
Section titled “1. 显式类型转换”显式类型转换是通过调用函数或使用操作符来强制转换数据类型。
-
字符串转换:使用
String()函数或toString()方法。let num = 123;let str = String(num); // "123"let str2 = num.toString(); // "123"let bool = true;let str3 = String(bool); // "true" -
数字转换:使用
Number()函数或parseInt()和parseFloat()。let str = "123";let num = Number(str); // 123let str2 = "123.45";let num2 = parseInt(str2); // 123let num3 = parseFloat(str2); // 123.45let bool = true;let num4 = Number(bool); // 1 -
布尔转换:使用
Boolean()函数。let str = "hello";let bool = Boolean(str); // truelet num = 0;let bool2 = Boolean(num); // false
2. 隐式类型转换
Section titled “2. 隐式类型转换”隐式类型转换是 JavaScript 在需要时自动进行的类型转换,也称为类型强制(Type Coercion)。
-
字符串转换:当使用
+运算符时,如果有一个操作数是字符串,另一个操作数会被转换为字符串。let num = 123;let str = "hello";let result = num + str; // "123hello" -
数字转换:当使用算术运算符(
-、*、/)时,操作数会被转换为数字。let str = "123";let num = str - 0; // 123let result = "10" * "2"; // 20let result2 = "10" / "2"; // 5 -
布尔转换:在逻辑运算中(
&&、||、!),操作数会被转换为布尔值。let str = "hello";let result = !str; // falselet result2 = !!str; // truelet result3 = str && "world"; // "world"
3. 特殊值转换
Section titled “3. 特殊值转换”一些特殊值的转换结果如下:
null转换为数字:0undefined转换为数字:NaNnull转换为布尔值:falseundefined转换为布尔值:false- 空字符串
""转换为数字:0 - 非空字符串转换为数字:字符串内容解析为数字(如果可能),否则为
NaN - 空字符串
""转换为布尔值:false - 非空字符串转换为布尔值:
true
console.log(Number(null)); // 0console.log(Number(undefined)); // NaNconsole.log(Boolean(null)); // falseconsole.log(Boolean(undefined)); // falseconsole.log(Number("")); // 0console.log(Number("123abc")); // NaNconsole.log(Boolean("")); // falseconsole.log(Boolean("hello")); // true字符串格式化
Section titled “字符串格式化”JavaScript 字符串格式化可以通过多种方式实现,以下是几种常见的方法:
1. 使用模板字符串 (Template Literals)
Section titled “1. 使用模板字符串 (Template Literals)”这种方法是最简洁和现代的方式,适用于 ES6 及更高版本。
let name = "Alice";let age = 30;console.log(`My name is ${name} and I am ${age} years old.`);2. 使用 String.prototype.replace()
Section titled “2. 使用 String.prototype.replace()”可以通过使用 replace() 方法结合正则表达式来实现简单的字符串替换。
let template = "My name is {name} and I am {age} years old.";let name = "Alice";let age = 30;let result = template.replace("{name}", name).replace("{age}", age);console.log(result);3. 使用数组的 join() 方法
Section titled “3. 使用数组的 join() 方法”这种方法适用于简单的字符串拼接。
let name = "Alice";let age = 30;console.log(["My name is ", name, " and I am ", age, " years old."].join(''));4. 自定义格式化函数
Section titled “4. 自定义格式化函数”可以创建一个通用的格式化函数来处理更复杂的格式化需求。
function formatString(template, replacements) { return template.replace(/{(\w+)}/g, function(match, key) { return typeof replacements[key] !== 'undefined' ? replacements[key] : match; });}
let template = "My name is {name} and I am {age} years old.";let replacements = { name: "Alice", age: 30 };console.log(formatString(template, replacements));5. 使用第三方库(如 sprintf-js)
Section titled “5. 使用第三方库(如 sprintf-js)”如果需要更多功能,可以使用第三方库。sprintf-js 是一个流行的库,类似于 C 语言中的 sprintf 函数。
首先需要安装该库:
npm install sprintf-js然后可以这样使用:
const sprintf = require('sprintf-js').sprintf;
let name = "Alice";let age = 30;console.log(sprintf("My name is %s and I am %d years old.", name, age));6. 使用 String.prototype.concat()
Section titled “6. 使用 String.prototype.concat()”这是一个简单的字符串拼接方法。
let name = "Alice";let age = 30;console.log("My name is ".concat(name, " and I am ", age, " years old."));以下是 JavaScript 中常见的运算符及其说明和示例:
|运算符类型|运算符|描述|示例|结果|
|---|---|---|---|---|
|算术运算符|+|加法|5 + 2|7|
||-|减法|5 - 2|3|
||*|乘法|5 * 2|10|
||/|除法|5 / 2|2.5|
||%|取余|5 % 2|1|
||**|幂运算|5 ** 2|25|
||++|自增|let a = 5; a++|6|
||--|自减|let a = 5; a--|4|
|赋值运算符|=|赋值|let a = 5|a = 5|
||+=|加法赋值|let a = 5; a += 2|a = 7|
||-=|减法赋值|let a = 5; a -= 2|a = 3|
||*=|乘法赋值|let a = 5; a *= 2|a = 10|
||/=|除法赋值|let a = 5; a /= 2|a = 2.5|
||%=|取余赋值|let a = 5; a %= 2|a = 1|
||**=|幂赋值|let a = 5; a **= 2|a = 25|
|比较运算符|==|等于|5 == '5'|true|
||===|全等|5 === '5'|false|
||!=|不等于|5 != '5'|false|
||!==|不全等|5 !== '5'|true|
||>|大于|5 > 2|true|
||<|小于|5 < 2|false|
||>=|大于等于|5 >= 2|true|
||<=|小于等于|5 <= 2|false|
|逻辑运算符|&&|逻辑与|true && false|false|
|||||逻辑或|true || false|true|
||!|逻辑非|!true|false|
|位运算符|&|按位与|5 & 1|1|
||||按位或|5 | 1|5|
||^|按位异或|5 ^ 1|4|
||~|按位非|~5|-6|
||<<|左移|5 << 1|10|
||>>|右移|5 >> 1|2|
||>>>|无符号右移|5 >>> 1|2|
|其他运算符|typeof|返回变量的数据类型|typeof 5|"number"|
||instanceof|检查对象是否是某个类的实例|obj instanceof Object|true|
||in|检查对象中是否存在某个属性|'name' in obj|true|
||new|创建一个对象实例|let obj = new Object()|obj|
||this|引用当前对象|this.name|当前对象的 name|
||void|计算表达式但不返回值|void(0)|undefined|
||,|计算多个表达式并返回最后一个表达式的值|(1, 2, 3)|3|
||? :|三元运算符(条件运算符)|let result = (a > b) ? 'a is greater' : 'b is greater';|取决于条件|
let sum = 5 + 2; // 7let diff = 5 - 2; // 3let product = 5 * 2; // 10let quotient = 5 / 2; // 2.5let remainder = 5 % 2; // 1let exponent = 5 ** 2; // 25let a = 5;a++; // 6a--; // 5let a = 5;a += 2; // 7a -= 2; // 5a *= 2; // 10a /= 2; // 5a %= 2; // 1a **= 2; // 25console.log(5 == '5'); // trueconsole.log(5 === '5'); // falseconsole.log(5 != '5'); // falseconsole.log(5 !== '5'); // trueconsole.log(5 > 2); // trueconsole.log(5 < 2); // falseconsole.log(5 >= 2); // trueconsole.log(5 <= 2); // falseconsole.log(true && false); // falseconsole.log(true || false); // trueconsole.log(!true); // falseconsole.log(5 & 1); // 1console.log(5 | 1); // 5console.log(5 ^ 1); // 4console.log(~5); // -6console.log(5 << 1); // 10console.log(5 >> 1); // 2console.log(5 >>> 1); // 2const obj = { name: "demo" };const a = 2;const b = 1;
console.log(typeof 5); // "number"console.log(obj instanceof Object); // trueconsole.log("name" in obj); // trueconsole.log(obj.name); // "demo"console.log(void 0); // undefinedconsole.log((1, 2, 3)); // 3let result = (a > b) ? "a is greater" : "b is greater";-
条件语句
const age = 20;if (age > 18) {console.log('Adult');} else if (age > 12) {console.log('Teenager');} else {console.log('Child');}// switchlet day = 3;let dayName;switch (day) {case 1:dayName = 'Monday';break;case 2:dayName = 'Tuesday';break;case 3:dayName = 'Wednesday';break;case 4:dayName = 'Thursday';break;case 5:dayName = 'Friday';break;case 6:dayName = 'Saturday';break;case 7:dayName = 'Sunday';break;default:dayName = 'Invalid day';}// 三元运算符let message = age > 18 ? 'Adult' : 'Not an adult'; -
循环
// For 循环for (let i = 0; i < 5; i++) { console.log(i);}
// While 循环let i = 0;while (i < 5) { console.log(i);i++;}
// Do-While 循环let j = 0;do { console.log(j); j++;} while (j < 5);
// for...in 循环用于遍历对象的可枚举属性let obj = { name: 'John', age: 30 };for (let key in obj) { console.log(key + ": " + obj[key]);}
// for...of 循环用于遍历可迭代对象(如数组、字符串、Map、Set 等)let arr = [1, 2, 3, 4, 5];for (let value of arr) { console.log(value);}手动实现 for..of
Section titled “手动实现 for..of”JavaScript 的迭代器是一种具有 next() 方法的对象,每次调用该方法都会返回一个包含 value 和 done 属性的对象。
- 使用迭代器手动实现 for……of
// 定义一个数组const arr = [1, 2, 3, 4, 5];
// 获取数组的迭代器const iterator = arr[Symbol.iterator]();
let result = iterator.next();while (!result.done) { console.log(result.value); // 输出当前值 result = iterator.next(); // 获取下一个值}- 使用生成器手动实现 for……of
// 定义一个生成器函数function* generator(arr) { for (let i = 0; i < arr.length; i++) { yield arr[i]; }}
// 定义一个数组const arr = [1, 2, 3, 4, 5];
// 获取生成器的迭代器const iterator = generator(arr);
let result = iterator.next();while (!result.done) { console.log(result.value); // 输出当前值 result = iterator.next(); // 获取下一个值}自定义可迭代对象
const myIterable = { data: [1, 2, 3, 4, 5], [Symbol.iterator]() { let index = 0; let data = this.data;
return { next() { if (index < data.length) { return { value: data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; }};
for (const value of myIterable) { console.log(value); // 输出值}-
函数声明
function greet(name) {return 'Hello ' + name;} -
函数表达式
const greet = function(name) {return 'Hello ' + name;}; -
箭头函数 (ES6)
const greet = (name) => 'Hello ' + name; -
默认参数函数 (ES6)
function greet(name = 'Guest') {console.log(`Hello, ${name}!`);}
-
声明和方法
let arr = [1, 2, 3, 4, 5];arr.push(6); // 添加 6 到末尾arr.pop(); // 移除最后一个元素arr.shift(); // 移除第一个元素arr.unshift(0); // 添加 0 到开头arr.splice(2, 1, 99); // 移除索引2处的1个元素,添加99arr.slice(1, 3); // 返回索引1到3之间的一个新数组(不包括3)
-
访问和修改属性
let person = {name: 'John',age: 30};console.log(person.name); // Johnconsole.log(person['age']); // 30person.name = 'Jane';person['age'] = 25;
解构赋值 (ES6)
Section titled “解构赋值 (ES6)”-
数组
let [a, b] = [1, 2]; -
对象
let { name, age } = { name: 'John', age: 30 };
扩展运算符和剩余参数 (ES6)
Section titled “扩展运算符和剩余参数 (ES6)”-
扩展运算符
let arr1 = [1, 2, 3];let arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]let obj1 = { name: 'John', age: 30 };let obj2 = { ...obj1, gender: 'male' }; // { name: 'John', age: 30, gender: 'male' } -
剩余参数
function sum(...args) {return args.reduce((acc, val) => acc + val, 0);}
类 (ES6)
Section titled “类 (ES6)”-
声明和继承
class Person {constructor(name, age) {this.name = name;this.age = age;}greet() {return `Hello, my name is ${this.name}`;}}class Student extends Person {constructor(name, age, grade) {super(name, age);this.grade = grade;}study() {return `${this.name} is studying`;}}
在 JavaScript 中,每个对象都有一个原型(prototype),对象可以通过原型继承属性和方法。原型链(prototype chain)是实现继承的一种方式,它是一系列对象的链接,这些对象通过原型属性相互连接。
-
原型对象 (Prototype Object):
- 每个 JavaScript 对象(除了
null)都有一个关联的对象,称为原型对象。 - 对象可以通过原型对象继承属性和方法。
- 每个 JavaScript 对象(除了
-
__proto__属性:- 每个对象都有一个
__proto__属性,指向其原型对象。 - 这个属性是访问内部
[[Prototype]]的方法。
- 每个对象都有一个
-
prototype属性:- 每个函数(包括构造函数)都有一个
prototype属性,这个属性指向一个对象,即该构造函数创建的实例的原型。
- 每个函数(包括构造函数)都有一个
// 定义一个构造函数function Person(name) { this.name = name;}
// 在 Person 的原型上添加方法Person.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name}`);};
// 创建一个实例const alice = new Person('Alice');
// 访问实例属性和原型方法console.log(alice.name); // 输出:Alicealice.sayHello(); // 输出:Hello, my name is Alice
// 检查实例的原型console.log(alice.__proto__ === Person.prototype); // 输出:true原型链的工作原理
Section titled “原型链的工作原理”当访问一个对象的属性或方法时,JavaScript 引擎会首先在该对象本身查找。如果找不到,它会沿着原型链向上查找,直到找到该属性或到达原型链的末尾(即 null)。
// 定义一个构造函数function Animal(name) { this.name = name;}
Animal.prototype.eat = function() { console.log(`${this.name} is eating`);};
// 定义另一个构造函数function Dog(name, breed) { Animal.call(this, name); // 继承属性 this.breed = breed;}
// 继承方法Dog.prototype = Object.create(Animal.prototype);Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() { console.log(`${this.name} is barking`);};
// 创建一个实例const rover = new Dog('Rover', 'Labrador');
// 访问属性和方法console.log(rover.name); // 输出:Roverconsole.log(rover.breed); // 输出:Labradorrover.eat(); // 输出:Rover is eatingrover.bark(); // 输出:Rover is barking
// 检查实例的原型链console.log(rover.__proto__ === Dog.prototype); // 输出:trueconsole.log(rover.__proto__.__proto__ === Animal.prototype); // 输出:trueconsole.log(rover.__proto__.__proto__.__proto__ === Object.prototype); // 输出:trueconsole.log(rover.__proto__.__proto__.__proto__.__proto__ === null); // 输出:true模块 (ES6)
Section titled “模块 (ES6)”-
导出和导入
// 导出export const name = 'John';export function greet() {return 'Hello';}// 导入import { name, greet } from './module';
Promise (ES6)
Section titled “Promise (ES6)”let promise = new Promise((resolve, reject) => { let success = true; if (success) { resolve('Success'); } else { reject('Error'); }});
promise .then(result => console.log(result)) .catch(error => console.log(error));异步函数 (ES8)
Section titled “异步函数 (ES8)”async function fetchData() { try { let response = await fetch('https://api.example.com/data'); let data = await response.json(); console.log(data); } catch (error) { console.log(error); }}