js手写代码 一、JavaScript基础
1.手写 Object.create 思路:将传入的对象作为原型
1 2 3 4 5 function create (obj ) { function F ( ){} F.prototype = obj return new F () }
2. 手写instanceof方法 instanceof 运算符用于判断构造函数的prototype属性是否出现在对象的原型链中的任何位置
实现步骤:
首先获取类型的原型
然后获取对象的原型
然后一直循环判断对象的原型是否等于类型的原型,直到对象原型为null,因为原型链最终为null
具体实现:
1 2 3 4 5 6 7 8 9 10 function myInstanceof (left,right ){ let proto = Object .getPrototypeOf (left) const prototype = right.prototype while (true ) { if (!proto) return false if (proto === prototype) return true proto = Object .getPrototypeOf (proto) } }
3. 手写new操作符 在调用new的过程中会发生以下四件事情
首先创建一个新的空对象
设置原型 将对象的原型设置为函数的prototype对象
让函数的this指向这个对象 指向构造函数的代码 为这个新对象添加属性
判断函数的返回值类型 如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function objectFactory ( ){ let newObject = null let constructor = Array .prototype .shift .call (arguments ) let result = null if (typeof constructor !== "function" ) { console .error ("tYpe error" ) return } newObject = Object .create (constructor.prototype ) result = constructor.apply (newObject,arguments ) console .log (result) let flag = result && (typeof result === 'object' || typeof result === 'funtion' ) console .log (flag) return flag ? result : newObject } objectFactory (Foo ,3 ,4 )
4. 手写Promise 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 const PENDING = 'pending' const RESOLVED = 'resolved' const REJECTED = 'rejected' function MyPromise (fn ) { var self = this this .state = PENDING this .value = null this .resolvedCallbacks = [] this .rejectedCallbacks = [] function resolve (value ) { if (value instanceof MyPromise ) { return value.then (resolve, reject) } if (self.state === PENDING ) { self.state = RESOLVED self.value = value self.resolvedCallbacks .forEach (callback => { callback (value) }) } } function reject (value ) { if (self.state === PENDING ) { self.state = REJECTED self.value = value self.rejectedCallbacks .forEach (callback => { callback (value) }) } } try { fn (resolve, reject) } catch (error) { reject (error) } }
5.手写 Promise.then 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 MyPromise .prototype .then = function (onResolved, onRejected ) { const self = this return new MyPromise ((resolve, reject ) => { let fulfilled = ( ) => { try { const result = onResolved (self.value ) return result instanceof MyPromise ? result.then (resolve, reject) : resolve (result) } catch (error) { reject (error) } } let rejected = ( ) => { try { const result = onRejected (self.value ) return result instanceof MyPromise ? result.then (resolve, reject) : reject (result) } catch (error) { reject (error) } } switch (self.state ) { case PENDING : self.resolvedCallbacks .push (fulfilled) self.rejectedCallbacks .push (rejected) break ; case RESOLVED : fulfilled () break case REJECTED : rejected () break default : break ; } }) } function testMyPromise ( ) { return new MyPromise ((resolve, reject ) => { setTimeout (() => { resolve (100 ) }, 3000 ) }) } testMyPromise ().then (res => { console .log ('123456' , res) })
6.手写Promise.all // 1. 核心思路 // 1. 接收一个Promise实例的数组或具有Iterator接口的对象作为参数 // 2. 这个方法返回一个新的Promise对象 // 3. 遍历传入的参数 用Promise.resolve() 将参数“包一层” 使其变成一个promise对象 // 4. 参数所有回调成功才是成功 返回值数组与参数顺序一致 // 5. 参数数组其中一个失败 则触发失败状态 第一个触发失败的Promise错误信息作为Promise.all的错误信息
// 2.实现代码 // 一般来说 Promise.all 用来处理多个并发请求 也是为了页面数据构造的方法,将一个页面所用到的在不同接口的数据一起请求过来,不过 如果其中一个接口失败了,多个请求也就失败了 页面可能啥也出不来,这就看当前页面的耦合程度了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 function promiseAll (promises ) { return new Promise (function (resolve, reject ) { if (!Array .isArray (promises)) { throw new TypeError ("argument must be a array" ) } let resolveCounter = 0 let promiseNum = promises.length let resolvedResult = [] for (let i = 0 ; i < promiseNum; i++) { Promise .resolve (promises[i]).then (value => { resolveCounter++ resolvedResult[i] = value if (resolveCounter === promiseNum) { return resolve (resolvedResult) } }, error => { return reject (error) }) } }) } let p1 = new Promise (function (resolve, reject ) { setTimeout (() => { resolve (1 ) }, 1000 ) }) let p2 = new Promise (function (resolve, reject ) { setTimeout (() => { resolve (2 ) }, 2000 ) }) let p3 = new Promise (function (resolve, reject ) { setTimeout (() => { resolve (3 ) }, 3000 ) }) promiseAll ([p3, p1, p2]).then (res => { console .log ('res' , res) })
7. 手写 Promise.race // 改方法的参数是 Promise 实例数组,然后其then注册的回调方法是数组中的某一个 // Promise 的状态变为fulfilled的时候就执行,因为Promise的状态只能改变一次 // 那么我们只需要把Promise.race中产生的Promise对象的resolve方法 注入到数组中的每一个Promise实例中的回调函数中即可
1 2 3 4 5 6 7 Promise .race = function (args ) { return new Promise (function (resolve, reject ) { for (let i = 0 ; i < args.length ; i++) { args[i].then (resolve, reject) } }) }
8. 手写防抖函数 // 函数防抖是指在事件被触发n秒后再执行回调,如果在这n秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function debounce (fn, wait ) { let timer = null return function ( ) { let context = this let args = arguments if (timer) { clearTimeout (timer) timer = null } timer = setTimeout (() => { fn.apply (context, args) }, wait) } }
9. 手写节流函数 // 函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发时间的回调函数执行,如果在同一个单位时间内 // 某事件被触发多次,只有一次能生效。节流可以使用在scroll函数的事件监听上,通过事件节流来降低事件调用的频率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function throttle (fn, delay ) { let curTime = Date .now (); return function ( ) { let context = this let args = arguments let nowTime = Date .now (); if (nowTime - curTime >= delay * 1000 ) { curTime = Date .now () return fn.apply (context, args) } } }
10. 手写类型判断函数 1 2 3 4 5 6 7 8 9 10 11 12 13 function getType (value ) { if (value === null ) { return 'null' } if (typeof value === 'object' ) { const typeStr = Object .prototype .toString .call (value) return typeStr.slice (8 ,-1 ) } else { return typeof value } }
13. 手写bind函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Function .prototype .myBind = function (context ) { if (typeof this !== 'function' ) { throw new TypeError ('Error' ) } var args = [...this .arguments ].slice (1 ) var fn = this return function Fn ( ) { return fn.apply ( this instanceof Fn ? this : context, args.concat (...arguments ) ) } }
14. 函数柯里化的实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function curry (fn, args ) { let length = fn.length args = args || [] return function ( ) { let subArgs = args.slice (0 ) for (let i = 0 ; i < arguments .length ; i++) { subArgs.push (arguments [i]) } if (subArgs.length >= length) { return fn.apply (this , subArgs) } else { return curry.call (this , fn, subArgs) } } }
15. 实现AJAX请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function customAjax ( ) { const SEVER_URL = '/server' const xhl = new XMLHttpRequest () xhr.open ("GET" , SEVER_URL , true ) xhr.onreadystatechange = function ( ) { if (this .readyState !== 4 ) return if (this .status === 200 || this .status === 304 ) { handle (this .response ) } else { console .log (this .statusText ) } } xhr.onerror = function ( ) { console .log (this .statusText ) } xhr.responseType = "json" xhr.setRequestHeader ("Accept" , "application/json" ) xhr.send (null ) }