常用前端手寫功能進(jìn)階示例詳解
1、Promise.all
Promise.myAll = function (promises) {
return new Promise((resolve, reject) => {
// promises 可以不是數(shù)組,但必須要具有 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 對(duì)象轉(zhuǎn)為 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 可以不是數(shù)組,但必須要具有 Iterator 接口
if (typeof promises[Symbol.iterator] !== 'function') {
reject('TypeError: promises is not iterable')
}
for (const item of promises) {
// 先出來的結(jié)果會(huì)被 resolve 或 reject 出去, 一旦狀態(tài)變化就不會(huì)再變
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 可以不是數(shù)組,但必須要具有 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++) {
// 從第一個(gè)元素開始,比較相鄰的兩個(gè)元素,前者大就交換位置
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]]
}
}
// 每次遍歷結(jié)束,都能找到一個(gè)最大值,放在數(shù)組最后
}
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++) {
// 假設(shè)每次循環(huán),最小值就是第一個(gè)
let minIndex = i
for (let j = i + 1; j < len; j++) {
// 如果最小值大于其他的值,則修改索引,從而找到真正的最小值
if (arr[minIndex] > arr[j]) {
minIndex = j
}
}
// 最小值和第一個(gè)交換位置
[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
// 每次取第一個(gè)元素作為基準(zhǔn)值
const pivot = arr.shift()
const left = []
const right = []
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
// 如果小于基準(zhǔn)值,則把它放在左數(shù)組
left.push(arr[i])
} else {
// 如果大于等于基準(zhǔn)值,則放在右數(shù)組
right.push(arr[i])
}
}
// 遞歸處理,并把左中右三個(gè)數(shù)組拼接起來
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]調(diào)用的時(shí)候,內(nèi)部的 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]調(diào)用的時(shí)候,內(nèi)部的 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 調(diào)用,this 為新創(chuàng)建的對(duì)象實(shí)例,將函數(shù)內(nèi)部的 this 替換為這個(gè)新對(duì)象
fn.apply(this, newArgs)
} else {
// 普通方式調(diào)用,將函數(shù)內(nèi)部的 this 替換為 context
fn.apply(context, newArgs)
}
}
// 支持 new 調(diào)用
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) {
// 判斷構(gòu)造函數(shù) Fn 是否出現(xiàn)在 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
// 將構(gòu)造函數(shù)內(nèi)部的 this 替換為新對(duì)象,并執(zhí)行構(gòu)造函數(shù)方法
const res = Fn.apply(obj, args)
if (typeof res === 'object' && res !== null) {
// 如果構(gòu)造函數(shù)有返回值,且類型為 object, 則把這個(gè)值返回
return res
} else {
return obj
}
}
12、統(tǒng)計(jì)頁面中所有標(biāo)簽的種類和個(gè)數(shù)
function getTagCount() {
// 獲取頁面上所有標(biāo)簽元素
const tags = document.getElementsByTagName('*')
const tagNames = []
for (const val of tags) {
// 把所有標(biāo)簽名轉(zhuǎn)為小寫,添加到數(shù)組中
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 }
以上就是今天的分享,你是不是全都掌握了呢,歡迎在評(píng)論區(qū)交流。如果文章對(duì)你有所幫助,不要忘了點(diǎn)上寶貴的一贊!
聽說點(diǎn)贊的人運(yùn)氣都不差,相信下一個(gè)升職加薪的一定是你~??
相關(guān)鏈接:10個(gè)常見的前端手寫功能,你全都會(huì)嗎?
以上就是前端手寫功能進(jìn)階的詳細(xì)內(nèi)容,更多關(guān)于前端手寫功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js實(shí)現(xiàn)動(dòng)態(tài)添加上傳文件頁面
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)動(dòng)態(tài)添加上傳文件頁面,如何動(dòng)態(tài)創(chuàng)建一個(gè)input標(biāo)簽示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
layui 動(dòng)態(tài)設(shè)置checbox 選中狀態(tài)的例子
今天小編就為大家分享一篇layui 動(dòng)態(tài)設(shè)置checbox 選中狀態(tài)的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09
JS+HTML5實(shí)現(xiàn)獲取手機(jī)驗(yàn)證碼倒計(jì)時(shí)按鈕
這篇文章主要介紹了基于JS+HTML5實(shí)現(xiàn)獲取手機(jī)驗(yàn)證碼倒計(jì)時(shí)按鈕,代碼簡單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08
layui時(shí)間控件選擇時(shí)間范圍的實(shí)現(xiàn)方法
今天小編就為大家分享一篇layui時(shí)間控件選擇時(shí)間范圍的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09
讓JavaScript 輕松支持函數(shù)重載 (Part 1 - 設(shè)計(jì))
JavaScript支持函數(shù)重載嗎?可以說不支持,也可以說支持。說不支持,是因?yàn)镴avaScript不能好像其它原生支持函數(shù)重載的語言一樣,直接寫多個(gè)同名函數(shù),讓編譯器來判斷某個(gè)調(diào)用對(duì)應(yīng)的是哪一個(gè)重載。2009-08-08
js實(shí)現(xiàn)字符串和數(shù)組之間相互轉(zhuǎn)換操作
這篇文章主要介紹了js實(shí)現(xiàn)字符串和數(shù)組之間相互轉(zhuǎn)換操作的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-01-01

