JavaScript中的函数不仅仅是用来封装代码的,它们在语言中有着特殊的地位。理解函数的工作原理,是学好JavaScript的关键。
JavaScript提供了几种不同的函数定义方法:
第一种是函数声明:
function sayHello(name) {
return `你好,${name}`;
}
这种方式的特点是存在提升效果,你可以在函数声明之前调用它。
第二种是函数表达式:
const sayHello = function(name) {
return `你好,${name}`;
};
这种方式不会提升,必须在赋值之后才能使用。
第三种是箭头函数:
const sayHello = (name) => `你好,${name}`;
箭头函数写法简洁,没有自己的this值,也不能用作构造函数。
在实际开发中,函数声明适合用在模块的顶层,函数表达式和箭头函数适合在需要的时候直接使用。
JavaScript函数对参数个数要求很宽松,传入的参数可以和定义的参数个数不同。
function showInfo(name, age) {
console.log(`${name},${age}岁`);
}
showInfo("张三"); // "张三,undefined岁"
showInfo("李四", 25, "额外参数"); // "李四,25岁"
如果参数不够,缺少的参数就是undefined。如果参数多了,多出来的会被忽略。
要处理不确定数量的参数,有两种方法:
传统的方式是使用arguments:
function addNumbers() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
现在更推荐使用rest参数:
function addNumbers(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
rest参数会得到一个真正的数组,而且必须放在参数列表的最后。
作用域决定了变量在哪里可以被访问。
全局变量在任何地方都可以访问,局部变量只能在函数内部访问:
let globalVar = "全局变量";
function testScope() {
let localVar = "局部变量";
console.log(globalVar); // 可以访问
console.log(localVar); // 可以访问
}
testScope();
// console.log(localVar); // 这里会报错
关于块级作用域,var和let的表现不同:
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1,var声明的变量会提升
// console.log(b); // 报错,let声明的变量只在块内有效
现在建议使用let和const来代替var,这样可以避免很多意想不到的问题。
闭包是指函数能够记住并访问它定义时的作用域,即使函数在其他地方执行。
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
count变量被内部函数引用,所以不会被清除,形成了私有状态。
闭包在实际开发中很有用,比如用来封装数据:
function createBankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit(amount) {
balance += amount;
},
withdraw(amount) {
if (amount <= balance) balance -= amount;
},
getBalance() {
return balance;
}
};
}
const account = createBankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
外部代码无法直接修改balance,保证了数据安全。
this的值取决于函数如何被调用,而不是在哪里定义。
const obj = {
name: "示例对象",
normalMethod() {
console.log(this.name);
},
arrowMethod: () => {
console.log(this.name);
}
};
obj.normalMethod(); // "示例对象"
obj.arrowMethod(); // undefined
普通函数的this指向调用它的对象,箭头函数的this继承自外层作用域。因此,对象的方法应该使用普通函数。
立即执行函数可以创建独立的作用域,避免污染全局环境。
(function() {
const privateVar = "私有变量";
console.log("立即执行");
})();
(() => {
console.log("箭头函数立即执行");
})();
在模块化规范普及之前,这是组织代码的常用方法。
函数可以作为参数传递,也可以作为返回值,这是函数作为"一等公民"的特性。
function processArray(arr, processor) {
const result = [];
for (const item of arr) {
result.push(processor(item));
}
return result;
}
const numbers = [1, 2, 3];
const doubled = processArray(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6]
数组的map、filter、reduce等方法都是基于这个原理。
结合闭包和高阶函数,我们可以实现一个简单的事件系统:
function createEventSystem() {
const eventListeners = {};
return {
on(eventName, callback) {
if (!eventListeners[eventName]) {
eventListeners[eventName] = [];
}
eventListeners[eventName].push(callback);
},
emit(eventName, data) {
if (eventListeners[eventName]) {
eventListeners[eventName].forEach(callback => callback(data));
}
},
off(eventName, callback) {
if (eventListeners[eventName]) {
eventListeners[eventName] = eventListeners[eventName]
.filter(cb => cb !== callback);
}
}
};
}
const eventBus = createEventSystem();
eventBus.on("message", data => console.log("收到:", data));
eventBus.emit("message", "你好世界");
循环中的闭包是个常见陷阱:
错误写法:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 3, 3, 3
}
正确写法:
// 使用let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}
// 或者使用立即执行函数
for (var i = 0; i < 3; i++) {
((j) => setTimeout(() => console.log(j), 100))(i);
}
优先使用const,避免意外修改变量
简单的函数逻辑可以使用箭头函数
对象的方法使用普通函数来确保this正确
合理使用闭包,注意避免内存泄漏
一个函数只做一件事,保持函数简洁
给函数起有意义的名称
控制函数的参数数量,太多参数可以考虑使用对象
概念 | 重点内容 |
---|---|
函数定义 | 声明会提升,表达式不会,箭头函数没有this |
参数处理 | 参数个数灵活,推荐使用rest参数 |
作用域 | let/const有块级作用域,var没有 |
闭包 | 函数可以记住定义时的作用域 |
this指向 | 普通函数动态绑定,箭头函数静态继承 |
高阶函数 | 函数可以作为参数或返回值 |
理解这些核心概念,能够帮助你写出更好的JavaScript代码。函数是JavaScript中最重要的一部分,花时间深入学习是值得的。在实际项目中多练习这些知识点,你会逐渐掌握它们的精髓。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
我理解的 JavaScript 函数式编程,都认为属于函数式编程的范畴,只要他们是以函数作为主要载体的。
给你的代码增加一点点函数式编程的特性,最近我对函数式编程非常感兴趣。这个概念让我着迷:应用数学来增强抽象性和强制纯粹性,以避免副作用,并实现代码的良好可复用性。同时,函数式编程非常复杂。
Async/await以及它底层promises的应用正在猛烈地冲击着JS的世界。在大多数客户端和JS服务端平台的支持下,回调编程已经成为过去的事情。当然,基于回调的编程很丑陋的。
如果你曾经了解或编写过JavaScript,你可能已经注意到定义函数的方法有两种。即便是对编程语言有更多经验的人也很难理解这些差异。在这篇博客的第一部分,我们将深入探讨函数声明和函数表达式之间的差异。
随着软件应用的复杂度不断上升,为了确保应用稳定且易拓展,代码质量就变的越来越重要。不幸的是,包括我在内的几乎每个开发者在职业生涯中都会面对质量很差的代码。这些代码通常有以下特征:
在js开发中,程序代码是从上而下一条线执行的,但有时候我们需要等待一个操作结束后,再进行下一步操作,这个时候就需要用到回调函数。 在js中,函数也是对象,确切地说:函数是用Function()构造函数创建的Function对象。
这篇文章主要介绍ES5中函数的4种调用,在ES5中函数内容的this指向和调用方法有关。以及ES6中函数的调用,使用箭头函数,其中箭头函数的this是和定义时有关和调用无关。
函数的三种定义方法分别是:函数定义语句、函数直接量表达式和Function()构造函数的方法,下面依次介绍这几种方法具体怎么实现,在实际编程中,Function()构造函数很少用到,前两中定义方法使用比较普遍。
微软 称excel就实现面向开发者的功能,也就是说我们不仅可以全新定义的公式,还可以重新定义excel的内置函数,现在Excel自定义函数增加了使用 JavaScript 编写的支持,下面就简单介绍下如何使用js来编写excel自定义函数。
这篇文章主要讲解:js立即执行函数是什么?js使用立即执行函数有什么作用呢?js立即执行函数的写法有哪些?
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!