外贸 需要到国外建网站吗,聊城网站百度推广,光明新区网站建设,平度网站制作1.var和let的区别
1.1作用域与有效范围
var 在函数或全局作用域中声明变量#xff0c;无论在块级作用域内外都可以访问。
var 即使在块级作用域外部访问#xff0c;仍然能获取到结果。
let 在块级作用域内声明变量#xff0c;仅在其所在的作用域中有效。
let 如果在作用域…1.var和let的区别
1.1作用域与有效范围
var 在函数或全局作用域中声明变量无论在块级作用域内外都可以访问。
var 即使在块级作用域外部访问仍然能获取到结果。
let 在块级作用域内声明变量仅在其所在的作用域中有效。
let 如果在作用域外访问会抛出 ReferenceError// 示例{var a 10;let b 20;}console.log(a); // 10 (var 在全局或函数作用域内有效)console.log(b); // ReferenceError: b is not defined (let 仅在块级作用域内有效)1.2重复定义
var: 可以在同一个作用域内多次声明同名变量而不会抛出错误后面声明的变量会覆盖前面的值。
let: 不允许在同一作用域内重复声明同名变量重复声明会抛出 SyntaxError。// 示例{var a 1;var a 2; // 无报错a 赋值为 2console.log(a); // 2let b 1;//let b 2; // 报错Uncaught SyntaxError: Identifier b has already been declaredconsole.log(b); // 1}1.3变量提升 var: 变量声明会被提升到作用域的顶部但赋值不会被提升因此会在使用变量前显示为 undefined。let: 变量声明不会被提升尝试在声明前访问会抛出 ReferenceError因为变量在声明之前处于“暂时性死区TDZ。// 示例
{console.log(a); // undefined (var 变量会提升初始化为 undefined)var a 10;console.log(b); // Uncaught ReferenceError: Cannot access b before initializationlet b 10; // let 变量不会提升访问前会抛出错误}1.4块级作用域与闭包
var在块级作用域内声明的变量会被提升到函数或全局作用域因此可能会影响闭包的行为。
let创建的是块级作用域变量避免了 var 在闭包中的不期望行为。// 示例
for (var i 0; i 3; i) {setTimeout(function () {console.log(i); // 输出 3, 由于 var 的提升i 的值在 for 循环外部是 3}, 100);}for (let j 0; j 3; j) {setTimeout(function () {console.log(j); // 输出 0, 1, 2, 因为 let 会在每次迭代中创建新的作用域}, 100);}1.5总结
var 和 let 的主要区别在于作用域、变量提升、以及是否支持重复定义。
var 是函数作用域或全局作用域且会提升到顶部let 是块级作用域不会提升。
let 在闭包和异步代码中表现得更稳定避免了 var 可能带来的问题。// 示例{var a 10;let b 20;}console.log(a); // 10 (var 在全局或函数作用域内有效)console.log(b); // ReferenceError: b is not defined (let 仅在块级作用域内有效)2.const 与 let 的差异
const: 声明的是常量必须在声明时初始化且值不能修改。
但 const 声明的是引用类型的对象时对象的内容是可变的只是不能重新赋值给其他对象。const a 10;
a 20; // Uncaught TypeError: Assignment to constant variable.
console.log(a)const obj {name: tom,age: 18};
obj.age 22;
console.log(obj) // {name: tom, age: 22}
obj {}; // Uncaught TypeError: Assignment to constant variable.总结var 和 let 的主要区别在于作用域、变量提升、以及是否支持重复定义。var 是函数作用域或全局作用域且会提升到顶部let 是块级作用域不会提升。let 在闭包和异步代码中表现得更稳定避免了 var 可能带来的问题。3.解构
3.1数组解构
解构赋值允许从数组中提取值并赋给变量。通过解构语法我们可以更简洁地获取数组元素。let arr [1, 2, 3]
let [a, b, c] arr
// 等价于
// let a arr[0]
// let b arr[1]
// let c arr[2]
console.log(a)
console.log(b)
console.log(c)3.2对象解构
对象解构允许从对象中提取值并赋给变量变量名必须与对象的属性名相同。let obj { name: tom, age: 18 };
let { name, age } obj
// 等价于
// let name obj.name
// let age obj.age
console.log(name)
console.log(age)4.链判断
可选链在判断中间属性是否存在时会自动短路并返回 undefined避免了显式的检查
可选链允许我们在访问深层嵌套对象的属性时避免因中间某一属性为 null 或 undefined 而导致的错误。let content null;
// 传统的链式判断
const username (content content.body content.body.user content.body.user.username) || defalut;
console.log(username)
//使用可选链?.
const uname content?.body?.user?.username || default;
console.log(uname)5.参数默认值
传统的参数默认值 使用 || 操作符来为参数提供默认值但当参数为 0 或 false 时也会被误判为“假值”。function add(a, b) {b b || 10; // 如果 b 为 falsy 值例如 0则默认赋值为 10return a b;
}
console.log(add(10)); // 20//使用 ES6 的默认参数值 通过在函数声明时直接为参数提供默认值避免了上面的问题。此方法仅在参数为 undefined 时生效而不是 null 或 0 等其他“假值”。function add2(a, b 10) {return a b;}
console.log(add2(10)); // 206.箭头函数
6.1一个参数 箭头函数提供了更简洁的函数表达式且默认绑定函数的 this
let print1 function (obj) {console.log(obj);
};
let print2 obj console.log(obj); // 箭头函数简写形式6.2两个参数 如果有多个参数则使用括号包裹参数。
let sum function (a, b) {return a b;
}
let sum2 (a, b) a b;6.3当箭头函数有多行语句时必须使用大括号 {} 并明确 return
let sum3 (a, b) {c a b;return c;
};6.4当箭头函数只有一行时可以省略 return 和大括号简洁书写
let sum4 (a, b) a b;7.字符串模板
ES6 引入了模板字符串也叫模板字面量它允许我们在字符串中直接嵌入变量或表达式使用反引号包裹并通过 ${} 插入变量。7.1 普通的字符串拼接
let person {name:tom,age: 22}
let {name,age} person
let str 姓名 name , 年龄 age;
console.log(str); // 姓名Tom, 年龄227.2 字符串模板
let person {name:tom,age: 22}
let {name,age} person
let str2 姓名${name}, 年龄${age};
console.log(str2); // 姓名Tom, 年龄227.3多行支持
let multilineStr 这是一行这是第二行这是第三行;
console.log(multilineStr); // 打印结果为3行 7.4字符串模板中的表达式
let num1 5;
let num2 10;
let result 结果${num1 num2};
console.log(result); // 结果157.5总结
字符串模板支持变量、表达式嵌入以及多行字符串。
使用字符串模板Template Literals比传统的字符串拼接更简洁和易于维护。
传统字符串拼接虽然仍然有效但随着代码复杂度增加使用模板字符串会使代码更具可读性和可维护性。8.Promise用法
Promise 是 JavaScript 中用于处理异步操作的一个对象代表了一个操作的最终完成或失败及其结果值。
Promise 有三种状态
pending等待状态初始状态既不是成功也不是失败。
fulfilled成功状态表示操作成功完成。
rejected失败状态表示操作失败8.18.1基础使用
let promise new Promise((resolve,reject){let dataFetched true; // 模拟数据是否获取成功if(dataFetched){resolve(数据获取成功!);}else{reject(数据获取失败!);}
})
promise.then((message)console.log(message)).catch((error){console.log(error)})8.2链式调用多个.then()
let fetchData new Promise((resolve)setTimeout(()resolve(8.2数据获取成功!),1000))
fetchData.then((message){console.log(message);return 8.2数据获取成功!;
}).then((processedData){console.log(processedData);return 8.2保存数据!;
}).then((saveData){console.log(saveData)
}).catch((error){console.log(error)
})
打印结果:
8.2数据获取成功1!
ES6.html:200 8.2数据获取成功2!
ES6.html:203 8.2保存数据3!
通过 .then() 实现多个异步操作的顺序执行。
Promise 支持链式调用即一个 .then() 返回的值会传递给下一个 .then()8.3Promise.all() Promise.all() 用于并行执行多个异步操作只有所有 Promise 都完成时它才会返回。 let fetchData1 new Promise((resolve) setTimeout(() resolve(数据1获取成功), 1000));
let fetchData2 new Promise((resolve) setTimeout(() resolve(数据2获取成功), 2000));Promise.all([fetchData1, fetchData2]).then((results) {console.log(results); // 输出[数据1获取成功, 数据2获取成功]}).catch((error) {console.error(error); // 如果其中一个失败会进入这里
});8.4Promise.race()
Promise.race() 也是用于并行执行多个异步操作但它会返回第一个完成的 Promiselet fetchData3 new Promise((resolve) setTimeout(() resolve(数据1获取成功), 1000));
let fetchData4 new Promise((resolve) setTimeout(() resolve(数据2获取成功), 500));Promise.race([fetchData3, fetchData4]).then((result) {console.log(result); // 输出数据2获取成功}).catch((error) {console.error(error);
});8.5总结
Promise 基本概念
Promise 代表异步操作的最终完成或失败及其结果值。
resolve() 用于标记成功并返回值reject() 用于标记失败并返回错误。
Promise 初始状态为 pending可以通过 resolve 转变为 fulfilled通过 reject 转变为 rejected。Promise 链式调用
通过 .then() 处理成功的结果.catch() 处理失败的错误。
Promise 支持链式调用即一个 .then() 返回的值会传递给下一个 .then()。并行操作
Promise.all() 用于并行执行多个异步操作等待所有 Promise 都完成后才会返回。
Promise.race() 用于并行执行多个异步操作只返回第一个完成的 Promise。优点
Promise 提供了比回调函数更优雅的方式来处理异步操作避免了回调地狱问题。
Promise 的链式调用使得多个异步操作可以顺序执行逻辑更清晰。
Promise 的并行控制Promise.all 和 Promise.race使得多个异步任务可以在并行时得到很好的控制。注意如果在链式调用中某一 Promise 被拒绝后续的 .then() 不会继续执行进入 .catch() 捕获错误。9.Async 和 Await
async 和 await 是 JavaScript 中用于处理异步操作的语法糖它们基于 Promise使得异步代码更具可读性和同步风格减少了回调函数和 .then() 链式调用的复杂性。9.1async 函数
async 关键字用于声明一个函数使其成为异步函数。异步函数返回一个 Promise 对象且在函数内部可以使用 await 来等待异步操作完成。let fetchData01 async () { return 数据获取成功! }
fetchData01().then((message) console.log(message))9.2 await 关键字
await 会暂停函数的执行直到 Promise 完成。
await 关键字只能在 async 函数内部使用用于等待一个 Promise 完成并返回其结果。
await 会等待 Promise 完成如果 Promise 被 resolve返回的值会赋给变量如果 Promise 被 reject会抛出异常。let fetchData02 async () {let result await new Promise((resolve) {setTimeout(() resolve(9.2获取数据成功!), 1000)})console.log(result)
}
fetchData02()9.3 async/await 错误处理
通过 try/catch 可以捕获 async 函数中 await 产生的错误与同步代码处理异常的方式相同let fetchData03 async () {try {let result await new Promise((resolve, reject) {setTimeout(() reject(9.3获取数据失败!), 1000)})console.log(result)} catch (error) {console.log(error)}
}
fetchData03()9.
在这里插入代码片9.4多个异步操作并行执行
let fetchData04 async () {let promise01 new Promise((resolve) setTimeout(() resolve(9.4获取数据成功01!)), 1000)let promise02 new Promise((resolve) setTimeout(() resolve(9.4获取数据成功02!)), 1000)let result await Promise.all([promise01, promise02])console.log(result)
}
fetchData04()9.5多个异步操作按顺序执行
let fetchData05 async () {let promise03 await new Promise((resolve) setTimeout(() resolve(9.5获取数据成功01!)), 1000)console.log(promise03)let promise04 await new Promise((resolve) setTimeout(() resolve(9.5获取数据成功02!)), 1000)console.log(promise04)
}
fetchData05()9.6避免回调地狱
回调地狱非常不推荐代码难以维护错误处理复杂。
链式的.then调用比回调地狱更清晰但当异步操作较多时.then() 链条会变得长且难以调试。
async/await最简洁和直观尤其适合多个异步操作的顺序执行。通过 try/catch 可以像同步代码一样处理错误强烈推荐使用。let loadData01 (callback) {setTimeout(() {console.log(9.6加载数据成功!)callback(null, --加载数据--)}, 1000)}
let processData01 (data, callback) {setTimeout(() {console.log(9.6处理数据成功!)callback(null, --${data} 处理数据--)}, 1000)}
let saveData01 (data, callback) {setTimeout(() {console.log(9.6保存数据成功!)callback(null, --${data} 保存数据--)}, 1000)
}// 回调地狱每个操作依赖前一个操作的完成
loadData01((err, data) {if (err) {console.error(数据加载失败:, err)return}processData01(data, (err, processedData) {if (err) {console.error(数据处理失败:, err)return}saveData01(processedData, (err, savedData) {if (err) {console.error(数据保存失败:, err)return}console.log(数据处理完成:, savedData)})})
})
//使用 Promise 避免回调地狱
let loadData02 () {return new Promise((resolve, reject) {setTimeout(() {console.log(9.6Promise加载数据成功!)resolve(--加载数据--)}, 1000)})
}let processData02 (data) {return new Promise((resolve, reject) {setTimeout(() {console.log(9.6Promise处理数据成功!)resolve( --${data} 处理数据--)}, 1000)})
}let saveData02 (data) { return new Promise((resolve, reject) {setTimeout(() {console.log(9.6Promise保存数据成功!)resolve(--${data} 保存数据--)}, 1000)})
}
//使用链式的.then调用避免回调地狱
loadData02().then(data processData02(data)).then(processedData saveData02(processedData)).then(savedData {console.log(9.6then数据处理完成:, savedData)}).catch(error {console.error(9.6then数据处理失败:, error)})
//使用 async/await避免回调地狱
let loadData03 async () {try {const data await loadData02()const processedData await processData02(data)const savedData await saveData02(processedData)console.log(9.6await数据处理完成:, savedData)} catch (error) {console.error(9.6await数据处理失败:, error)}
}
loadData03()10.模块化 ES6 Module
ES6 Module 模块功能主要由两个命令构成export 和 import。
export 命令用于规定模块的对外接口import 命令用于输入其他模块提供的功能10.1命名导出(Named Export)
可以导出多个变量或函数。导出的名称需要与导入时的名称一致。//写法一
//导出变量
export const PI 3.14;
//导出函数
export function add(a, b) {return a b;
}
export function subtract(a, b) {return a - b;
}
//导出类
export class Person {constructor(name, age) {this.name namethis.age age} sayHello() {console.log(Hello, my name is ${this.name} and Im ${this.age} years old.)}
}//写法二
//导出变量
const PI 3.14;
export {PI}
//导出函数
function add(a, b) {return a b;
}
function subtract(a, b) {return a - b;
}
export{add,subtract}10.2默认导出(Default Exports)
默认导出可以是一个函数、对象、类等。每个模块只能有一个默认导出。//greet.js
//默认导出变量
export default 10
const person {name: Amy,age: 20,
}
export default person
//默认导出函数
export default function greet(name) {return Hello, ${name}!;
}
//默认导出类
export default class Person {constructor(name, age) {this.name namethis.age age}sayHello() {console.log(Hello, my name is ${this.name} and Im ${this.age} years old.)}
}10.3命名导入(Named Import)
导入时使用 {} 来指定要导入的变量或函数名称必须与导出的名称一致。// app.js
import { add, subtract, PI } from ./math.js;console.log(add(1, 2)); // 3
console.log(subtract(5, 3)); // 2
console.log(PI); // 3.1410.4默认导入(Default Imports)
导入时不使用 {}可以给默认导入的内容起任何名称。// app.js
import greet from ./greet.js;console.log(greet(Tom)); // Hello, Tom!10.5批量导出和导入可以通过 export * from 来批量导出一个模块中的所有导出内容。
// math.js
export function add(a, b) {return a b;
}
export function subtract(a, b) {return a - b;
}
export const PI 3.14;
export * from ./math.js;// app.js
import * as math from ./index.js;console.log(math.add(1, 2)); // 3
console.log(math.subtract(5, 3)); // 2
console.log(math.PI); // 3.1410.6同时导入
// app.js
import greet, { add, subtract, PI } from ./math.js;console.log(greet(Tom)); // Hello, Tom!
console.log(add(1, 2)); // 3
console.log(subtract(5, 3)); // 2
console.log(PI); // 3.1410.7导出导入时起别名 可以在导入时给变量或函数起别名。
// app.js
import { add as addition, subtract as subtraction, PI as pi } from ./math.js;console.log(addition(2, 3)); // 5
console.log(subtraction(5, 3)); // 2
console.log(pi); // 3.1410.8export 与 import 的复合写法
如果在一个模块之中先输入后输出同一个模块import 语句可以与 export 语句写在一起。export { foo, bar } from my_module// 可以简单理解为
import { foo, bar } from my_module
export { foo, bar }10.9异步导入动态导入
// app.js
// 动态导入
import(./math.js).then(math {console.log(math.add(1, 2)); // 3console.log(math.PI); // 3.14
});10.10总结
命名导出Named Export用于导出多个功能导入时需要使用相同的名称。
默认导出Default Export每个模块只能有一个默认导出导入时可以使用任意名称。
批量导入和导出通过 export * 可以批量导出使用 import * as 来导入所有内容。
动态导入使用 import() 可以按需加载模块实现代码分割。模块化使得功能单元可以被不同的文件复用减少了冗余代码。
通过命名空间模块不同文件的函数、变量等不会发生命名冲突。
模块化可以将代码分成不同的文件每个文件负责不同的功能增强了代码的可维护性。