小壮壮妈妈 發表於 2025-6-13 09:18:00

Web前端入门第 65 问:JavaScript 函数参数各种使用方式

<p><strong>函数参数是什么?</strong></p>
<p>就是函数内部无法确定的一个东西,需要外部传给函数内部的玩意儿,语法上就是写在函数括号中的东东。比如:</p>
<pre><code class="language-js">function test(a) {}
</code></pre>
<p>其中的 <code>a</code> 就是 test 函数的参数,在函数体内部,a 作为一个变量存在,可以修改它。</p>
<p>JS 的函数参数,真的是可以传入任意值,没有任何限制,可以包括 <code>原始类型</code>、<code>对象</code>,<code>数组</code>,<code>函数</code> 等等,只要是 JS 语言支持的,都可以当做参数传入。</p>
<h3 id="原始类型">原始类型</h3>
<p>JS 原始类型参数(<code>number</code>、<code>string</code>、<code>boolean</code>、<code>null</code>、<code>undefined</code>、<code>symbol</code>、<code>bigint</code>)<strong>按值传递</strong>,传入的是值的副本,在函数里面修改传入的值不会影响外部变量。</p>
<pre><code class="language-js">function test(a) {
a = '前端路引'; // 修改原始类型不会影响 arg 变量值
}
let arg= '微信公众号';
test(arg);
console.log(arg); // 输出 '微信公众号'(原值未改变)
</code></pre>
<h3 id="引用类型">引用类型</h3>
<p>JS 引用类型参数(<code>对象</code>、<code>数组</code>、<code>函数</code>)<strong>按引用地址传递</strong>,如果函数里面修改了对象属性,会影响外部变量,使用时需特别注意!!</p>
<pre><code class="language-js">function test (obj) {
obj.name = '前端路引' // 修改了对象属性,会影响共享的对象
obj = { // 如果直接给 obj 参数赋值,不会影响共享的对象,因为 obj 已经变成了一个新的对象
    test: '测试参数'
}
}
const weChat = {
type: '微信公众号',
age: 1,
};
test(weChat);
console.log(weChat) // {type: '微信公众号', age: 1, name: '前端路引'}
</code></pre>
<h3 id="默认参数">默认参数</h3>
<p>ES6 版本为 JS 注入了一大堆活性,各种花活不断,默认参数就是其中一个最常用的花活。当未传入参数或者传入的参数是 <code>undefined</code>,则使用默认参数。</p>
<pre><code class="language-js">function test(a = '前端路引') {
return a; // 将 a 变量值返回出去
}

let arg= '微信公众号';
console.log(test(arg)); // 输出 '微信公众号'

// 没传入参数,使用默认值
console.log(test()); // 输出 '前端路引'

// 传入 undefined 也是用默认值
console.log(test(undefined)); // 输出 '前端路引'
</code></pre>
<h3 id="剩余参数">剩余参数</h3>
<p>ES6 的又一花活之一,允许使用 <code>...</code> 语法,将多余的参数合并为数组,在箭头函数中可以代替 <code>arguments</code> 对象。</p>
<pre><code class="language-js">function sum(...numbers) {
return numbers.reduce((acc, num) =&gt; acc + num, 0);
}
sum(1, 2, 3); // 返回 6

function test(a, ...rest) {
console.log(a); // 获得传入的第一个参数,输出 '公众号'
console.log(rest); // 多余参数转为数组,输出 ['前端路引', '函数测试']
}
test('公众号', '前端路引', '函数测试');
</code></pre>
<p>需特别注意,剩余参数只能放在最后,否则报语法错误 <code>SyntaxError: Rest parameter must be last formal parameter</code>。</p>
<p>比如:</p>
<pre><code class="language-js">function test(...rest, a) { // 报错SyntaxError: Rest parameter must be last formal parameter
}
</code></pre>
<h3 id="解构赋值传参">解构赋值传参</h3>
<p>还是 ES6 的花活之一,用于解构对象或数组参数。</p>
<pre><code class="language-js">/**
* 对象解构
* name 为解构参数对象中的 name 属性
* rest 为解构参数对象中剩余的属性,也是对象
*/
function test1({ name, ...rest }) {
console.log(name); // 输出 '前端路引'
// rest 获得剩余为分配的对象属性
console.log(rest); // 输出 {age: 1}
}
test1({ name: '前端路引', age: 1 });

/**
* 数组解构
* first 为第一个数组值
* rest 为数组剩余值,也是一个数组
*/
function test2() {
console.log(first); // 输出 '前端路引'
console.log(rest); // 输出
}
test2(['前端路引', 1, '微信公众号']);
</code></pre>
<p>参数使用使用解构赋值时,需特别注意,如果参数没传入参数,那么解构将会报错:</p>
<pre><code class="language-js">// 报错 TypeError: Cannot destructure property 'name' of 'undefined' as it is undefined.
function test({ name }) {
}
test();
</code></pre>
<p>原因是未传入参数时,默认便是 <code>undefined</code>,对 <code>undefined</code> 解构便会报错!!这时候可以使用函数默认参数进行解决:</p>
<pre><code class="language-js">// 表示未传入参数时使用空对象进行解构
function test({ name } = {}) {}
test();
</code></pre>
<p>解构中也可以使用默认值:</p>
<pre><code class="language-js">// 对象解构默认值
function test1({ name = '前端路引' } = {}) {
console.log(name);
}
test1(); // 输出 '前端路引'
test1({age: 1}); // 输出 '前端路引'

// 需注意另一种写法
function test2({ name } = { name: '前端路引' }) {
console.log(name);
}
test2(); // 输出 '前端路引'
test2({age: 1}); // 输出 undefined

// 数组解构默认值
function test3( = []) {
console.log(first);
}
test3();
</code></pre>
<p>test2 中使用了一个默认对象,这个对象中有 name 属性,如果传入参数不存在时候,将会获得 name 属性值,但如果传入参数存在时,并且传入的对象中没有 name 属性,那么就只能是 undefined。</p>
<h3 id="arguments-对象">arguments 对象</h3>
<p>使用 function 声明的函数,可以使用 <code>arguments</code> 所有参数。需注意 <code>arguments</code> 在箭头函数中<strong>不可用</strong>。</p>
<p>arguments 是<strong>类数组对象</strong>,不是所有数组方法都可以使用,可以使用 <code>...</code> 展开运算符转换为数组。</p>
<pre><code class="language-js">function test() {
// arguments.push('微信公众号'); // 报错 TypeError: arguments.push is not a function
const temp = [...arguments]; // 使用展开运算符转换为数组
temp.push('微信公众号'); // 转为数组之后可以使用 push 方法
console.log(temp);
}
test(1, '前端路引', true); // 输出
</code></pre>
<h3 id="函数作为参数">函数作为参数</h3>
<p>虽然 <code>回调函数</code> 参数这种方式已经被 <code>Promise</code> 代替,但如果要实现各种钩子函数,还是只能使用 function 作为参数传递。</p>
<p>使用函数作为参数的函数有一个专用名词叫做 <code>高阶函数</code>。多用于 事件处理、异步操作 等等。</p>
<pre><code class="language-js">function test1(url, callback) {
// 模拟异步操作
setTimeout(() =&gt; {
    callback({ data: '前端路引' });
}, 1000);
}
test1('/api', (response) =&gt; {
console.log(response.data); // 输出 '前端路引'
});

// 使用 Promise 改写 test1 函数:
function test2(url) {
return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      resolve({ data: '前端路引' });
    }, 1000)
})
}
test2('/api').then((response) =&gt; {
console.log(response.data); // 输出 '前端路引'
})
</code></pre>
<p>当需要钩子函数时候,便无法使用 Promise 替换了,比如:</p>
<pre><code class="language-js">function test({
url,
before, // 钩子函数,在请求开始时调用
callback,
} = {}) {
before &amp;&amp; before('请求开始');
setTimeout(() =&gt; {
    // 执行完之后回调
    callback &amp;&amp; callback({ data: '前端路引' });
}, 1000)
}
test({
url: '/api',
before(msg) {
    console.log(msg);
},
callback(response) {
    console.log(response.data);
}
})
</code></pre>
<h3 id="函数柯里化">函数柯里化</h3>
<p>通过闭包返回函数,分步传递参数,这种方式称为 <code>函数柯里化</code>。</p>
<pre><code class="language-js">function test(a) {
return (b) =&gt; a * b; // 函数返回值是一个函数,用于二次调用
}
const double = test(2); // 第一次传入参数,获得一个返回函数
console.log(double(5)); // 第二次传入参数,获得结果,输出 10
</code></pre>
<p>由于闭包中的变量一直在内存中,所以在使用时候需注意<strong>内存泄漏</strong>问题!!</p>
<h3 id="bind-方法绑定参数">bind 方法绑定参数</h3>
<p><code>bind</code> 这方法不仅可以绑定内部 this 指针,还能用于固定部分参数,生成新函数。</p>
<pre><code class="language-js">function test1(type, name) {
console.log(this);
return `${type}:${name}`;
}
const test2 = test1.bind({age: 1}, '微信公众号');
console.log(test2('前端路引')); // 输出 '微信公众号:前端路引'
</code></pre>
<p><code>test1.bind({age: 1}, '微信公众号')</code> 作用是给 test1 绑定 this 指向 <code>{age: 1}</code> 对象,同时固定了第一个参数为 <code>'微信公众号'</code>,返回一个新的函数,此函数只有剩下的 <code>name</code> 参数。</p>
<p>也可以使用 <code>test1.bind(null, '微信公众号')</code> 不绑定 this 指针,仅固定第一个参数。</p>
<h3 id="隐式参数类型转换">隐式参数类型转换</h3>
<p>由于 JS 的参数灵活性,在使用时,需特别注意类型转换问题。比如字符串 <code>'5'</code> 转为数字 <code>5</code>:</p>
<pre><code class="language-js">function test(a, b) {
return a + b;
}
test('3', 5); // 返回 '35'(字符串拼接)
test(3, '5'); // 返回 '35'
test(3, 5); // 返回 8
</code></pre>
<p>如果无法确定传入的参数类型,那么就有必要显式转换类型(如 <code>Number(param)</code>):</p>
<pre><code class="language-js">function test(a, b) {
return Number(a) + Number(b);
}
test('3', 5); // 返回 8
test(3, '5'); // 返回 8
test(3, 5); // 返回 8
</code></pre>
<p>或进行参数类型校验,当输入不合法时候,抛出异常:</p>
<pre><code class="language-js">function test(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
    throw new Error('参数类型错误');
}
return a + b;
}
test('3', 5); // 抛出异常
</code></pre>
<h2 id="写在最后">写在最后</h2>
<p>理解各种函数传参方式,灵活运用可以在编程中玩出花来。各种优雅的设计模式、易于维护的高级代码,都离不开函数的使用技巧~~</p>
<p>在使用函数参数时,也需特别注意参数合法性校验,尤其是提供给外部调用的函数,必须做参数类型校验,避免程序出现参数类型错误。</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/18926463</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/18926463
頁: [1]
查看完整版本: Web前端入门第 65 问:JavaScript 函数参数各种使用方式