当前位置: 首页 > news >正文

javascript入门

1 js基本语法

1.1 基础

1. var 和 let 的核心区别详解

```javascript
// 函数作用域(var)
function testVar() {for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出 3, 3, 3}
}// 块级作用域(let)
function testLet() {for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出 0, 1, 2}
}// 常量(const)
const PI = 3.14;
// PI = 3.1415; // 报错:Assignment to constant variable
testLet();
testVar();

console 是 JavaScript 中的一个内置全局对象,用于向浏览器控制台或 Node.js 终端输出信息

一、作用域范围不同

  • var:函数作用域(Function Scope)
    在函数内部使用 var 声明的变量,仅在该函数内可见,不会被块级作用域限制

    function example() {if (true) {var x = 10; // var 在函数内有效,而非块内}console.log(x); // 输出 10
    }
    
  • let:块级作用域(Block Scope)
    使用 let 声明的变量仅在最近的大括号 {} 内有效(如 ifforwhile 块)。

    function example() {if (true) {let y = 20; // let 仅在 if 块内有效}console.log(y); // 报错:y is not defined
    }
    

二、变量提升机制不同

  • var:存在变量提升(Hoisting)
    var 声明的变量会被提升到作用域顶部,但赋值不会提升。

    console.log(a); // 输出 undefined(变量已提升,但未赋值)
    var a = 10;
    
  • let:不存在变量提升,存在“暂时性死区”(Temporal Dead Zone, TDZ)
    let 声明的变量在声明前无法访问,访问会报错。

    console.log(b); // 报错:Cannot access 'b' before initialization
    let b = 20;
    

三、重复声明处理不同

  • var:允许在同一作用域内重复声明同一变量

    var c = 1;
    var c = 2; // 合法,c 的值变为 2
    
  • let:禁止在同一作用域内重复声明同一变量

    let d = 1;
    let d = 2; // 报错:Identifier 'd' has already been declared
    

四、在循环中的表现差异

  • var:在循环中声明的变量会被共享到整个函数作用域

    function testVar() {for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出 3, 3, 3}
    }
    

    原因:3 个定时器回调共享同一个 i,循环结束后 i 的值为 3,回调执行时读取的是最终值。

  • let:在循环中会为每次迭代创建独立的变量

    function testLet() {for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 100); // 输出 0, 1, 2}
    }
    

    原因:每次循环都会生成一个独立的 i,回调函数捕获的是当前迭代的 i 值。

总结对比表

特性varlet
作用域函数作用域块级作用域
变量提升存在,初始化为 undefined不存在,存在暂时性死区
重复声明允许禁止
循环中的表现所有迭代共享同一变量每次迭代创建独立变量
是否推荐使用不推荐(ES6 后)推荐

2. 基本数据类型

  • 值类型:Number、String、Boolean、null、undefined、Symbol(ES6)
  • 引用类型:Object(包括数组、函数、日期等)
// 值类型
const num = 42;
const str = "Hello";
const isDone = false;
const nothing = null;
let unknown; // undefined// 引用类型
const obj = { name: "John", age: 30 };
const arr = [1, 2, 3];
const func = function() { return 42; };

JavaScript 和 Python 都是动态类型语言,变量的类型是在运行时确定的,而不是在编写代码时强制指定

3.控制

// if-else
const age = 18;
if (age < 18) {console.log("未成年");
} else if (age >= 18 && age < 60) {console.log("成年");
} else {console.log("老年");
}// switch
const day = 3;
switch (day) {case 1:console.log("周一");break;case 2:console.log("周二");break;default:console.log("其他");
}

4.循环

// for 循环
for (let i = 0; i < 3; i++) {console.log(i); // 输出 0, 1, 2
}// while 循环
let j = 0;
while (j < 3) {console.log(j); // 输出 0, 1, 2j++;
}// for...of 遍历数组
const colors = ["red", "green", "blue"];
for (const color of colors) {console.log(color); // 输出 "red", "green", "blue"
}// for...in 遍历对象
const person = { name: "John", age: 30 };
for (const key in person) {console.log(`${key}: ${person[key]}`); // 输出 "name: John", "age: 30"
}

1.2 中级-函数

一、函数定义与调用

  1. 函数声明(Function Declaration)
  • 语法function 函数名(参数) { ... }
  • 特点:函数声明会被提升(Hoisting),可在定义前调用

示例

// 声明函数
function greet(name) {return `Hello, ${name}!`;
}// 调用函数
console.log(greet('John')); // 输出 "Hello, John!"
  1. 函数表达式(Function Expression)
  • 语法const 变量名 = function(参数) { ... }
  • 特点:函数作为值赋给变量,不会被提升

示例

// 匿名函数表达式
const add = function(a, b) {return a + b;
};// 具名函数表达式(便于递归或调试)
const factorial = function fact(n) {return n <= 1 ? 1 : n * fact(n - 1);
};console.log(factorial(5)); // 120
  1. 箭头函数(Arrow Function)
  • 语法(参数) => { ... }(参数) => 表达式
  • 特点:语法更简洁,无独立的 thisarguments

示例

// 基本箭头函数
const multiply = (a, b) => a * b;// 单参数省略括号
const square = x => x * x;// 无参数用空括号
const getRandom = () => Math.random();// 多行代码用大括号
const sumArray = arr => {let total = 0;for (const num of arr) {total += num;}return total;
};

二、参数与返回值

  1. 参数默认值
  • 语法function 函数名(参数 = 默认值) { ... }

示例

function greet(name = 'Guest') {return `Hello, ${name}!`;
}console.log(greet()); // 输出 "Hello, Guest!"
console.log(greet('John')); // 输出 "Hello, John!"
  1. 剩余参数(Rest Parameters)
  • 语法function 函数名(...参数名) { ... }
  • 作用:将多个参数收集为数组

示例

function sum(...numbers) {return numbers.reduce((total, num) => total + num, 0);
}console.log(sum(1, 2, 3)); // 输出 6
console.log(sum(1, 2, 3, 4, 5)); // 输出 15

数组.reduce(callback(累积值, 当前值, 当前索引, 原数组), 初始值); 缺省了

三、异步函数
1. 回调函数(Callback)
定义:作为参数传递给另一个函数的函数
应用:处理异步操作(如定时器、AJAX 请求)

示例

function fetchData(callback) {setTimeout(() => {const data = { message: 'Data loaded' };callback(data);}, 1000);
}fetchData(data => {console.log(data.message); // 1秒后输出 "Data loaded"
});
//setTimeout 这个内置函数 
//setTimeout(callback, delay, arg1, arg2, ...);

2. Promise
定义:表示异步操作的最终完成或失败
方法:then()、catch()、finally()

// 创建一个 Promise
function readFilePromise(filePath) {return new Promise((resolve, reject) => {// 模拟异步操作(如文件读取)setTimeout(() => {// 模拟文件内容const content = `这是 ${filePath} 的内容`;// 随机决定成功或失败const success = Math.random() > 0.3;if (success) {resolve(content); // 操作成功,返回数据} else {reject(new Error('读取文件失败')); // 操作失败,返回错误}}, 1000);});
}// 使用 Promise
readFilePromise('example.txt').then((data) => {console.log('成功:', data);//date==contentreturn data.toUpperCase(); // 链式调用,传递处理后的数据 内置函数}).then((uppercaseData) => {console.log('转换后:', uppercaseData);}).catch((error) => {console.error('错误:', error.message);}).finally(() => {console.log('无论成功失败都执行');});
  1. 创建 Promise
new Promise((resolve, reject) => {// 异步操作...if (成功) {resolve(结果); // 传递成功数据} else {reject(错误); // 传递失败原因}
});
  • resolve:异步操作成功时调用,传递结果。
  • reject:异步操作失败时调用,传递错误对象。

3. async/await
语法糖:基于 Promise,使异步代码更像同步代码
规则:
async 函数返回 Promise
await 暂停函数执行,等待 Promise 解决

示例

async function fetchData() {return new Promise(resolve => {setTimeout(() => resolve({ message: 'Async/await' }), 1000);});
}async function main() {try {const data = await fetchData();console.log(data.message); // 1秒后输出 "Async/await"} catch (error) {console.error(error);}

2 对象

  1. JavaScript:基于原型的动态对象
  • 特性
    • 动态类型:对象属性可随时添加、删除、修改。
    • 基于原型:通过原型链实现继承,无严格类定义。
    • 弱类型:属性值类型不固定。

示例

// 创建对象(无需类定义)
const person = {name: 'John',age: 30,greet() {return `Hello, I'm ${this.name}`;}
};// 动态添加属性
person.job = 'Engineer';// 修改方法
person.greet = function() {return `Hi, I'm ${this.name}, a ${this.job}`;
};console.log(person.greet()); // "Hi, I'm John, a Engineer"

2 、对象创建与初始化

// 1. 对象字面量(最常用)
const obj1 = {key: 'value',method() { return this.key; }
};// 2. 构造函数
function User(name) {this.name = name;this.sayHi = function() {return `Hi, ${this.name}`;};
}const user = new User('Alice');// 3. 类语法(ES6 糖衣)
class Car {constructor(model) {this.model = model;}drive() {return `${this.model} is driving`;}
}const car = new Car('Tesla');

3 JavaScript:原型链与组合继承

// 1. 原型链继承
class Animal {constructor(name) {this.name = name;}speak() {return `${this.name} makes a sound`;}
}class Dog extends Animal {constructor(name) {super(name);  // 调用父类构造函数}speak() {return `${this.name} barks`;  // 重写方法}
}const dog = new Dog('Buddy');
console.log(dog.speak());  // "Buddy barks"// 2. 组合继承(混入 mixin)
const flyMixin = {fly() {return `${this.name} is flying`;}
};Object.assign(Dog.prototype, flyMixin);  // 动态添加能力
console.log(dog.fly());  // "Buddy is flying"

4 JavaScript 的 prototype

一、prototype 就像「家族遗传」

想象一个家族:

  • 爷爷(基础模板)有一些特质(如蓝眼睛、高个子)。
  • 爸爸(继承爷爷)继承了这些特质,还发展了自己的技能(如弹钢琴)。
  • (继承爸爸)继承了爷爷和爸爸的特质,还增加了自己的爱好(如编程)。

JavaScript 中

  • 爷爷 = Object.prototype(所有对象的最终原型)。
  • 爸爸 = 你创建的一个对象(作为另一个对象的原型)。
  • = 基于原型创建的新对象。

示例

// 爷爷(基础模板)
const grandFather = {eyeColor: 'blue',height: 'tall'
};// 爸爸(继承爷爷)
const father = Object.create(grandFather);
father.playPiano = function() {return "Playing Mozart...";
};// 你(继承爸爸)
const you = Object.create(father);
you.code = function() {return "Coding JavaScript...";
};// 你可以使用所有继承的特质和技能
console.log(you.eyeColor);     // "blue"(来自爷爷)
console.log(you.playPiano());  // "Playing Mozart..."(来自爸爸)
console.log(you.code());       // "Coding JavaScript..."(你自己的)

二、prototype 的核心作用:

1. 共享属性和方法
  • 原型就像一个「共享仓库」,所有继承它的对象都能从中获取资源。
  • 优点:节省内存(属性和方法只需在原型中存储一次)。

类比

  • 家族有一个「共享工具箱」(原型),里面有锤子、螺丝刀等工具。
  • 家族成员(对象)不需要每个人都买一套工具,直接从工具箱拿即可。
  1. 动态更新
  • 修改原型会影响所有继承它的对象(就像家族传统改变,所有后代都会受影响)。

示例

const person = {species: 'Human'
};const alice = Object.create(person);
const bob = Object.create(person);console.log(alice.species);  // "Human"
console.log(bob.species);    // "Human"// 修改原型
person.species = 'Homo Sapiens';console.log(alice.species);  // "Homo Sapiens"(自动更新)
console.log(bob.species);    // "Homo Sapiens"(自动更新)

三、prototype vs 「类」的区别

1. 传统「类」的思维
  • 类(如 C++、Java)是「蓝图」,对象是「复制」。
  • 每个对象都有自己的属性副本。

类比

  • 汽车工厂有一份设计图(类),生产的每辆汽车(对象)都是设计图的独立复制。
  1. JavaScript 的原型思维
  • 对象直接关联其他对象(原型),无需复制。
  • 访问属性时,先看自己有没有,没有就去原型里找。

类比

  • 你开了一家奶茶店(对象),没有自己的配方(属性)。
  • 你直接用隔壁店(原型)的配方,顾客点单时,先看自己有没有记录,没有就去隔壁查。

四、构造函数与 prototype 的关系

当你用 new 创建对象时:

  1. JavaScript 先创建一个空对象。
  2. 将这个空对象的原型(__proto__)指向构造函数的 prototype 属性。
  3. 执行构造函数,并将 this 绑定到新对象。

示例

function Cat(name) {this.name = name;  // 为新对象添加属性
}// 向 Cat 的原型添加共享方法
Cat.prototype.meow = function() {return `${this.name} says Meow!`;
};const whiskers = new Cat('Whiskers');
console.log(whiskers.meow());  // "Whiskers says Meow!"// 实际上 whiskers 的原型指向 Cat.prototype
console.log(whiskers.__proto__ === Cat.prototype);  // true

五、原型链的查找过程

当你访问 obj.property 时:

  1. 先看 obj 自己有没有 property
  2. 如果没有,去 obj.__proto__ 里找。
  3. 如果还没有,去 obj.__proto__.__proto__ 里找。
  4. 以此类推,直到找到或到达 Object.prototype(如果还没有,返回 undefined)。

类比

  • 你想知道家族祖传的红烧肉做法:
    1. 先问自己(有没有记录)。
    2. 没有就问爸爸。
    3. 爸爸也不知道就问爷爷。
    4. 爷爷也不知道就问曾祖父。
    5. 如果所有人都不知道,那就没有这个配方。

六、ES6 类与原型的关系

ES6 的 class 只是原型的「语法糖」,让代码更像传统的类。

示例

// ES6 类(实际基于原型)
class Dog {constructor(name) {this.name = name;}bark() {return `${this.name} barks!`;}
}const buddy = new Dog('Buddy');// 本质上与原型方式相同
console.log(buddy.__proto__ === Dog.prototype);  // true

总结

JavaScript 的 prototype 就像:

  • 共享工具箱:多个对象共用一套工具。
  • 家族遗传:后代继承前代的特质和技能。
  • 查找链:先看自己有没有,没有就去原型里找。

记住

  • 原型是对象之间的「关联关系」,不是复制。
  • 理解 prototype,就能理解 JavaScript 的「继承」和「多态」。

Cat.prototype 是一个对象,所有 new Cat() 创建的实例都会继承它的属性和方法。
继承通过 proto 实现:cat.proto === Cat.prototype。

相关文章:

  • RT-Thread Studio 配置使用详细教程
  • Spring Cloud Gateway 介绍
  • 金蝶K3 ERP 跨网段访问服务器卡顿问题排查和解决方法
  • 用户态与内核态是什么?有什么作用?两者在什么时候切换?为什么要切换?
  • word用endnote插入国标参考文献
  • 【C++】多重继承与虚继承
  • IDEA2025(2025.1.1)都更新了什么???
  • DevSecOps实践:用Terraform策略检查筑牢基础设施安全防线
  • 蓝桥杯20112 不同的总分值
  • 金属切削机床制造企业如何破局?探索项目管理数字化转型
  • Redis:渐进式遍历
  • vue3 数据过滤方法
  • Linux笔记之Ubuntu22.04安装 fcitx5 输入法
  • 观点 | 科技企业到了品牌建设的历史性窗口期
  • PRIMES“中国校准实验室”正式运营,携手东隆科技共筑精准测量新标准
  • ROS2 工作空间中, CMakeLists.txt, setup.py和 package.xml的作用分别是?
  • [免费]微信小程序音乐播放器(爬取网易云音乐数据)(node.js后端)【论文+源码】
  • 智能眼镜销量暴涨 800%,科技革新引发消费热潮
  • docker compose安装Prometheus、Grafana
  • VAS1082Q奇力科技LED驱动芯片固定电流值用于车用市场
  • 设备上哪个网站做外贸推广/百度推广代理公司哪家好
  • 闵行网站制作/网站如何优化排名软件
  • 南宁太阳能网站建设/发外链的网址
  • 用什么系统做威客网站/网站优化查询
  • 要看网站是多少/二次感染即将大爆发
  • 网站建设与维护总结/站长工具站长