JavaScript 高级概念与语法特性详解
本文系统梳理了 JavaScript 的高级概念与实用语法,涵盖闭包、函数绑定、命名空间、解构赋值、可选链及柯里化等核心特性。通过具体代码示例,解析如何优雅地处理数据、避免错误及优化函数逻辑,帮助开发者提升代码质量与执行效率。
JavaScript 语言持续引入新特性,发展势头迅猛。本文整理了一系列该语言的高级概念与实用技巧,旨在帮助开发者理解更优雅的编码方式。
1. 闭包
闭包是 JavaScript 中的关键技术,内部函数能够持续访问其外部函数的变量与参数,即便外部函数已经执行完毕并返回。利用闭包,我们可以封装不希望暴露给外部作用域的数据。
//
<button onclick=”increaseCounter()”>Increase Counter</button>
//1. 全局变量,变量会被意外修改
let counter = 0;
function increaseCounter() {
counter++;
}
//2. 局部变量,每次调用都重置为0
function increaseCounter() {
let counter = 0;
counter++;
}
//3. 闭包函数,符合要求
const increaseCounter = (function() {
let counter = 0;
return function() {
counter = counter + 1;
console.log(counter);
};
})();2. 函数绑定
当上下文丢失导致 this 指向无法确定时,可以通过函数绑定机制来解决这一问题。
// 1. 与预期不符,得到undefined
let book = {
title: ‘Learn JavaScript',
printTitle() {
console.log(`Book's title: ${this.title}`);
}
}
setTimeout(book.printTitle, 1000); // Book's title: undefined
// 2. 利用函数绑定,符合预期
let book = {
title: ‘Learn JavaScript',
printTitle() {
console.log(`Book's title: ${this.title}`);
}
}
let printTitle = book.printTitle.bind(book);
setTimeout(printTitle, 1000); // Book's title: JavaScript3. 使用命名空间
引入命名空间机制可以有效防止代码之间的命名冲突。
// 1. move、jump函数在animal命名空间下,需要通过animal.move()来调用
let animal = {
move: () => {
console.log(‘Move!');
},
jump: () => {
consle.log(‘Jump!');
}
};
// 2. 真实项目中,可能会按如下方式使用命名空间
if (typeof APP === "undefined") {
APP = {};
APP.ANIMAL = {};
}
APP.ANIMAL.move = () => {
console.log(‘Move');
};
APP.ANIMAL.jump = () => {
console.log(‘Jump');
};
APP.ANIMAL.move(); // Move
APP.ANIMAL.jump(); // Jump4. 判断属性是否存在
利用 in 关键字可以检测对象中是否包含特定的属性。
const person = {
id: "123",
name: "张三"
}
console.debug("id" in person) //true
console.debug("age" in person) //false5. 解构赋值
借助解构赋值表达式,可以从对象或数组中提取属性与值,并将其赋值给其他变量,操作十分便捷。
const { address: addressLine } = { address: "长安街20号", postcode: "518118" };
console.warn(addressLine); // 长安街20号
const [first, second] = [1, 2, 3, 4]
console.warn(first, second) // 1 2
//动态解构
const extractKey = "postcode"
const { [extractKey]: youbian } = { address: "长安街20号", postcode: "518118" };
console.log(youbian) //5181186. 遍历对象属性
使用 Object.entries 方法可以方便地遍历对象的键值对。
const data = { address: "长安街20号", postcode: "518118" };
Object.entries(data).forEach(([key,value]) => {
if (["address", "postcode"].includes(key)) {
console.log('key:', key , 'value:', value)
}
})
//输出结果如下
key: address value: 长安街20号
key: postcode value: 5181187. 过滤数组
利用数组的 filter 和 some 方法可以对数组进行筛选操作。
const fruits = ["apple", null, "mongo", undefined, ""]
const filted = fruits.filter(Boolean)
console.debug(filted) //(2) ["apple", "mongo"]
const any = fruits.some(Boolean)
console.log(any) //true8. 消除重复值
const fruits = ["apple", null, "mongo", "apple", ""]
const uniqued = [...new Set(fruits)]
console.debug(uniqued) //(4) ["apple", null, "mongo", ""]9. 判断是否数组
建议使用 Array.isArray 方法来判断类型,而非使用 typeof。
const fruits = ["apple", null, "mongo", "apple", ""]
console.debug(typeof fruits) //object
console.error(Array.isArray(fruits)) //true10. 转换数字和字符串
const text = "12345"
console.debug("text:", +text, "typeof:", typeof(+text)) //text:12345 typeof:number
const num = 123456
console.debug("number:", num+"", "typeof:", typeof(num+"")) //number:123456 typeof:string11. 转换为 boolean
利用 !! 运算符可以将其他数据类型转换为 Boolean 类型。
console.log(!!null, typeof(!!null)) //false, boolean
console.log(!!"", typeof(!!"")) //false, boolean
console.log(!!undefined, typeof(!!undefined)) //false, boolean
console.log(!!null, typeof(!!null)) //false, boolean
console.log(!!true, typeof(!!true)) //true, boolean
console.log(!!false, typeof(!!false)) //false, boolean
console.log(!!{id:"", name:""}, typeof(!!{id:"", name:""})) //true, boolean12. 可选链
可选链 ?. 提供了一种安全访问嵌套对象属性的方式,可避免在对象或属性不存在时抛出异常。鉴于 JavaScript 是非类型化语言,这一特性非常实用。
//未使用可选链接,将抛出异常
const contactInfos = { address: "长安街20号" };
console.warn(contactInfos.user.phoneNumber)
// 以上语句将报错:Cannot read properties of undefined (reading 'phoneNumber')
//使用可选链接,将打印undefined
const contactInfos = { address: "长安街20号" };
console.warn(contactInfos.user?.phoneNumber) // undefined13. 合并运算符
合并运算符的语法为两个问号 ??。对于该运算符连接的两个参数,若第一个参数既非 null 也非 undefined,则返回第一个参数;否则返回第二个参数。
const contactInfos = { address: "长安街20号" };
console.warn(contactInfos.user?.phoneNumber ?? "") // ""
const contactInfos = { address: "长安街20号", addressNumber: 0 };
console.warn(contactInfos.addressNumber || undefined) // undefined
console.warn(contactInfos.addressNumber ?? undefined) // 014. 有条件地添加属性
使用 ... 扩展语法,可以在满足特定条件时,仅为对象添加指定属性。
const moreInfos = { info: "请开车前往." }
return {
address: "长安街20号",
postcode: "518118",
...(moreInfos !== undefined && { moreInfos }) //仅当moreInfos不是undefined时,才添加moreInfos属性
}15. 异步调用异常捕获
以下写法使得处理异步调用异常的代码更加简洁。
const results = await getPosts().catch((err) => {
return {
type: "error",
message: err.message
}
});
console.warn(results) // { type: "error", message: "cannot get posts from this endpoint" }16. 弱引用 Map
WeakMap 与 Map 不同,其键必须是引用对象,不能是基础类型。当没有对该键对象的引用时,该对象将从 Map 及内存中自动移除。
const videoSegments = new WeakMap()
let options = { id: "1234", timeStart: 1653831957378, size: 10000 }
const segment = { data: new Uint8Array(200) }
videoSegments.set(options, segment)
console.warn(videoSegments.get(options)) // { data: new Uint8Array(200) }
//以下当options被赋值为null后,该对象将被移除和回收
options = null
console.warn(videoSegments.has(options)) // false, the `options` key object is deleted from the WeakMap17. 反射
Reflect 是一个全局对象,它为元编程提供了一些实用的静态方法。
const person = {
name: 'Bob',
[Symbol('email')]: 'bob@evil.com'
};
Reflect.get(person, 'name'); // = Bob
Reflect.has(person, 'email'); // = true
Reflect.has(person, 'phone'); // = false
Reflect.getPrototypeOf(person); // = { constructor ... }
Reflect.getOwnPropertyDescriptor( person, 'name'); // = { value: 'Bob', writable: true, enumerable: true, configurable: true }
Reflect.ownKeys(person); // name, Symbol(email)
Reflect.defineProperty(person, 'phone', { writable: true });
Reflect.has(person, 'phone'); // = true
Reflect.set(person, 'phone', '123456789');
Reflect.deleteProperty(person, 'phone');
Reflect.has(person, 'phone'); // = false18. 柯里化
柯里化(Currying)是一种关于函数的高阶技术,指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。柯里化不会调用函数,仅对函数进行转换。
// 完成银行转账交易函数,余额+转入金额-费用
const transaction = (fee, balance, amount) => (
balance + amout - fee;
);
// 简单实现的柯里化函数
const curry = (fn, ...args) => (
(..._arg) => (
fn(...args, ..._arg)
)
);
// 复用了transaction函数的免交易费函数
const freeTransaction = curry(transaction, 0);
freeTransaction(10, 90); // = 10019. 组合
组合是一种技术,其中一个函数的结果被传递到下一个函数,依次传递直至执行最终函数并计算出结果。函数组合可以由任意数量的函数构成。
//f 和 g 都是函数,x 是在它们之间通过“管道”传输的值
var compose = function(f,g) {
return function(x) {
return f(g(x));
};
};
var toUpperCase = function(x) { return x.toUpperCase(); };
var exclaim = function(x) { return x + '!'; };
var shout = compose(exclaim, toUpperCase);
shout("send in the clowns"); //=> "SEND IN THE CLOWNS!"// 组合函数
const compose = (...fns) => x => fns.reduce((y, f) => f(y), x);
// 原函数
const addFee = amount => amount + 2;
const addDiscount = amount => amount - 5;
// 函数组合
const composition = compose(addFee, addDiscount)(100);
console.log(composition) //97到此这篇关于 JavaScript 的高级概念和用法的文章就介绍到这了,更多相关 js 高级用法内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
