基础-函数
约 1489 字大约 5 分钟
2025-10-09
函数定义(函数声明)
传统方式
传统方式定义函数,具有函数提升特性,即可以在定义前调用
// 函数声明 function greet(name) { return `Hello, ${name}!`; } console.log(greet('Alice')); // "Hello, Alice!" // 函数提升:可以在定义前调用 sayHello(); // "Hello!" (正常工作) function sayHello() { console.log("Hello!"); }函数表达式
将函数赋值给变量,此时没有函数提升特性
// 函数表达式 let greet = function(name) { return `Hello, ${name}!`; }; console.log(greet('Bob')); // "Hello, Bob!"箭头函数
更简洁的语法,没有自己的
this、arguments、super和new.target// 基本语法 const add = (a, b) => { return a + b; }; // 单执行语句可以省略花括号 const multiply = (a, b) => a * b; // 单个参数可省略括号 const square = x => x * x; // 无参数需要空括号 const sayHi = () => console.log("Hi!"); console.log(add(2, 3)); // 5 console.log(multiply(2, 3)); // 6 console.log(square(4)); // 16立即执行函数(IIFE)
定义后立即执行的函数,用于创建独立作用域。
现代模块化中较少使用,但在旧代码中很常见
(function() { let privateVar = '我是私有的'; console.log('IIFE 立即执行'); })(); // 带参数的 IIFE (function(name) { console.log(`Hello, ${name}!`); })('World');
函数参数
arguments对象
函数的实际参数会被保存在一个类似数组的 arguments 对象中。在函数内,你可以按如下方式找出传入的参数:
arguments[i];其中
i是参数的序号,从0开始。所以第一个传入函数的参数会是arguments[0]。参数的数量由arguments.length表示。使用
arguments对象,你可以处理比声明更多的参数来调用函数。这在你事先不知道会需要将多少参数传递给函数时十分有用。你可以用arguments.length来获得实际传递给函数的参数的数量,然后用arguments对象来访问每个参数。function myConcat(separator) { let result = ""; // 初始化列表 // 迭代 arguments for (let i = 1; i < arguments.length; i++) { result += arguments[i] + separator; } return result; }console.log(myConcat("、", "红", "橙", "蓝")); // "红、橙、蓝、" console.log(myConcat(";", "大象", "长颈鹿", "狮子", "猎豹")); // "大象;长颈鹿;狮子;猎豹;" console.log(myConcat("。", "智者", "罗勒", "牛至", "胡椒", "香菜")); // "智者。罗勒。牛至。胡椒。香菜。"备注: arguments 变量只是“类数组”,而不是数组。它与数组类似,有索引编号和 length 属性。尽管如此,它并不具备 Array 对象的所有数组操作方法。
默认参数
function multiply(a, b = 1) { return a * b; }剩余参数
将多个参数收集到一个数组中
function showTags(title, ...tags) { console.log(`标题: ${title}`); console.log(`标签: ${tags.join(', ')}`); } showTags('JS教程', '编程', '前端', 'JavaScript');this关键字this是 JavaScript 中的一个特殊关键字,它在函数执行时自动定义,指向当前执行上下文的对象。- 当函数独立调用时,this指向全局对象(浏览器中为window,Node.js中为global)
function showThis() { console.log(this); } showThis(); // 浏览器中输出: Window对象- 当函数作为对象的方法调用时,
this指向调用该方法的对象
const person = { name: '张三', sayHello: function() { console.log(`你好,我是${this.name}`); } }; person.sayHello(); // 输出: "你好,我是张三"- 使用
new关键字调用构造函数时,this指向新创建的对象
function Person(name) { this.name = name; this.sayName = function() { console.log(this.name); }; } const person = new Person('赵六'); person.sayName(); // 输出: "赵六"- 箭头函数没有自己的this,它继承自外层作用域的this值
const obj = { name: '箭头函数示例', regularFunction: function() { console.log('普通函数:', this.name); }, arrowFunction: () => { console.log('箭头函数:', this.name); } }; obj.regularFunction(); // 输出: "普通函数: 箭头函数示例" obj.arrowFunction(); // 输出: "箭头函数: undefined" (取决于外层this)- 回调函数中的this:
const obj = { name: '测试对象', handleClick: function() { console.log(this.name); } }; // 事件处理中的this问题 document.getElementById('myButton').addEventListener('click', obj.handleClick); // 点击按钮时输出: "测试对象" // 但如果是这样: setTimeout(obj.handleClick, 1000); // 1秒后输出: undefined (this指向全局对象)
返回值
如果没有 return 或 return 后无值,默认返回 undefined。
作用域
在函数内定义的变量不能在函数之外的任何地方访问
定义在全局域中的函数可以访问所有全局变量
内层函数可以访问外层函数能访问的所有变量,外层函数无法访问内层函数变量
const globalVar = '全局变量';
function outer() {
const outerVar = '外部变量';
function inner() {
const innerVar = '内部变量';
console.log(innerVar); // 可以访问
console.log(outerVar); // 可以访问
console.log(globalVar); // 可以访问
}
inner();
// console.log(innerVar); // 错误:无法访问内部变量
}
outer();闭包
闭包的本质:内部函数引用外部函数的变量,外部函数返回内部函数。
闭包的作用:实现变量封装、状态持久化
function outer() {
const outerVar = '我在外部函数中';
function inner() {
console.log(outerVar); // 访问外部函数的变量
}
return inner;
}
const closureFunc = outer();
closureFunc(); // 输出: "我在外部函数中"应用示例:
const calculator = (function() {
let memory = 0;
return {
add: function(a, b) {
return a + b;
},
subtract: function(a, b) {
return a - b;
},
store: function(value) {
memory = value;
},
recall: function() {
return memory;
},
clear: function() {
memory = 0;
}
};
})();
console.log(calculator.add(5, 3)); // 8
calculator.store(100);
console.log(calculator.recall()); // 100常用函数
isNaN()isNaN()函数判断一个值是否是NaN。注意:isNaN函数内部的强制转换规则十分有趣。你也可以使用Number.isNaN()来判断该值是否为NaN。parseFloat()parseFloat()函数解析字符串参数,并返回一个浮点数。parseInt()parseInt()函数解析字符串参数,并返回指定的基数(基础数学中的数制)的整数。encodeURI()encodeURI()方法通过以表示字符的 UTF-8 编码的一个、两个、三个或四个转义序列替换统一资源标识符(URI)的某些字符来进行编码(对于由两个“代理(surrogate)”字符组成的字符,只会编码为四个转义序列)。decodeURI()decodeURI()函数对先前经过encodeURI函数或者其他类似方法编码过的统一资源标志符(URI)进行解码。
