常用前端手寫功能進階示例詳解
1、Promise.all
Promise.myAll = function (promises) { return new Promise((resolve, reject) => { // promises 可以不是數組,但必須要具有 Iterator 接口 if (typeof promises[Symbol.iterator] !== 'function') { reject('TypeError: promises is not iterable') } if (promises.length === 0) { resolve([]) } else { const res = [] const len = promises.length let count = 0 for (let i = 0; i < len; i++) { // Promise.resolve 的作用是將普通值或 thenable 對象轉為 promise,promise 則直接返回 Promise.resolve(promises[i]) .then((data) => { res[i] = data count += 1 if (count === len) { resolve(res) } }) .catch((err) => { reject(err) }) } } }) } // test function p1() { return new Promise((resolve, reject) => { setTimeout(resolve, 1000, 1) }) } function p2() { return new Promise((resolve, reject) => { setTimeout(resolve, 1000, 2) }) } Promise.myAll([p1(), p2()]).then(res => { console.log(res) // [1, 2] })
2、Promise.race
Promise.myRace = function (promises) { return new Promise((resolve, reject) => { // promises 可以不是數組,但必須要具有 Iterator 接口 if (typeof promises[Symbol.iterator] !== 'function') { reject('TypeError: promises is not iterable') } for (const item of promises) { // 先出來的結果會被 resolve 或 reject 出去, 一旦狀態變化就不會再變 Promise.resolve(item).then(resolve, reject) } }) } // test function p1() { return new Promise((resolve, reject) => { setTimeout(resolve, 1000, 1) }) } function p2() { return new Promise((resolve, reject) => { setTimeout(resolve, 1000, 2) }) } Promise.myRace([p1(), p2()]).then((res) => { console.log(res) // 1 })
3、Promise.any
Promise.myAny = function (promises) { return new Promise((resolve, reject) => { // promises 可以不是數組,但必須要具有 Iterator 接口 if (typeof promises[Symbol.iterator] !== 'function') { reject('TypeError: promises is not iterable') } const len = promises.length let count = 0 for (let i = 0; i < len; i++) { Promise.resolve(promises[i]).then(resolve, (err) => { count += 1 if (count === promises.length) { reject(new Error('所有 promise 都失敗')) } }) } }) } // test function p1() { return new Promise((resolve, reject) => { setTimeout(reject, 1000, 1) }) } function p2() { return new Promise((resolve, reject) => { setTimeout(resolve, 1000, 2) }) } Promise.myAny([p1(), p2()]).then((res) => { console.log(res) // 2 })
4、冒泡排序
function bubbleSort(arr) { let len = arr.length for (let i = 0; i < len - 1; i++) { // 從第一個元素開始,比較相鄰的兩個元素,前者大就交換位置 for (let j = 0; j < len - 1 - i; j++) { if (arr[j] > arr[j + 1]) { // 交換位置 [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]] } } // 每次遍歷結束,都能找到一個最大值,放在數組最後 } return arr } // test const arr = [3, 1, 2, 5, 4] console.log(bubbleSort(arr)) // [1, 2, 3, 4, 5]
5、選擇排序
function selectSort(arr) { let len = arr.length for (let i = 0; i < len - 1; i++) { // 假設每次循環,最小值就是第一個 let minIndex = i for (let j = i + 1; j < len; j++) { // 如果最小值大於其他的值,則修改索引,從而找到真正的最小值 if (arr[minIndex] > arr[j]) { minIndex = j } } // 最小值和第一個交換位置 [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]] } return arr } // test const arr = [3, 1, 2, 5, 4] console.log(bubbleSort(arr)) // [1, 2, 3, 4, 5]
6、快速排序
function quickSort(arr) { if (arr.length <= 1) return arr // 每次取第一個元素作為基準值 const pivot = arr.shift() const left = [] const right = [] for (let i = 0; i < arr.length; i++) { if (arr[i] < pivot) { // 如果小於基準值,則把它放在左數組 left.push(arr[i]) } else { // 如果大於等於基準值,則放在右數組 right.push(arr[i]) } } // 遞歸處理,並把左中右三個數組拼接起來 return quickSort(left).concat([pivot], quickSort(right)) } // test const arr = [3, 1, 2, 5, 4] console.log(quickSort(arr)) // [1, 2, 3, 4, 5]
7、call
Function.prototype.myCall = function (context = globalThis) { // 把方法添加到 context 上,這樣使用context[key]調用的時候,內部的 this 就指向瞭 context // 使用 Symbol 防止 context 原有屬性被覆蓋 const key = Symbol('key') context[key] = this const args = [...arguments].slice(1) const res = context[key](...args) delete context[key] return res } // test const myName = { name: 'Jack' } function say() { const [age, height] = arguments console.log(`My name is ${this.name}, My age is ${age}, My height is ${height}`) } say.myCall(myName, 16, 170) // My name is Jack, My age is 16, My height is 170
8、apply
Function.prototype.myApply = function (context = globalThis) { // 把方法添加到 context 上,這樣使用context[key]調用的時候,內部的 this 就指向瞭 context // 使用 Symbol 防止 context 原有屬性被覆蓋 const key = Symbol('key') context[key] = this let res if (arguments[1]) { res = context[key](...arguments[1]) } else { res = context[key]() } delete context[key] return res } // test const myName = { name: 'Jack' } function say() { const [age, height] = arguments console.log(`My name is ${this.name}, My age is ${age}, My height is ${height}`) } say.myApply(myName, [16, 170]) // My name is Jack, My age is 16, My height is 170
9、bind
Function.prototype.myBind = function (context = globalThis) { const fn = this const args = [...arguments].slice(1) const newFunc = function () { const newArgs = args.concat(...arguments) if (this instanceof newFunc) { // 通過 new 調用,this 為新創建的對象實例,將函數內部的 this 替換為這個新對象 fn.apply(this, newArgs) } else { // 普通方式調用,將函數內部的 this 替換為 context fn.apply(context, newArgs) } } // 支持 new 調用 newFunc.prototype = Object.create(fn.prototype) return newFunc } // test const myName = { name: 'Jack' } function say() { const [age, height] = arguments console.log(`My name is ${this.name}, My age is ${age}, My height is ${height}`) } const mySay = say.myBind(myName, 16, 170) mySay() // My name is Jack, My age is 16, My height is 170
10、instanceof
function myInstanceOf(obj, Fn) { // 判斷構造函數 Fn 是否出現在 obj 的原型鏈上 let proto = Object.getPrototypeOf(obj) while (proto) { if (proto === Fn.prototype) return true proto = Object.getPrototypeOf(proto) } return false }
11、new
function myNew(Fn, ...args) { const obj = new Object() obj.__proto__ = Fn.prototype // 將構造函數內部的 this 替換為新對象,並執行構造函數方法 const res = Fn.apply(obj, args) if (typeof res === 'object' && res !== null) { // 如果構造函數有返回值,且類型為 object, 則把這個值返回 return res } else { return obj } }
12、統計頁面中所有標簽的種類和個數
function getTagCount() { // 獲取頁面上所有標簽元素 const tags = document.getElementsByTagName('*') const tagNames = [] for (const val of tags) { // 把所有標簽名轉為小寫,添加到數組中 tagNames.push(val.tagName.toLocaleLowerCase()) } const res = {} for (const val of tagNames) { if (!res[val]) { res[val] = 1 } else { res[val]++ } } return res } // test console.log(getTagCount()) // { html: 1, head: 1, body: 1, div: 2, script: 1 }
以上就是今天的分享,你是不是全都掌握瞭呢,歡迎在評論區交流。如果文章對你有所幫助,不要忘瞭點上寶貴的一贊!
聽說點贊的人運氣都不差,相信下一個升職加薪的一定是你~😃
相關鏈接:10個常見的前端手寫功能,你全都會嗎?
以上就是前端手寫功能進階的詳細內容,更多關於前端手寫功能的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 字節飛書面試promise.all實現示例
- 徹底搞懂 javascript的Promise
- 淺析Promise的介紹及基本用法
- Promise靜態四兄弟實現示例詳解
- 面試手寫實現Promise.all