常用前端手写功能进阶示例详解

目录

  • 1、Promise.all
  • 2、Promise.race
  • 3、Promise.any
  • 4、冒泡排序
  • 5、选择排序
  • 6、快速排序
  • 7、call
  • 8、apply
  • 9、bind
  • 10、instanceof
  • 11、new
  • 12、统计页面中所有标签的种类和个数

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.lengthlet count = 0for (let i = 0; i < len; i++) {// Promise.resolve 的作用是将普通值或 thenable 对象转为 promise,promise 则直接返回Promise.resolve(promises[i]).then((data) => {res[i] = datacount += 1if (count === len) {resolve(res)}}).catch((err) => {reject(err)})}}})}// testfunction 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)}})}// testfunction 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.lengthlet count = 0for (let i = 0; i < len; i++) {Promise.resolve(promises[i]).then(resolve, (err) => {count += 1if (count === promises.length) {reject(new Error('所有 promise 都失败'))}})}})}// testfunction 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.lengthfor (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}// testconst arr = [3, 1, 2, 5, 4]console.log(bubbleSort(arr)) // [1, 2, 3, 4, 5]


5、选择排序
function selectSort(arr) {let len = arr.lengthfor (let i = 0; i < len - 1; i++) {// 假设每次循环,最小值就是第一个let minIndex = ifor (let j = i + 1; j < len; j++) {// 如果最小值大于其他的值,则修改索引,从而找到真正的最小值if (arr[minIndex] > arr[j]) {minIndex = j}}// 最小值和第一个交换位置[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]}return arr}// testconst 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))}// testconst 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] = thisconst args = [...arguments].slice(1)const res = context[key](...args)delete context[key]return res}// testconst myName = { name: 'Jack' }function say() {const [age, height] = argumentsconsole.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] = thislet resif (arguments[1]) {res = context[key](...arguments[1])} else {res = context[key]()}delete context[key]return res}// testconst myName = { name: 'Jack' }function say() {const [age, height] = argumentsconsole.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 = thisconst 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 替换为 contextfn.apply(context, newArgs)}}// 支持 new 调用newFunc.prototype = Object.create(fn.prototype)return newFunc}// testconst myName = { name: 'Jack' }function say() {const [age, height] = argumentsconsole.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 trueproto = 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}// testconsole.log(getTagCount()) // { html: 1, head: 1, body: 1, div: 2, script: 1 }

以上就是今天的分享,你是不是全都掌握了呢,欢迎在评论区交流。如果文章对你有所帮助,不要忘了点上宝贵的一赞!
听说点赞的人运气都不差,相信下一个升职加薪的一定是你~
相关链接:10个常见的前端手写功能,你全都会吗?
【常用前端手写功能进阶示例详解】以上就是前端手写功能进阶的详细内容,更多关于前端手写功能的资料请关注脚本之家其它相关文章!

    推荐阅读