JavaScript函數(shù)和作用域(經(jīng)典面試題)
一、閉包,使用場(chǎng)景
1.閉包的定義
閉包(Closure)是指函數(shù)與其引用環(huán)境(lexical environment)的組合。當(dāng)一個(gè)函數(shù)能夠記住并訪(fǎng)問(wèn)其定義時(shí)的作用域,即使該函數(shù)在其作用域外執(zhí)行,依然可以訪(fǎng)問(wèn)那些變量。閉包的核心特點(diǎn)是:
- 函數(shù)嵌套:閉包通常涉及嵌套函數(shù)(內(nèi)部函數(shù)引用外部函數(shù)的變量)。
- 變量持久化:外部函數(shù)的變量不會(huì)被垃圾回收,因?yàn)閮?nèi)部函數(shù)仍持有引用。
2.閉包的實(shí)現(xiàn)原理
function outer() {
let count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}
const closureFunc = outer();
closureFunc(); // 輸出 1
closureFunc(); // 輸出 2inner函數(shù)引用了outer的變量count,形成閉包。- 每次調(diào)用
closureFunc時(shí),count的值會(huì)被保留。
3.閉包的應(yīng)用場(chǎng)景
(1)數(shù)據(jù)封裝與私有變量
通過(guò)閉包模擬私有變量,避免全局污染:
function createCounter() {
let privateCount = 0;
return {
increment: function() { privateCount++; },
getValue: function() { return privateCount; }
};
}
const counter = createCounter();
counter.increment();
console.log(counter.getValue()); // 輸出 1(2)函數(shù)柯里化
將多參數(shù)函數(shù)轉(zhuǎn)換為單參數(shù)鏈?zhǔn)秸{(diào)用:
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // 輸出 10(3)事件處理與回調(diào)
在異步操作中保留上下文:
function setupClickHandler() {
let clicked = 0;
document.getElementById('btn').addEventListener('click', function() {
clicked++;
console.log(`按鈕被點(diǎn)擊 ${clicked} 次`);
});
}
setupClickHandler();(4)模塊化開(kāi)發(fā)
實(shí)現(xiàn)模塊的隔離作用域:
const module = (function() {
let privateData = '秘密';
return {
getData: function() { return privateData; }
};
})();
console.log(module.getData()); // 輸出 "秘密"4.注意事項(xiàng)
- 內(nèi)存泄漏:閉包可能導(dǎo)致變量長(zhǎng)期駐留內(nèi)存,需手動(dòng)解除引用(如
closureFunc = null)。 - 性能影響:過(guò)度使用閉包會(huì)增加內(nèi)存消耗。
二、詞法作用域和動(dòng)態(tài)作用域區(qū)別
1.詞法作用域(Lexical Scoping)
詞法作用域由代碼書(shū)寫(xiě)時(shí)的結(jié)構(gòu)決定,作用域在代碼編譯階段就已確定。變量的訪(fǎng)問(wèn)權(quán)限取決于其在代碼中的物理位置(即定義時(shí)的嵌套關(guān)系),與函數(shù)調(diào)用時(shí)的執(zhí)行上下文無(wú)關(guān)。
- 特點(diǎn):
- 作用域鏈基于函數(shù)或塊的定義位置建立,內(nèi)部函數(shù)可訪(fǎng)問(wèn)外部函數(shù)的變量,但外部函數(shù)無(wú)法訪(fǎng)問(wèn)內(nèi)部函數(shù)的變量。
- 大多數(shù)現(xiàn)代編程語(yǔ)言(如JavaScript、Python、C++)默認(rèn)采用詞法作用域。
- 示例:
function outer() {
let x = 10;
function inner() {
console.log(x); // 訪(fǎng)問(wèn)外部函數(shù)的x(詞法作用域)
}
inner();
}
outer(); // 輸出102.動(dòng)態(tài)作用域(Dynamic Scoping)
動(dòng)態(tài)作用域由函數(shù)調(diào)用時(shí)的執(zhí)行上下文決定,作用域鏈在運(yùn)行時(shí)動(dòng)態(tài)生成。變量的訪(fǎng)問(wèn)權(quán)限取決于調(diào)用鏈的順序,而非代碼的靜態(tài)結(jié)構(gòu)。
- 特點(diǎn):
- 函數(shù)內(nèi)部的變量可能因調(diào)用方式不同而引用不同的值。
- 傳統(tǒng)語(yǔ)言如Bash、Perl的局部變量支持動(dòng)態(tài)作用域,但現(xiàn)代語(yǔ)言較少使用。
- 示例:
x=1
function foo() {
echo $x # 動(dòng)態(tài)作用域下,x的值取決于調(diào)用者
}
function bar() {
local x=2
foo
}
bar # 輸出2(動(dòng)態(tài)作用域)3.核心區(qū)別
- 確定時(shí)機(jī):
- 詞法作用域在代碼編譯時(shí)靜態(tài)確定。
- 動(dòng)態(tài)作用域在函數(shù)運(yùn)行時(shí)動(dòng)態(tài)確定。
- 依賴(lài)關(guān)系:
- 詞法作用域依賴(lài)代碼的物理結(jié)構(gòu)(嵌套關(guān)系)。
- 動(dòng)態(tài)作用域依賴(lài)函數(shù)的調(diào)用棧。
- 典型語(yǔ)言:
- 詞法作用域:JavaScript、Python、C。
- 動(dòng)態(tài)作用域:Bash、Emacs Lisp(部分支持)。
- 性能影響:
- 詞法作用域允許更高效的靜態(tài)優(yōu)化。
- 動(dòng)態(tài)作用域需在運(yùn)行時(shí)解析變量,可能降低性能。
4.實(shí)際影響
- 閉包(Closure):詞法作用域是閉包的基礎(chǔ),內(nèi)部函數(shù)可“記住”定義時(shí)的環(huán)境。
- 調(diào)試難度:動(dòng)態(tài)作用域可能導(dǎo)致變量值難以預(yù)測(cè),增加調(diào)試復(fù)雜度。
三、call、apply和bind方法的區(qū)別
1.功能:
這三個(gè)方法都是 JavaScript 中函數(shù)對(duì)象的方法,用于顯式綁定函數(shù)的 this 值,并執(zhí)行函數(shù)。核心功能是動(dòng)態(tài)改變函數(shù)運(yùn)行時(shí) this 的指向。
2.call 方法
- 語(yǔ)法:
func.call(thisArg, arg1, arg2, ...) - 作用: 立即調(diào)用函數(shù),并指定函數(shù)內(nèi)部的
this值為thisArg,同時(shí)傳遞參數(shù)列表(逐個(gè)傳遞)。 - 示例:
function greet(name) {
console.log(`Hello, ${name}! I'm ${this.title}.`);
}
const context = { title: 'Mr' };
greet.call(context, 'Alice'); // 輸出: Hello, Alice! I'm Mr.3.apply 方法
- 語(yǔ)法:
func.apply(thisArg, [argsArray]) - 作用: 立即調(diào)用函數(shù),并指定
this值為thisArg,參數(shù)通過(guò)數(shù)組(或類(lèi)數(shù)組對(duì)象)傳遞。 - 與 call 的區(qū)別: 僅參數(shù)傳遞方式不同(數(shù)組 vs 逐個(gè)參數(shù))。
- 示例:
greet.apply(context, ['Alice']); // 輸出與 call 相同
4.bind 方法
- 語(yǔ)法:
func.bind(thisArg, arg1, arg2, ...) - 作用: 返回一個(gè)新函數(shù),新函數(shù)的
this永久綁定為thisArg,并可預(yù)先綁定部分參數(shù)(柯里化)。 - 特點(diǎn): 不會(huì)立即執(zhí)行函數(shù),需手動(dòng)調(diào)用返回的新函數(shù)。
- 示例:
const boundGreet = greet.bind(context, 'Alice'); boundGreet(); // 輸出: Hello, Alice! I'm Mr.
5.區(qū)別:
| 方法 | 調(diào)用時(shí)機(jī) | 參數(shù)形式 | 返回值 |
|---|---|---|---|
call | 立即執(zhí)行 | 逐個(gè)參數(shù) | 函數(shù)執(zhí)行結(jié)果 |
apply | 立即執(zhí)行 | 數(shù)組或類(lèi)數(shù)組 | 函數(shù)執(zhí)行結(jié)果 |
bind | 延遲執(zhí)行 | 逐個(gè)參數(shù) | 綁定后的函數(shù) |
6.使用場(chǎng)景
- call/apply: 需要立即調(diào)用函數(shù)并明確
this時(shí),如借用其他對(duì)象的方法(如數(shù)組方法用于類(lèi)數(shù)組對(duì)象)。 - bind: 需要固定
this或部分參數(shù)時(shí)(如事件監(jiān)聽(tīng)回調(diào)、定時(shí)器函數(shù))。
示例:借用數(shù)組方法
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.push.call(arrayLike, 'c'); // arrayLike 變?yōu)?{ 0: 'a', 1: 'b', 2: 'c', length: 3 }四、什么是高階函數(shù)
1.高階函數(shù)的定義
高階函數(shù)是指能夠接收其他函數(shù)作為參數(shù),或者將函數(shù)作為返回值的函數(shù)。這種特性使得代碼更具抽象性和靈活性,常用于函數(shù)式編程中。
2.高階函數(shù)的特點(diǎn)
(1)接收函數(shù)作為參數(shù)
高階函數(shù)可以接受一個(gè)或多個(gè)函數(shù)作為輸入?yún)?shù)。例如,map、filter 和 reduce 是常見(jiàn)的高階函數(shù),它們通過(guò)傳入的函數(shù)對(duì)數(shù)據(jù)進(jìn)行處理。
(2)返回函數(shù)作為結(jié)果
高階函數(shù)可以生成并返回一個(gè)新函數(shù)。例如,閉包或裝飾器(在 Python 中)通常會(huì)返回一個(gè)函數(shù)。
3.高階函數(shù)的常見(jiàn)用例
(1)函數(shù)組合
將多個(gè)函數(shù)組合成一個(gè)新的函數(shù),例如 compose(f, g)(x) 等價(jià)于 f(g(x))。
(2)回調(diào)函數(shù)
在異步編程中,高階函數(shù)常用于處理回調(diào)邏輯,例如 setTimeout 或事件監(jiān)聽(tīng)器。
(3)裝飾器模式
在不修改原函數(shù)代碼的情況下,通過(guò)高階函數(shù)擴(kuò)展其功能。例如 Python 的 @decorator 語(yǔ)法。
4.示例
// 接收函數(shù)作為參數(shù)
const numbers = [1, 2, 3];
const squared = numbers.map(x => x * x); // [1, 4, 9]
// 返回函數(shù)
function multiplier(factor) {
return x => x * factor;
}
const double = multiplier(2);
console.log(double(5)); // 105.優(yōu)勢(shì)
- 代碼復(fù)用性:通過(guò)抽象通用邏輯,減少重復(fù)代碼。
- 靈活性:動(dòng)態(tài)調(diào)整函數(shù)行為,適應(yīng)不同場(chǎng)景。
- 可讀性:通過(guò)函數(shù)組合,使代碼更符合聲明式編程風(fēng)格。
五、解釋箭頭函數(shù)的特性及其與普通函數(shù)的區(qū)別
1.特性
箭頭函數(shù)(Arrow Function)是ES6引入的一種簡(jiǎn)化函數(shù)定義的語(yǔ)法,具有以下核心特性:
簡(jiǎn)潔語(yǔ)法:省略function關(guān)鍵字,使用=>定義函數(shù)。單行表達(dá)式可省略{}和return。
const add = (a, b) => a + b;
無(wú)this綁定:箭頭函數(shù)不綁定自身的this,而是繼承外層作用域的this值。
const obj = {
value: 10,
getValue: () => console.log(this.value) // 輸出undefined(繼承全局作用域)
};無(wú)arguments對(duì)象:需使用剩余參數(shù)(...args)替代。
const logArgs = (...args) => console.log(args);
不可作為構(gòu)造函數(shù):無(wú)法通過(guò)new調(diào)用,且沒(méi)有prototype屬性。
const Foo = () => {};
new Foo(); // TypeError: Foo is not a constructor2.區(qū)別
(1)this綁定
普通函數(shù)的this由調(diào)用方式?jīng)Q定(動(dòng)態(tài)綁定),箭頭函數(shù)繼承定義時(shí)的this(靜態(tài)綁定)。
function regularFunc() { console.log(this); }
const arrowFunc = () => console.log(this);
const obj = { method: regularFunc, arrowMethod: arrowFunc };
obj.method(); // 輸出obj(普通函數(shù))
obj.arrowMethod(); // 輸出全局對(duì)象(箭頭函數(shù)繼承定義時(shí)的this)(2)構(gòu)造函數(shù)與prototype
普通函數(shù)可作為構(gòu)造函數(shù),箭頭函數(shù)不能。
(3)arguments對(duì)象
普通函數(shù)可通過(guò)arguments訪(fǎng)問(wèn)參數(shù),箭頭函數(shù)需使用剩余參數(shù)。
(4)語(yǔ)法靈活性
普通函數(shù)支持函數(shù)聲明和表達(dá)式,箭頭函數(shù)僅限表達(dá)式形式。
3.適用場(chǎng)景
箭頭函數(shù):適合需要綁定外層this的場(chǎng)景(如回調(diào)函數(shù)、數(shù)組方法)。
[1, 2, 3].map(item => item * 2);
普通函數(shù):需要?jiǎng)討B(tài)this、構(gòu)造函數(shù)或arguments時(shí)使用。
function Person(name) { this.name = name; }六、什么是生成器函數(shù)
1.概念
生成器函數(shù)是 JavaScript 中的一種特殊函數(shù),允許通過(guò) yield 關(guān)鍵字暫停和恢復(fù)執(zhí)行。它返回一個(gè)生成器對(duì)象(Generator),該對(duì)象遵循迭代器協(xié)議,可以逐步產(chǎn)生值,而非一次性計(jì)算所有結(jié)果。
2.基本語(yǔ)法
生成器函數(shù)通過(guò)在 function 后添加星號(hào)(*)定義:
function* generatorFunction() {
yield 'value1';
yield 'value2';
return 'finalValue'; // 可選
}調(diào)用生成器函數(shù)時(shí),不會(huì)立即執(zhí)行函數(shù)體,而是返回一個(gè)生成器對(duì)象:
const generator = generatorFunction();
3.核心特性
暫停與恢復(fù)
通過(guò) yield 暫停函數(shù)執(zhí)行,并返回當(dāng)前值。調(diào)用 next() 方法恢復(fù)執(zhí)行,直到下一個(gè) yield 或 return。
惰性求值
值按需生成,節(jié)省內(nèi)存。例如處理大型數(shù)據(jù)集時(shí),無(wú)需預(yù)先生成全部結(jié)果。
4.對(duì)象的方法
next():恢復(fù)執(zhí)行,返回{ value: yieldedValue, done: boolean }。return(value):終止生成器,返回{ value: value, done: true }。throw(error):向生成器拋入錯(cuò)誤,可在函數(shù)內(nèi)通過(guò)try-catch捕獲。
示例:生成斐波那契數(shù)列
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 15.區(qū)別
| 特性 | 生成器函數(shù) | 普通函數(shù) |
|---|---|---|
| 執(zhí)行方式 | 可暫停和恢復(fù) | 一次性執(zhí)行完畢 |
| 返回值 | 生成器對(duì)象(迭代器) | 直接返回結(jié)果 |
| 內(nèi)存占用 | 惰性計(jì)算,內(nèi)存效率高 | 可能占用更多內(nèi)存 |
6.常見(jiàn)應(yīng)用場(chǎng)景
- 異步編程:與
Promise結(jié)合簡(jiǎn)化異步流程(如redux-saga)。 - 無(wú)限序列:按需生成無(wú)限序列(如斐波那契數(shù)列)。
- 狀態(tài)管理:通過(guò)
yield暫停保存中間狀態(tài)。
七、防抖
1.概念
防抖(Debounce)是一種優(yōu)化高頻觸發(fā)事件的技術(shù),確保事件在停止觸發(fā)后的一段時(shí)間內(nèi)只執(zhí)行一次。常用于輸入框搜索、窗口大小調(diào)整等場(chǎng)景。
2.基礎(chǔ)實(shí)現(xiàn)
function debounce(func, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}- 核心邏輯:每次觸發(fā)時(shí)清除舊定時(shí)器,重新設(shè)置延遲執(zhí)行。
- 參數(shù)說(shuō)明:
func:需要防抖的目標(biāo)函數(shù)。delay:延遲時(shí)間(毫秒)。
3.立即執(zhí)行版本
若需首次觸發(fā)立即執(zhí)行,后續(xù)延遲可添加標(biāo)志位控制:
function debounce(func, delay, immediate) {
let timer;
return function(...args) {
const context = this;
if (immediate && !timer) {
func.apply(context, args);
}
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
if (!immediate) {
func.apply(context, args);
}
}, delay);
};
}immediate為true時(shí):首次觸發(fā)立即執(zhí)行,后續(xù)停止觸發(fā)delay毫秒后再恢復(fù)立即執(zhí)行能力。
4.取消功能擴(kuò)展
為防抖函數(shù)添加取消方法:
function debounce(func, delay) {
let timer;
const debounced = function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
debounced.cancel = () => {
clearTimeout(timer);
timer = null;
};
return debounced;
}調(diào)用示例:
const debouncedFn = debounce(handler, 500); debouncedFn.cancel(); // 取消延遲執(zhí)行
5.應(yīng)用場(chǎng)景
- 輸入框搜索:用戶(hù)停止輸入500毫秒后發(fā)起請(qǐng)求。
- 窗口調(diào)整:停止調(diào)整窗口后計(jì)算布局。
- 按鈕防重復(fù)點(diǎn)擊:避免用戶(hù)快速多次提交。
6.注意事項(xiàng)
- 確保
func的this指向正確,需通過(guò)apply或call綁定上下文。 - 頻繁觸發(fā)的場(chǎng)景下(如動(dòng)畫(huà)),防抖可能導(dǎo)致延遲過(guò)高,需權(quán)衡延遲時(shí)間。
八、節(jié)流
1.概念
函數(shù)節(jié)流(Throttle)是一種限制函數(shù)執(zhí)行頻率的技術(shù),確保函數(shù)在指定時(shí)間間隔內(nèi)只執(zhí)行一次。常用于高頻事件(如滾動(dòng)、輸入、窗口調(diào)整)的性能優(yōu)化。
2.時(shí)間戳版節(jié)流
通過(guò)記錄上一次執(zhí)行的時(shí)間戳,判斷當(dāng)前時(shí)間是否超過(guò)間隔:
function throttle(func, delay) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
func.apply(this, args);
lastTime = now;
}
};
}特點(diǎn):立即執(zhí)行,但最后一次觸發(fā)可能不執(zhí)行。
3.定時(shí)器版節(jié)流
通過(guò)定時(shí)器控制執(zhí)行,確保間隔結(jié)束后觸發(fā):
function throttle(func, delay) {
let timer = null;
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
}特點(diǎn):延遲執(zhí)行,確保最后一次觸發(fā)會(huì)執(zhí)行。
4.結(jié)合時(shí)間戳與定時(shí)器
綜合兩種方案,實(shí)現(xiàn)首次立即執(zhí)行、末次延遲執(zhí)行的效果:
function throttle(func, delay) {
let lastTime = 0, timer = null;
return function(...args) {
const now = Date.now();
const remaining = delay - (now - lastTime);
if (remaining <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
func.apply(this, args);
lastTime = now;
} else if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
lastTime = Date.now();
timer = null;
}, remaining);
}
};
}5.應(yīng)用示例
監(jiān)聽(tīng)滾動(dòng)事件時(shí),限制處理函數(shù)的頻率:
const handleScroll = throttle(() => {
console.log('Scroll event throttled');
}, 200);
window.addEventListener('scroll', handleScroll);6.注意事項(xiàng)
- 間隔時(shí)間:根據(jù)實(shí)際場(chǎng)景調(diào)整
delay參數(shù),避免卡頓或響應(yīng)不足。 - 上下文綁定:使用
apply確保函數(shù)內(nèi)的this指向正確。 - 取消機(jī)制:可擴(kuò)展功能,支持手動(dòng)取消未執(zhí)行的定時(shí)器。
九、遞歸函數(shù)的優(yōu)缺點(diǎn)
1.優(yōu)點(diǎn)
- 代碼簡(jiǎn)潔清晰
遞歸能將復(fù)雜問(wèn)題分解為相似的子問(wèn)題,代碼邏輯更接近數(shù)學(xué)定義或自然語(yǔ)言描述。例如階乘、斐波那契數(shù)列的實(shí)現(xiàn)只需幾行代碼。
- 減少顯式循環(huán)結(jié)構(gòu)
對(duì)于樹(shù)形結(jié)構(gòu)(如DOM遍歷、目錄掃描)或分治算法(如快速排序、歸并排序),遞歸無(wú)需手動(dòng)維護(hù)?;蜓h(huán)變量,降低實(shí)現(xiàn)復(fù)雜度。
- 天然的問(wèn)題分解能力
適合解決具有自相似性的問(wèn)題(如漢諾塔、回溯算法),子問(wèn)題的解能直接組合成原問(wèn)題的解。
2.缺點(diǎn)
- 棧溢出風(fēng)險(xiǎn)
每次遞歸調(diào)用會(huì)占用棧幀空間,深度過(guò)大時(shí)(如未優(yōu)化的斐波那契數(shù)列計(jì)算)可能導(dǎo)致棧溢出錯(cuò)誤。尾遞歸優(yōu)化可緩解此問(wèn)題,但并非所有語(yǔ)言支持。
- 性能開(kāi)銷(xiāo)較高
函數(shù)調(diào)用涉及壓棧、跳轉(zhuǎn)等操作,比循環(huán)開(kāi)銷(xiāo)更大。例如計(jì)算fib(30)可能觸發(fā)數(shù)百萬(wàn)次遞歸調(diào)用,而迭代法只需幾十次循環(huán)。
- 調(diào)試難度增加
多層遞歸時(shí),調(diào)用棧跟蹤復(fù)雜,錯(cuò)誤可能難以定位。需依賴(lài)日志或調(diào)試工具觀察中間狀態(tài)。
- 重復(fù)計(jì)算問(wèn)題
某些遞歸(如樸素斐波那契實(shí)現(xiàn))會(huì)重復(fù)計(jì)算相同子問(wèn)題,需配合備忘錄(Memoization)優(yōu)化。
# 未優(yōu)化的斐波那契遞歸
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2) # 存在大量重復(fù)計(jì)算3.使用建議
- 適用場(chǎng)景:?jiǎn)栴}可明確分解為子問(wèn)題,且子問(wèn)題與原問(wèn)題同構(gòu)(如樹(shù)的遍歷)。
- 避免場(chǎng)景:對(duì)性能敏感或遞歸深度不可控時(shí)(如處理用戶(hù)輸入的未知層級(jí)數(shù)據(jù))。
- 優(yōu)化手段:尾遞歸改寫(xiě)(如Scheme)、備忘錄模式(緩存中間結(jié)果)、改用迭代實(shí)現(xiàn)。
十、什么是純函數(shù)
1.定義
純函數(shù)是指在相同的輸入下始終返回相同的輸出,并且不會(huì)產(chǎn)生任何副作用的函數(shù)。這意味著純函數(shù)不依賴(lài)于外部狀態(tài),也不會(huì)修改外部狀態(tài)。
2.特性
- 確定性:對(duì)于相同的輸入,純函數(shù)總是返回相同的輸出。例如:
function add(a, b) {
return a + b;
}無(wú)論何時(shí)調(diào)用 add(2, 3),結(jié)果始終是 5。
- 無(wú)副作用:純函數(shù)不會(huì)修改外部變量、全局狀態(tài)或傳入的參數(shù)。例如:
let counter = 0;
function increment() {
counter++; // 副作用:修改了外部變量
}increment 不是純函數(shù),因?yàn)樗薷牧送獠孔兞?counter。
3.優(yōu)點(diǎn)
- 可預(yù)測(cè)性:由于純函數(shù)的行為完全由輸入決定,結(jié)果更容易預(yù)測(cè)和測(cè)試。
- 可緩存性:相同的輸入總是對(duì)應(yīng)相同的輸出,因此可以緩存結(jié)果以提高性能。
- 易于并行化:純函數(shù)不依賴(lài)外部狀態(tài),可以在多線(xiàn)程環(huán)境下安全運(yùn)行。
4示例
// 純函數(shù)
function square(x) {
return x * x;
}
// 非純函數(shù)
function getRandomNumber() {
return Math.random(); // 輸出不確定
}5.如何編寫(xiě)
避免修改外部狀態(tài)或傳入的參數(shù):
// 不純的函數(shù)
function updateUser(user) {
user.age = 30; // 直接修改了參數(shù)
return user;
}
// 純函數(shù)
function updateUserPure(user) {
return { ...user, age: 30 }; // 返回新對(duì)象,不修改原參數(shù)
}避免依賴(lài)外部變量:
// 不純的函數(shù)
let taxRate = 0.1;
function calculateTax(amount) {
return amount * taxRate; // 依賴(lài)外部變量
}
// 純函數(shù)
function calculateTaxPure(amount, rate) {
return amount * rate; // 所有依賴(lài)都通過(guò)參數(shù)傳入
}十一、解釋函數(shù)重載在JavaScript中的實(shí)現(xiàn)方式
1.概念
函數(shù)重載允許同一函數(shù)名根據(jù)參數(shù)類(lèi)型或數(shù)量不同執(zhí)行不同操作。JavaScript本身不支持傳統(tǒng)意義上的函數(shù)重載(如Java或C++),但可以通過(guò)特定技巧模擬實(shí)現(xiàn)。
2.基于參數(shù)數(shù)量的重載
通過(guò)檢查arguments對(duì)象或剩余參數(shù)(rest parameters)判斷傳入?yún)?shù)數(shù)量,執(zhí)行不同邏輯:
function example() {
if (arguments.length === 1) {
console.log("處理單參數(shù)邏輯");
} else if (arguments.length === 2) {
console.log("處理雙參數(shù)邏輯");
}
}
example("A"); // 輸出: 處理單參數(shù)邏輯
example("A", "B"); // 輸出: 處理雙參數(shù)邏輯3.基于參數(shù)類(lèi)型的重載
使用typeof或instanceof檢查參數(shù)類(lèi)型,動(dòng)態(tài)調(diào)整行為:
function process(input) {
if (typeof input === "string") {
console.log("處理字符串邏輯");
} else if (typeof input === "number") {
console.log("處理數(shù)字邏輯");
}
}
process("text"); // 輸出: 處理字符串邏輯
process(42); // 輸出: 處理數(shù)字邏輯4.使用對(duì)象參數(shù)模擬重載
通過(guò)傳遞配置對(duì)象統(tǒng)一參數(shù),避免參數(shù)順序問(wèn)題:
function configure(options) {
if (options.mode === "fast") {
console.log("啟用快速模式");
} else if (options.mode === "safe") {
console.log("啟用安全模式");
}
}
configure({ mode: "fast" }); // 輸出: 啟用快速模式5.結(jié)合默認(rèn)參數(shù)與條件判斷
利用ES6默認(rèn)參數(shù)簡(jiǎn)化邏輯分支:
function load(data, format = "json") {
if (format === "json") {
console.log("解析JSON數(shù)據(jù)");
} else if (format === "xml") {
console.log("解析XML數(shù)據(jù)");
}
}
load({}); // 輸出: 解析JSON數(shù)據(jù)
load({}, "xml"); // 輸出: 解析XML數(shù)據(jù)6.注意事項(xiàng)
- JavaScript函數(shù)重載本質(zhì)是手動(dòng)模擬,需顯式編寫(xiě)參數(shù)檢查邏輯。
- 過(guò)度使用可能導(dǎo)致代碼可讀性下降,建議優(yōu)先考慮清晰命名的獨(dú)立函數(shù)。
- TypeScript提供更規(guī)范的重載語(yǔ)法支持,適合大型項(xiàng)目。
十二、什么是偏函數(shù)
1.概念
偏函數(shù)(Partial Function)是一種在函數(shù)式編程中常見(jiàn)的概念,指的是通過(guò)固定一個(gè)函數(shù)的部分參數(shù),生成一個(gè)新的函數(shù)。這種技術(shù)允許開(kāi)發(fā)者復(fù)用已有函數(shù),同時(shí)減少重復(fù)代碼。
2.作用
偏函數(shù)的主要作用是將一個(gè)多參數(shù)函數(shù)轉(zhuǎn)換為一個(gè)參數(shù)較少的函數(shù)。通過(guò)預(yù)先綁定某些參數(shù),可以在后續(xù)調(diào)用時(shí)簡(jiǎn)化操作。例如,一個(gè)計(jì)算乘方的函數(shù)可以通過(guò)偏函數(shù)固定底數(shù),生成一個(gè)專(zhuān)門(mén)計(jì)算平方或立方的函數(shù)。
3.實(shí)現(xiàn)方式
在Python中,可以使用functools.partial來(lái)實(shí)現(xiàn)偏函數(shù)。以下是一個(gè)示例:
from functools import partial
def power(base, exponent):
return base ** exponent
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5)) # 輸出25
print(cube(3)) # 輸出274.優(yōu)點(diǎn)
- 代碼復(fù)用:通過(guò)固定部分參數(shù),避免重復(fù)編寫(xiě)相似的函數(shù)。
- 靈活性:可以在運(yùn)行時(shí)動(dòng)態(tài)生成新的函數(shù),適應(yīng)不同的需求。
- 可讀性:通過(guò)賦予偏函數(shù)有意義的名稱(chēng),提升代碼的可讀性。
5.應(yīng)用場(chǎng)景
- 回調(diào)函數(shù):在事件處理中,可以通過(guò)偏函數(shù)預(yù)先綁定部分參數(shù),簡(jiǎn)化回調(diào)函數(shù)的定義。
- 配置函數(shù):在需要多次調(diào)用同一函數(shù)但部分參數(shù)固定的場(chǎng)景中,使用偏函數(shù)可以減少冗余代碼。
- 數(shù)學(xué)運(yùn)算:如上述示例所示,通過(guò)偏函數(shù)可以快速生成特定運(yùn)算的函數(shù)。
6.注意事項(xiàng)
- 參數(shù)順序:偏函數(shù)綁定的參數(shù)順序需與原函數(shù)一致,否則可能導(dǎo)致錯(cuò)誤。
- 不可變參數(shù):偏函數(shù)生成的新函數(shù)不能修改已綁定的參數(shù)值。
- 性能開(kāi)銷(xiāo):盡管偏函數(shù)的性能開(kāi)銷(xiāo)通常較小,但在高性能場(chǎng)景中仍需謹(jǐn)慎使用。
到此這篇關(guān)于JavaScript函數(shù)和作用域(經(jīng)典面試題)的文章就介紹到這了,更多相關(guān)js函數(shù)和作用域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript暫時(shí)性死區(qū)以及函數(shù)作用域
- JavaScript中塊級(jí)作用域與函數(shù)作用域深入剖析
- JavaScript改變函數(shù)作用域的方法示例
- Js逆向教程作用域和自執(zhí)行函數(shù)介紹
- 一篇文章告訴你JavaScript的作用域和函數(shù)該這樣理解
- 深入理解JavaScript 中的匿名函數(shù)((function() {})();)與變量的作用域
- 通過(guò)函數(shù)作用域和塊級(jí)作用域看javascript的作用域鏈
- 深入理解js函數(shù)的作用域與this指向
- javascript的函數(shù)作用域
相關(guān)文章
基于JavaScript實(shí)現(xiàn)焦點(diǎn)圖輪播效果
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實(shí)現(xiàn)焦點(diǎn)圖輪播效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
基于JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件觸發(fā)器
這篇文章主要為大家詳細(xì)介紹了如何使用JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件觸發(fā)器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
JavaScript String 對(duì)象常用方法總結(jié)
下面小編就為大家?guī)?lái)一篇JavaScript String 對(duì)象常用方法總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考2016-04-04
Js實(shí)現(xiàn)中國(guó)公民身份證號(hào)碼有效性驗(yàn)證實(shí)例代碼
這篇文章主要介紹了Js實(shí)現(xiàn)中國(guó)公民身份證號(hào)碼有效性驗(yàn)證實(shí)例代碼,可以識(shí)別身份證號(hào)碼的正確性,有興趣的可以了解一下2017-05-05
深入理解JavaScript繼承的多種方式和優(yōu)缺點(diǎn)
這篇文章主要介紹了深入理解JavaScript繼承的多種方式和優(yōu)缺點(diǎn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05

