好記性不如爛筆頭
內(nèi)容來自 面試寶典-中級難度JavaScript面試題合集
問: 如何實現(xiàn)在 JavaScript 中的操作 settimeout/setinterval?
在 JavaScript 中,setTimeout()
和 setInterval()
是兩個非常重要的函數(shù),它們分別用于設(shè)置一次性延時執(zhí)行的函數(shù)和周期性重復(fù)執(zhí)行的函數(shù)。
-
setTimeout()
: 這個函數(shù)接受兩個參數(shù)副硅,第一個參數(shù)是需要延遲執(zhí)行的函數(shù)或代碼片段碳蛋,第二個參數(shù)是延遲的時間(單位為毫秒)肃弟。例如:
setTimeout(function(){
console.log('Hello, world!');
}, 3000); // 在3秒鐘后輸出 "Hello, world!"
-
setInterval()
: 這個函數(shù)與setTimeout()
類似,但它是用來設(shè)置一個每隔一段時間就會自動執(zhí)行一次的函數(shù)穷缤。它同樣接受兩個參數(shù)部蛇,第一個參數(shù)是要周期性執(zhí)行的函數(shù),第二個參數(shù)是時間間隔(單位為毫秒)房蝉。例如:
setInterval(function(){
console.log(new Date());
}, 1000); // 每隔一秒鐘就輸出當(dāng)前時間
注意:在使用這兩個函數(shù)時皇筛,需要注意的是想虎,由于 JavaScript 的異步特性舌厨,它們并不會阻塞程序的執(zhí)行忿薇。因此,在需要同步操作的情況下揉燃,可能需要使用其他方法來實現(xiàn)炊汤。
另外弊攘,在結(jié)束定時器的時候可以使用 clearTimeout 和 clearInterval 函數(shù)來停止定時任務(wù):
var timer = setTimeout(function(){console.log("Hello")}, 500);
clearTimeout(timer);
var intervalId = setInterval(() => {console.log('Tick') }, 1000);
clearInterval(intervalId);
以上就是在 JavaScript 中如何操作 setTimeout()
和 setInterval()
的方法襟交。
問: 如何實現(xiàn)在 JavaScript 中的操作 data structure?
在 JavaScript 中,數(shù)據(jù)結(jié)構(gòu)主要指不同數(shù)據(jù)類型之間的關(guān)系啼染。JavaScript 提供了多種內(nèi)置的數(shù)據(jù)結(jié)構(gòu)焕梅,包括基本數(shù)據(jù)類型(如字符串丘侠、數(shù)字和布爾值)逐样、復(fù)合數(shù)據(jù)類型(如數(shù)組和對象),以及其他一些高級數(shù)據(jù)結(jié)構(gòu)(如 Map挪捕、Set级零、WeakMap、WeakSet鉴嗤、Proxy 等)序调。
-
字符串 (String): 由零或多個字符組成的有限序列发绢。
let str = 'hello, world!';
-
數(shù)字 (Number): 包括整數(shù)和浮點數(shù)。
let num = 123;
-
布爾值 (Boolean): 只有兩個值:true 和 false经柴。
let bool = true;
-
對象 (Object): 是一組無序的鍵值對兒墩朦,鍵通常是字符串介杆,值則可以是任意類型。
let obj = { name: 'John Doe', age: 30, email: 'johndoe@example.com' };
-
數(shù)組 (Array): 有序的元素列表荆隘,每個元素都有唯一的索引(位置)赴背。
let arr = [1, 2, 3];
-
Map: 是鍵值對的集合凰荚,任何類型的值都可以作為鍵或值。
let map = new Map(); map.set('name', 'John'); map.set(23, 'Doe');
-
Set: 是不包含重復(fù)值的可迭代的唯一元素集缆毁。
let set = new Set([1, 2, 3, 3, 4]);
WeakMap 和 WeakSet: 都是用來儲存弱引用的對象脊框。區(qū)別在于 WeakMap 存儲鍵值對践啄,而 WeakSet 只存儲唯一值屿讽。
Proxy: 是 ES6 引入的新特性,提供了一種代理機制烂完,可以改變某些操作的默認行為,等同于在語言層面做出修改效斑,所以屬于一種“元編程”(meta programming)柱徙,即對編程語言進行編程护侮。
在使用這些數(shù)據(jù)結(jié)構(gòu)時,還需要掌握相關(guān)的操作方法滨溉,比如遍歷晦攒、查找得哆、排序贩据、刪除等。不同的數(shù)據(jù)結(jié)構(gòu)具有不同的性能特性矾芙,根據(jù)具體的應(yīng)用場景合理地選擇和使用數(shù)據(jù)結(jié)構(gòu)能夠極大地提升程序的運行效率和代碼的可讀性近上。
問: 請詳述 JavaScript 的裝飾器模式壹无?
裝飾器模式是在不改變原有對象的基礎(chǔ)上,在運行時期給對象動態(tài)地添加職責(zé)的一種設(shè)計模式。在 JavaScript 中拒迅,裝飾器模式通常通過閉包和原型鏈來實現(xiàn)。
在 JavaScript 中作箍,裝飾器模式的典型應(yīng)用就是面向切面編程(AOP)胞得。AOP 是為了實現(xiàn)橫切關(guān)注點而創(chuàng)建的一種技術(shù)屹电,它可以分離出業(yè)務(wù)邏輯中的公共部分危号,然后將其封裝成可以重用的模塊。
以下是使用裝飾器模式的一個簡單例子:
function logging(target, name, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`Calling "${name}" with`, args);
return originalMethod.apply(this, args);
};
return descriptor;
}
class Math {
@logging
add(a, b) {
return a + b;
}
}
const math = new Math();
math.add(2, 3); // 輸出: Calling "add" with [2, 3]
在這個例子中猪半,@logging
就是一個裝飾器磨确,它接收一個方法并返回一個新的方法声邦。新方法在調(diào)用原方法之前先打印一條日志消息翔忽。
要使裝飾器工作,我們需要使用 Babel 或 TypeScript 的編譯器驶悟,因為目前的 JavaScript 語法還不支持直接在類的方法上使用裝飾器痕鳍。
總的來說龙巨,裝飾器模式可以使我們的代碼更簡潔旨别,更易于維護和擴展。但是铭若,過度使用裝飾器也可能導(dǎo)致代碼變得難以理解和調(diào)試,因此在實際開發(fā)中應(yīng)適度使用裝飾器瞳腌。
問: 如何實現(xiàn)在 JavaScript 中的操作箭頭函數(shù)嫂侍?
箭頭函數(shù)是 ES6 中引入的新特性之一荚坞,它是一種簡寫形式的函數(shù)表達式西剥,可以簡化函數(shù)的定義方式。與傳統(tǒng)函數(shù)相比揪阿,箭頭函數(shù)有以下幾個特點:
- 箭頭函數(shù)不需要使用
function
關(guān)鍵字來聲明函數(shù)南捂。 - 函數(shù)體內(nèi)的
return
關(guān)鍵字可以省略旧找。 - 箭頭函數(shù)沒有自己的
this
對象钮蛛,它的this
值取決于上下文環(huán)境中的this
值。
以下是箭頭函數(shù)的一些示例:
// 定義一個簡單的箭頭函數(shù)
let sum = (x, y) => x + y;
console.log(sum(5, 10)); // 輸出: 15
// 如果只有一個參數(shù)岭辣,可以省略括號
let greet = name => `Hello, ${name}`;
console.log(greet('World')); // 輸出: Hello, World
// 如果函數(shù)體只有一行語句且沒有返回值沦童,則可以省略花括號和 return 關(guān)鍵字
let square = x => x * x;
console.log(square(5)); // 輸出: 25
箭頭函數(shù)非常適合用于回調(diào)函數(shù)和 IIFE(立即執(zhí)行函數(shù)表達式)偷遗,因為它可以幫助我們避免變量作用域和 this
的問題驼壶。例如热凹,我們可以使用箭頭函數(shù)來重新編寫下面這段代碼:
var numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(num) {
console.log(num * 2);
});
var numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => console.log(num * 2));
總的來說瞭吃,箭頭函數(shù)使得代碼更加簡潔易讀,同時也避免了一些常見的陷阱霹陡。然而止状,在某些情況下怯疤,例如需要使用 arguments
對象或者 super
關(guān)鍵字時荞彼,仍然需要使用傳統(tǒng)的函數(shù)定義方式啦粹。
問: 如何實現(xiàn)在 JavaScript 中的操作 WeakMap渠欺?
WeakMap 是 ES6 中引入的一種新型數(shù)據(jù)結(jié)構(gòu)高蜂,類似于 Map备恤,但它只能用于存儲對象作為鍵,并且不會阻止 GC 清理這些鍵喉镰。這意味著如果 WeakMap 中的所有引用都被移除梧喷,那么對應(yīng)的鍵也會被 GC 回收脖咐。
下面是 WeakMap 的基本使用方法:
-
創(chuàng)建 WeakMap:
var wm = new WeakMap();
-
向 WeakMap 添加鍵值對:
var key = {}; var value = 'some value'; wm.set(key, value);
-
從 WeakMap 獲取值:
var result = wm.get(key); console.log(result); // 輸出: some value
-
刪除鍵值對:
wm.delete(key);
-
檢查 WeakMap 是否包含某個鍵:
if(wm.has(key)) { console.log('The key exists in the WeakMap'); } else { console.log('The key does not exist in the WeakMap'); }
-
遍歷 WeakMap:
for(let [key, value] of wm) { console.log(`${key}: ${value}`); }
需要注意的是偿凭,由于 WeakMap 不會阻止 GC 回收鍵派歌,所以在訪問 WeakMap 的時候必須確保鍵還存在,否則會拋出 TypeError 錯誤匾嘱。此外霎烙,WeakMap 也不支持迭代器悬垃,因此不能使用 for...of
循環(huán)來遍歷 WeakMap。
WeakMap 主要用于防止內(nèi)存泄漏和優(yōu)化性能烘豌。當(dāng)我們將大量數(shù)據(jù)放入普通的 Map 或者 Set 時廊佩,很容易造成內(nèi)存泄漏靖榕,因為普通 Map 和 Set 會阻止 GC 回收這些數(shù)據(jù)序矩,而 WeakMap 則不會簸淀。
問: 如何實現(xiàn)在 JavaScript 中的操作新特性?
隨著 JavaScript 的不斷發(fā)展舷手,ECMAScript 標(biāo)準(zhǔn)委員會不斷地推出新的特性以增強其功能和靈活性男窟。以下是近年來一些比較重要的 JavaScript 新特性的概述:
ES6:這是 JavaScript 最大的一次升級贾富,引入了大量的新特性颤枪,包括塊級作用域、箭頭函數(shù)扇住、類艘蹋、模板字符串、解構(gòu)賦值咱娶、默認參數(shù)和 Rest 參數(shù)等。
ES7/ES2016:新增了 Array.prototype.includes的榛、Exponentiation Operator(指數(shù)運算符)等特性夫晌。
ES8/ES2017:引入了 async/await昧诱、對象屬性簡寫盏档、共享內(nèi)存和原子操作蜈亩、正則表達式的命名捕獲組等。
ES9/ES2018:引入了異步迭代器畅涂、Promise.prototype.finally午衰、Rest/Spread 屬性等冒萄。
ES10/ES2019:引入了可選鏈操作符(?.)尊流、空值合并運算符(??)奠旺、BigInt 類型、動態(tài)導(dǎo)入等鄙信。
ES11/ES2020:增加了 BigInt装诡、全局 this 和 import.meta鸦采,以及匹配空白符、Unicode 屬性轉(zhuǎn)義等顶霞。
ES12/ES2021:添加了頂級 await选浑、可選的 Chaining Call Syntax古徒、私有字段读恃、Promise.allSettled 等寺惫。
ES13/ES2022:增加了 RegExp Match Indices肌蜻、Promise.any蒋搜、正則表達式引擎的 Unicode 屬性支持等。
以上的每一個新特性都有助于提高 JavaScript 的可讀性和可維護性育谬,并使得開發(fā)者能夠更高效地編寫代碼膛檀。隨著新的標(biāo)準(zhǔn)不斷出臺咖刃,我們應(yīng)該及時了解并學(xué)習(xí)這些新特性,以便更好地利用它們進行開發(fā)花鹅。
問: 如何實現(xiàn)在 JavaScript 中的操作訪問器屬性刨肃?
訪問器屬性(accessor properties)是 ES5 引入的一項新特性真友,允許我們在對象中創(chuàng)建一對 getter 和 setter 方法盔然,從而控制屬性的讀寫操作焕参。訪問器屬性的主要優(yōu)點是可以根據(jù)需要更改對象的行為叠纷,而無需更改屬性本身涩嚣。
訪問器屬性由一對方法組成:getter 方法負責(zé)讀取值,setter 方法負責(zé)設(shè)置值掂僵。在定義訪問器屬性時航厚,我們會提供一對方法,而不是提供一個具體的值锰蓬。以下是訪問器屬性的基本用法:
var person = {};
Object.defineProperty(person, 'fullName', {
get: function() {
return this.firstName + ' ' + this.lastName;
},
set: function(value) {
var names = value.split(' ');
this.firstName = names[0];
this.lastName = names[names.length - 1];
}
});
person.fullName = 'John Doe'; // 使用 setter 方法
console.log(person.fullName); // 使用 getter 方法
在這個例子中幔睬,我們定義了一個名為 fullName
的訪問器屬性,它有一個 getter 方法和一個 setter 方法芹扭。當(dāng)我們設(shè)置 fullName
屬性時麻顶,setter 方法將新值拆分成兩部分,并將它們分別存儲到 firstName
和 lastName
屬性中辅肾。當(dāng)我們獲取 fullName
屬性時,getter 方法將 firstName
和 lastName
屬性連接起來并返回結(jié)果轮锥。
訪問器屬性可以在數(shù)據(jù)可視化矫钓、數(shù)據(jù)驗證等方面發(fā)揮重要作用。但是,由于訪問器屬性不能使用 in
運算符檢查新娜,也不能被 for-in
循環(huán)遍歷到赵辕,因此需要注意使用場合。
問: 如何實現(xiàn)在 JavaScript 中的操作 stream API杯活?
Stream API 是 ES6 中的一個重要特性匆帚,它提供了一種新的方式來處理數(shù)據(jù)流。數(shù)據(jù)流是一系列連續(xù)的旁钧、非同步的數(shù)據(jù)項吸重,可以通過管道操作進行傳輸和處理。Stream API 支持兩種類型的流:Readable 和 Writable歪今。
Readable Stream:讀取數(shù)據(jù)嚎幸,可以讀取文件、HTTP 請求等寄猩。
Writable Stream:寫入數(shù)據(jù)嫉晶,可以寫入文件、發(fā)送 HTTP 響應(yīng)等田篇。
以下是使用 Stream API 的基本步驟:
創(chuàng)建一個 Readable 流或 Writable 流替废。
設(shè)置相應(yīng)的事件監(jiān)聽器。
使用 pipe 方法將 Readable 流連接到 Writable 流泊柬。
以下是使用 Stream API 的一個例子:
// 創(chuàng)建一個 Readable 流
let readableStream = getReadableStreamSomehow();
// 設(shè)置事件監(jiān)聽器
readableStream.on('data', chunk => console.log(chunk.toString()));
// 創(chuàng)建一個 Writable 流
let writableStream = getWritableStreamSomehow();
// 將 Readable 流連接到 Writable 流
readableStream.pipe(writableStream);
在這個例子中椎镣,getReadableStreamSomehow()
和 getWritableStreamSomehow()
是用來獲取流的方法,它們的具體實現(xiàn)取決于具體的環(huán)境兽赁。
除了 Readable 和 Writable 流之外状答,還有 Duplex 和 Transform 流,它們既可以讀也可以寫刀崖。
Stream API 是一項強大的工具惊科,可以有效地處理大數(shù)據(jù)和網(wǎng)絡(luò)通信等問題。但是在使用時需要小心亮钦,因為如果不對流進行適當(dāng)?shù)墓芾砗完P(guān)閉,可能會引發(fā)內(nèi)存泄漏等問題蜂莉。
問: 請詳述 JavaScript 的數(shù)據(jù)結(jié)構(gòu)孙咪?
JavaScript 的數(shù)據(jù)結(jié)構(gòu)主要有三種類型:原始類型巡语、復(fù)合類型和特殊類型。
原始類型:指的是 JavaScript 內(nèi)置的五種基本數(shù)據(jù)類型男公,包括字符串荤堪、數(shù)字、布爾值澄阳、未定義和 null。
復(fù)合類型:主要包括對象和數(shù)組碎赢,它們都是由一組數(shù)據(jù)組成的低剔。
特殊類型:包括 Function肮塞、Date襟齿、RegExp 和 Error 對象。
下面是每種數(shù)據(jù)類型的詳細描述:
字符串(string):字符串是由雙引號或單引號包圍的一段文本枕赵,可以進行拼接猜欺、截取、替換等操作拷窜。
數(shù)字(number):可以是整數(shù)或浮點數(shù)开皿。
布爾值(boolean):有兩種值:true 和 false。
未定義(undefined):表示變量尚未賦值或者值不存在篮昧。
null:表示空對象引用赋荆。
對象(object):一組鍵值對的集合,鍵可以是字符串或者 Symbol懊昨,值可以是任何類型窄潭。
數(shù)組(array):一組有序的值的集合,每個值都有一個唯一的索引疚颊。
函數(shù)(function):一段代碼的容器狈孔,可以被調(diào)用信认。
Date 對象:表示日期和時間材义。
正則表達式(RegExp):用于文本搜索和替換的規(guī)則。
Error 對象:表示運行時出現(xiàn)的錯誤嫁赏。
熟悉 JavaScript 的各種數(shù)據(jù)結(jié)構(gòu)有助于我們更好地理解代碼其掂,并寫出更具表現(xiàn)力的代碼。此外潦蝇,JavaScript 還有一些高級數(shù)據(jù)結(jié)構(gòu)款熬,如 Map、Set攘乒、WeakMap贤牛、WeakSet、Proxy 等则酝,可以幫助我們解決特定的問題殉簸。
問: 如何實現(xiàn)在 JavaScript 中的操作迭代器?
要在JavaScript中操作迭代器,您需要創(chuàng)建一個特殊的對象般卑,該對象具有一個名為next()
的方法武鲁。每次調(diào)用此方法時,都會返回一個包含兩個屬性的對象——value
和done
蝠检。
value
屬性用于表示下一個可用的值沐鼠,而done
屬性是一個布爾類型,當(dāng)已迭代到最后一個值時為真叹谁。此外饲梭,迭代器還應(yīng)維護一個內(nèi)部指針排拷,以指示當(dāng)前集合中值的位置。
具體實現(xiàn)步驟如下:
- 創(chuàng)建一個迭代器函數(shù)监氢,并將其賦給要迭代的對象藤违。
function makeIterator(array) {
let nextIndex = 0;
return {
next: function() {
const value = array[nextIndex];
nextIndex += 1;
return { value, done: nextIndex === array.length };
}
};
}
- 使用
Symbol.iterator
屬性來定義默認的迭代器行為。
let myIterable = {
[Symbol.iterator]() {
return makeIterator(['a', 'b', 'c']);
}
};
for (let value of myIterable) {
console.log(value);
}
- 調(diào)用
next()
方法并處理結(jié)果议街。
let iterator = makeIterator(['a', 'b', 'c']);
console.log(iterator.next().value); // expected output: "a"
console.log(iterator.next().value); // expected output: "b"
console.log(iterator.next().value); // expected output: "c"
console.log(iterator.next().done); // expected output: true
請注意,您可以根據(jù)需要修改這些代碼特漩,以便在您的項目中更好地使用迭代器骨杂。