[h1]前言[/h1]
本文针对目前常见的面试题,实现了相应方法的核心原理,部分边界细节未处理。后续也会持续更新,希望对你有所帮助。
[h1]1. 实现一个call函数[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]// 将要改变this指向的方法挂到目标this上执行并返回
复制代码- Function.prototype.mycall = function (context) {
复制代码- if (typeof this !== 'function') {
复制代码- throw new TypeError('not funciton')
复制代码- context = context || window
复制代码- let arg = [...arguments].slice(1)
复制代码- let result = context.fn(...arg)
复制代码 [h1]2. 实现一个apply函数[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]Function.prototype.myapply = function (context) {
复制代码- if (typeof this !== 'function') {
复制代码- throw new TypeError('not funciton')
复制代码- context = context || window
复制代码- result = context.fn(...arguments[1])
复制代码 [h1]3. 实现一个bind函数[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]Function.prototype.mybind = function (context) {
复制代码- if (typeof this !== 'function') {
复制代码- throw new TypeError('Error')
复制代码- let arg = [...arguments].slice(1)
复制代码- return new _this(...arg, ...arguments)
复制代码- return _this.apply(context, arg.concat(...arguments))
复制代码 [h1]4. instanceof的原理[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]// 右边变量的原型存在于左边变量的原型链上
复制代码- function instanceOf(left, right) {
复制代码- let leftValue = left.__proto__
复制代码- let rightValue = right.prototype
复制代码- if (leftValue === null) {
复制代码- if (leftValue === right) {
复制代码- leftValue = rightValue.__proto__
复制代码 [h1]5. Object.create的基本实现原理[/h1]- [/code][list][*][*][*][*][/list][code]function create(obj) {
复制代码 [h1]6. new本质[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]function myNew (fun) {
复制代码- // 创建一个新对象且将其隐式原型指向构造函数原型
复制代码- __proto__ : fun.prototype
复制代码- fun.call(obj, ...arguments)
复制代码- [/code][code]function person(name, age) {
复制代码- let obj = myNew(person)('chen', 18) // {name: "chen", age: 18}
复制代码 [h1]7. 实现一个基本的Promise[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]// ①自动执行函数,②三个状态,③then
复制代码- if (this.state === 'pending') {
复制代码- if (this.state === 'pending') {
复制代码- then(onFulfilled, onRejected) {
复制代码 [h1]8. 实现浅拷贝[/h1]- [/code][list][*][*][*][*][*][*][/list][code]// 1. ...实现
复制代码- [/code][code]// 2. Object.assign实现
复制代码- [/code][code]let copy2 = Object.assign({}, {x:1})
复制代码 [h1]9. 实现一个基本的深拷贝[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]// 1. JOSN.stringify()/JSON.parse()
复制代码- let obj = {a: 1, b: {x: 3}}
复制代码- JSON.parse(JSON.stringify(obj))
复制代码- function deepClone(obj) {
复制代码- let copy = obj instanceof Array ? [] : {}
复制代码- if (obj.hasOwnProperty(i)) {
复制代码- copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
复制代码 [h1]10. 使用setTimeout模拟setInterval[/h1]- [/code][list][*][*][*][*][*][/list][code]// 可避免setInterval因执行时间导致的间隔执行时间不一致
复制代码- setTimeout (function () {
复制代码- setTimeout (arguments.callee, 500)
复制代码 11. js实现一个继承方法// 借用构造函数继承实例属性
- let Super = function () {}
复制代码- Super.prototype = Parent.prototype
复制代码- Child.prototype = new Super()
复制代码 [h1][/h1][h1]12. 实现一个基本的Event Bus[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]// 组件通信,一个触发与监听的过程
复制代码- this.events = this.events || new Map()
复制代码- if (!this.events.get(type)) {
复制代码- this.events.set(type, fn)
复制代码- let handle = this.events.get(type)
复制代码- handle.apply(this, [...arguments].slice(1))
复制代码- let emitter = new EventEmitter()
复制代码- emitter.addListener('ages', age => {
复制代码- emitter.emit('ages', 18) // 18
复制代码 [h1]13. 实现一个双向数据绑定[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]let obj = {}
复制代码- let input = document.getElementById('input')
复制代码- let span = document.getElementById('span')
复制代码- Object.defineProperty(obj, 'text', {
复制代码- input.addEventListener('keyup', function(e) {
复制代码- obj.text = e.target.value
复制代码 完整实现可前往之前写的:这应该是最详细的响应式系统讲解了
[h1][/h1][h1]14. 实现一个简单路由[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]class Route{
复制代码- this.freshRoute = this.freshRoute.bind(this)
复制代码- window.addEventListener('load', this.freshRoute, false)
复制代码- window.addEventListener('hashchange', this.freshRoute, false)
复制代码- this.routes[path] = cb || function () {}
复制代码- this.currentHash = location.hash.slice(1) || '/'
复制代码- this.routes[this.currentHash]()
复制代码 [h1]15. 实现懒加载[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]
复制代码- let imgs = document.querySelectorAll('img')
复制代码- let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
复制代码- let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
复制代码- for (let i = 0; i < imgs.length; i ++) {
复制代码- let x = clientHeight + scrollTop - imgs[i].offsetTop
复制代码- if (x > 0 && x < clientHeight+imgs[i].height) {
复制代码- imgs[i].src = imgs[i].getAttribute('data')
复制代码- setInterval(lazyLoad, 1000)
复制代码 [h1]16. rem实现原理[/h1]- [/code][list][*][*][*][*][*][*][*][/list][code]function setRem () {
复制代码- let doc = document.documentElement
复制代码- let width = doc.getBoundingClientRect().width
复制代码- doc.style.fontSize = rem + 'px'
复制代码 [h1]17. 手写实现AJAX[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]// 1. 简单实现
复制代码- let xhr = new XMLHttpRequest()
复制代码- xhr.open(method, url, async)
复制代码- xhr.onreadystatechange = () => {
复制代码- if (xhr.readyStatus === 4 && xhr.status === 200) {
复制代码- console.log(xhr.responseText)
复制代码- [/code][code]// 2. 基于promise实现
复制代码- [/code][code]function ajax (options) {
复制代码- const method = options.method.toLocaleLowerCase() || 'get'
复制代码- const async = options.async
复制代码- const data = options.data
复制代码- const xhr = new XMLHttpRequest()
复制代码- if (options.timeout && options.timeout > 0) {
复制代码- xhr.timeout = options.timeout
复制代码- return new Promise ((resolve, reject) => {
复制代码- xhr.ontimeout = () => reject && reject('请求超时')
复制代码- xhr.onreadystatechange = () => {
复制代码- if (xhr.readyState == 4) {
复制代码- // 200-300 之间表示请求成功,304资源未变,取缓存
复制代码- if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
复制代码- resolve && resolve(xhr.responseText)
复制代码- xhr.onerror = err => reject && reject(err)
复制代码- if (data instanceof Object) {
复制代码- // 参数拼接需要通过 encodeURIComponent 进行编码
复制代码- paramArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
复制代码- encodeData = paramArr.join('&')
复制代码- const index = url.indexOf('?')
复制代码- if (index === -1) url += '?'
复制代码- else if (index !== url.length -1) url += '&'
复制代码- xhr.open(method, url, async)
复制代码- if (method === 'get') xhr.send(null)
复制代码- xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded;charset=UTF-8')
复制代码 [h1]18. 实现拖拽[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]window.onload = function () {
复制代码- let drag = document.getElementById('box')
复制代码- drag.onmousedown = function(e) {
复制代码- var e = e || window.event
复制代码- // 鼠标与拖拽元素边界的距离 = 鼠标与可视区边界的距离 - 拖拽元素与边界的距离
复制代码- let diffX = e.clientX - drag.offsetLeft
复制代码- let diffY = e.clientY - drag.offsetTop
复制代码- drag.onmousemove = function (e) {
复制代码- // 拖拽元素移动的距离 = 鼠标与可视区边界的距离 - 鼠标与拖拽元素边界的距离
复制代码- let left = e.clientX - diffX
复制代码- let top = e.clientY - diffY
复制代码- } else if (left > window.innerWidth - drag.offsetWidth) {
复制代码- left = window.innerWidth - drag.offsetWidth
复制代码- } else if (top > window.innerHeight - drag.offsetHeight) {
复制代码- top = window.innerHeight - drag.offsetHeight
复制代码- drag.style.left = left + 'px'
复制代码- drag.style.top = top + 'px'
复制代码- drag.onmouseup = function (e) {
复制代码 [h1]19. 实现一个节流函数[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]function throttle (fn, delay) {
复制代码- if (now - prev >= delay) {
复制代码- [/code][code]function fn () {
复制代码- addEventListener('scroll', throttle(fn, 1000))
复制代码 [h1]20. 实现一个防抖函数[/h1]- [/code][list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]function debounce (fn, delay) {
复制代码- // 在规定时间内再次触发会先清除定时器后再重设定时器
复制代码- timer = setTimeout(function () {
复制代码- [/code][code]function fn () {
复制代码- addEventListener('scroll', debounce(fn, 1000))
复制代码 [h1]最后[/h1]后续会持续更新,欢迎关注点个赞!
作者:陈煜仑
https://juejin.im/post/5d2ee123e51d4577614761f8
觉得本文对你有帮助?请分享给更多人!
关注「前端大学」,提升前端技能!
▲长按二维码即可获得100G编程视频资料!
好文章,我在看 |
|