Skip to main content

JavaScript核心基础与现代特性

JavaScript是现代Web开发的核心语言,从简单的网页脚本发展为功能强大的编程语言,支持函数式编程、面向对象编程和异步编程等多种编程范式。掌握JavaScript的核心概念对于前端开发至关重要。

核心价值

JavaScript = 动态类型 + 函数式编程 + 面向对象 + 异步编程

  • 🔄 动态类型系统:灵活的类型转换和运行时类型检查
  • 🎯 函数式编程:高阶函数、闭包、纯函数等特性
  • 🏗️ 面向对象编程:原型链、类、继承等机制
  • 异步编程:Promise、async/await、事件循环
  • 🌐 跨平台能力:浏览器、Node.js、移动端统一语言
  • 📦 丰富生态:npm生态系统和无数开源库

1. JavaScript数据类型系统

1.1 数据类型分类

JavaScript有两大类数据类型:原始类型(Primitive Types)和引用类型(Reference Types)。

数据类型特性对比

类型分类存储方式赋值行为比较方式可变性
原始类型栈内存值拷贝值比较不可变
引用类型堆内存引用拷贝引用比较可变

原始类型深度解析

原始类型完整示例
javascript
1// 1. Number 数字类型
2const integer = 42; // 整数
3const float = 3.14159; // 浮点数
4const scientific = 1.23e-4; // 科学计数法
5const binary = 0b1010; // 二进制
6const octal = 0o755; // 八进制
7const hex = 0xFF; // 十六进制
8const infinity = Infinity; // 无穷大
9const notANumber = NaN; // 非数字
10
11// 数字类型检查和转换
12console.log(Number.isInteger(42)); // true
13console.log(Number.isNaN(NaN)); // true
14console.log(Number.parseFloat('3.14')); // 3.14
15console.log(Number.parseInt('42px')); // 42
16
17// 2. String 字符串类型
18const singleQuote = 'Hello World';
19const doubleQuote = "Hello World";
20const templateLiteral = `Hello ${name}`;
21const multiLine = `
22 这是一个
23 多行字符串
24`;
25
26// 字符串方法
27const text = "JavaScript";
28console.log(text.length); // 10
29console.log(text.toUpperCase()); // "JAVASCRIPT"
30console.log(text.slice(0, 4)); // "Java"
31console.log(text.includes('Script')); // true
32console.log(text.split('')); // ['J','a','v','a','S','c','r','i','p','t']
33
34// 3. Boolean 布尔类型
35const isTrue = true;
36const isFalse = false;
37
38// 布尔转换规则
39console.log(Boolean(0)); // false
40console.log(Boolean('')); // false
41console.log(Boolean(null)); // false
42console.log(Boolean(undefined)); // false
43console.log(Boolean(NaN)); // false
44console.log(Boolean([])); // true (空数组是真值)
45console.log(Boolean({})); // true (空对象是真值)
46
47// 4. Undefined 和 Null
48let undefinedVar; // undefined
49const nullVar = null; // null
50
51console.log(typeof undefined); // "undefined"
52console.log(typeof null); // "object" (历史遗留问题)
53console.log(undefined == null); // true (宽松相等)
54console.log(undefined === null); // false (严格相等)
55
56// 5. Symbol 符号类型 (ES6+)
57const symbol1 = Symbol('description');
58const symbol2 = Symbol('description');
59console.log(symbol1 === symbol2); // false (每个Symbol都是唯一的)
60
61// Symbol的应用场景
62const PRIVATE_KEY = Symbol('private');
63const obj = {
64 publicProperty: 'public',
65 [PRIVATE_KEY]: 'private'
66};
67
68// 6. BigInt 大整数类型 (ES2020+)
69const bigInt1 = 123456789012345678901234567890n;
70const bigInt2 = BigInt('123456789012345678901234567890');
71console.log(bigInt1 === bigInt2); // true
72
73// BigInt运算
74console.log(bigInt1 + 1n); // 需要使用BigInt进行运算
75// console.log(bigInt1 + 1); // TypeError: 不能混合BigInt和Number

2. 变量与作用域

2.1 变量声明方式

JavaScript提供了三种变量声明方式:varletconst,它们在作用域、提升和重复声明方面有重要区别。

变量声明对比表

特性varletconst推荐使用
作用域函数作用域块级作用域块级作用域let/const
变量提升否(暂时性死区)否(暂时性死区)let/const
重复声明允许不允许不允许let/const
重新赋值允许允许不允许根据需求
全局对象属性let/const

var声明的问题

var声明问题示例
javascript
1// 1. 函数作用域问题
2function varScopeIssue() {
3 if (true) {
4 var x = 1;
5 }
6 console.log(x); // 1 - var没有块级作用域
7}
8
9// 2. 变量提升问题
10console.log(hoistedVar); // undefined - 变量提升但未赋值
11var hoistedVar = 'Hello';
12
13// 等价于:
14// var hoistedVar;
15// console.log(hoistedVar); // undefined
16// hoistedVar = 'Hello';
17
18// 3. 循环中的问题
19for (var i = 0; i < 3; i++) {
20 setTimeout(() => {
21 console.log('var:', i); // 输出: 3, 3, 3
22 }, 100);
23}
24
25// 4. 重复声明问题
26var name = 'John';
27var name = 'Jane'; // 不会报错,但可能导致意外覆盖
28console.log(name); // 'Jane'
29
30// 5. 全局对象污染
31var globalVar = 'I am global';
32console.log(window.globalVar); // 'I am global' (在浏览器中)

3. 函数与作用域

3.1 函数定义方式

JavaScript提供了多种函数定义方式,每种方式都有其特定的用途和特性。

函数定义方式详解

函数定义方式对比
javascript
1// 1. 函数声明 (Function Declaration)
2function greet(name) {
3 return `Hello, ${name}!`;
4}
5
6// 函数声明会被提升,可以在声明前调用
7console.log(sayHello('World')); // "Hello, World!"
8
9function sayHello(name) {
10 return `Hello, ${name}!`;
11}
12
13// 2. 函数表达式 (Function Expression)
14const greetExpression = function(name) {
15 return `Hello, ${name}!`;
16};
17
18// 命名函数表达式
19const greetNamed = function greetFunction(name) {
20 return `Hello, ${name}!`;
21};
22
23// 3. 箭头函数 (Arrow Function)
24const greetArrow = (name) => {
25 return `Hello, ${name}!`;
26};
27
28// 简化的箭头函数
29const greetShort = name => `Hello, ${name}!`;
30
31// 无参数箭头函数
32const getCurrentTime = () => new Date().toISOString();
33
34// 多参数箭头函数
35const add = (a, b) => a + b;
36
37// 返回对象字面量(需要括号)
38const createUser = (name, age) => ({ name, age, id: Date.now() });
39
40// 4. 方法定义
41const obj = {
42 // 传统方法定义
43 greet: function(name) {
44 return `Hello, ${name}!`;
45 },
46
47 // ES6简写方法
48 greetShort(name) {
49 return `Hello, ${name}!`;
50 },
51
52 // 箭头函数方法(注意this绑定)
53 greetArrow: (name) => {
54 // 这里的this不指向obj
55 return `Hello, ${name}!`;
56 }
57};
58
59// 5. 构造函数
60function Person(name, age) {
61 this.name = name;
62 this.age = age;
63 this.greet = function() {
64 return `Hello, I'm ${this.name}`;
65 };
66}
67
68// 使用new关键字创建实例
69const person = new Person('John', 30);
70
71// 6. 生成器函数
72function* numberGenerator() {
73 let i = 0;
74 while (true) {
75 yield i++;
76 }
77}
78
79const gen = numberGenerator();
80console.log(gen.next().value); // 0
81console.log(gen.next().value); // 1
82
83// 7. 异步函数
84async function fetchData(url) {
85 try {
86 const response = await fetch(url);
87 const data = await response.json();
88 return data;
89 } catch (error) {
90 console.error('Fetch error:', error);
91 throw error;
92 }
93}
94
95// 异步箭头函数
96const fetchDataArrow = async (url) => {
97 const response = await fetch(url);
98 return response.json();
99};
100
101// 8. 立即执行函数表达式 (IIFE)
102(function() {
103 console.log('IIFE executed immediately');
104})();
105
106// 箭头函数IIFE
107(() => {
108 console.log('Arrow IIFE executed');
109})();
110
111// 带参数的IIFE
112((name) => {
113 console.log(`Hello, ${name}!`);
114})('World');
115
116// 9. 高阶函数
117function createMultiplier(factor) {
118 return function(number) {
119 return number * factor;
120 };
121}
122
123const double = createMultiplier(2);
124const triple = createMultiplier(3);
125
126console.log(double(5)); // 10
127console.log(triple(4)); // 12
128
129// 10. 函数作为参数
130function processArray(arr, callback) {
131 const result = [];
132 for (let i = 0; i < arr.length; i++) {
133 result.push(callback(arr[i], i, arr));
134 }
135 return result;
136}
137
138const numbers = [1, 2, 3, 4, 5];
139const doubled = processArray(numbers, x => x * 2);
140console.log(doubled); // [2, 4, 6, 8, 10]

4. 对象与原型

4.1 对象创建与操作

JavaScript中的对象是键值对的集合,是语言的核心数据结构。

对象创建方式

对象创建方式详解
javascript
1// 1. 对象字面量(最常用)
2const person = {
3 name: 'John',
4 age: 30,
5 city: 'New York',
6
7 // 方法
8 greet() {
9 return `Hello, I'm ${this.name}`;
10 },
11
12 // 计算属性名
13 ['full' + 'Name']: 'John Doe',
14
15 // 属性简写
16 // 如果变量名和属性名相同,可以简写
17 // name, // 等价于 name: name
18};
19
20// 2. Object构造函数
21const person2 = new Object();
22person2.name = 'Jane';
23person2.age = 25;
24person2.greet = function() {
25 return `Hello, I'm ${this.name}`;
26};
27
28// 3. Object.create()
29const personPrototype = {
30 greet() {
31 return `Hello, I'm ${this.name}`;
32 },
33
34 setAge(age) {
35 this.age = age;
36 }
37};
38
39const person3 = Object.create(personPrototype);
40person3.name = 'Bob';
41person3.age = 35;
42
43// 4. 构造函数
44function Person(name, age) {
45 this.name = name;
46 this.age = age;
47}
48
49Person.prototype.greet = function() {
50 return `Hello, I'm ${this.name}`;
51};
52
53const person4 = new Person('Alice', 28);
54
55// 5. 类语法(ES6+)
56class PersonClass {
57 constructor(name, age) {
58 this.name = name;
59 this.age = age;
60 }
61
62 greet() {
63 return `Hello, I'm ${this.name}`;
64 }
65
66 static createAnonymous() {
67 return new PersonClass('Anonymous', 0);
68 }
69}
70
71const person5 = new PersonClass('Charlie', 32);
72
73// 6. 工厂函数
74function createPerson(name, age) {
75 return {
76 name,
77 age,
78 greet() {
79 return `Hello, I'm ${this.name}`;
80 }
81 };
82}
83
84const person6 = createPerson('David', 27);
85
86// 7. 使用Object.assign()
87const defaultPerson = {
88 name: 'Unknown',
89 age: 0,
90 city: 'Unknown'
91};
92
93const person7 = Object.assign({}, defaultPerson, {
94 name: 'Eve',
95 age: 29
96});
97
98// 8. 使用扩展运算符
99const person8 = {
100 ...defaultPerson,
101 name: 'Frank',
102 age: 31
103};
104
105// 9. 动态属性创建
106function createObjectWithDynamicProps(props) {
107 const obj = {};
108
109 for (const [key, value] of Object.entries(props)) {
110 obj[key] = value;
111 }
112
113 return obj;
114}
115
116const dynamicPerson = createObjectWithDynamicProps({
117 name: 'Grace',
118 age: 26,
119 occupation: 'Developer'
120});
121
122// 10. 使用Proxy创建对象
123const personProxy = new Proxy({}, {
124 set(target, property, value) {
125 if (property === 'age' && (typeof value !== 'number' || value < 0)) {
126 throw new Error('Age must be a positive number');
127 }
128 target[property] = value;
129 return true;
130 },
131
132 get(target, property) {
133 if (property === 'info') {
134 return `${target.name} is ${target.age} years old`;
135 }
136 return target[property];
137 }
138});
139
140personProxy.name = 'Henry';
141personProxy.age = 33;
142console.log(personProxy.info); // "Henry is 33 years old"

面试题

1. 解释JavaScript中的变量提升

答案: 变量提升是JavaScript引擎在执行代码前,将变量和函数声明移动到其作用域顶部的行为。

  • var声明:变量声明被提升,但赋值不会提升,初始值为undefined
  • let/const声明:声明被提升,但存在暂时性死区,访问会报错
  • 函数声明:整个函数定义都会被提升
  • 函数表达式:只有变量声明被提升,函数定义不会

2. 什么是闭包?闭包有什么用途?

答案: 闭包是指内部函数可以访问外部函数作用域中变量的特性,即使外部函数已经执行完毕。

用途:

  • 数据封装和私有变量
  • 模块模式
  • 函数工厂
  • 回调函数中保持状态
  • 记忆化和缓存

3. 解释JavaScript的原型链

答案: 原型链是JavaScript实现继承的机制。每个对象都有一个内部属性[[Prototype]],指向其原型对象。当访问对象属性时,如果对象本身没有该属性,就会沿着原型链向上查找。

查找顺序:对象本身 → 对象原型 → 原型的原型 → ... → Object.prototype → null

4. this关键字的绑定规则是什么?

答案: this的绑定遵循以下规则(优先级从高到低):

  1. new绑定:使用new调用函数时,this绑定到新创建的对象
  2. 显式绑定:使用call、apply、bind时,this绑定到指定对象
  3. 隐式绑定:作为对象方法调用时,this绑定到该对象
  4. 默认绑定:独立函数调用时,this绑定到全局对象(严格模式下为undefined)

箭头函数不遵循这些规则,它的this由词法作用域决定。

5. 如何实现对象的深拷贝?

答案:

javascript
1function deepClone(obj) {
2 if (obj === null || typeof obj !== 'object') {
3 return obj;
4 }
5
6 if (obj instanceof Date) {
7 return new Date(obj.getTime());
8 }
9
10 if (obj instanceof Array) {
11 return obj.map(item => deepClone(item));
12 }
13
14 if (typeof obj === 'object') {
15 const clonedObj = {};
16 for (const key in obj) {
17 if (obj.hasOwnProperty(key)) {
18 clonedObj[key] = deepClone(obj[key]);
19 }
20 }
21 return clonedObj;
22 }
23}

其他方法:

  • JSON.parse(JSON.stringify(obj))(有限制)
  • 使用Lodash的cloneDeep
  • 使用structuredClone(现代浏览器)

通过掌握这些JavaScript核心概念,可以编写更高质量、更可维护的代码,并为学习更高级的JavaScript特性打下坚实基础。

参与讨论