前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >前端面试手写代码

前端面试手写代码

作者头像
小小杨
发布于 2021-10-13 02:31:55
发布于 2021-10-13 02:31:55
34200
代码可运行
举报
文章被收录于专栏:下落木下落木
运行总次数:0
代码可运行

单例模式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SingleObject{
  constructor(name) {
    this.name = name
  }

  login() {
    console.log('name: ', this.name)
  }
}

SingleObject.getInstance = (() => {
  let instance

  return (name) => {
    if (!instance) {
      instance = new SingleObject(name)
    }
    return instance
  }
})()

// 测试
const a = SingleObject.getInstance('yang')
const b = SingleObject.getInstance('guo')

console.log(a === b) // true
console.log(a.login(), b.login()) // yang

// getInstance是类的静态方法,不能使用new SingleObject()
// 创建出来的实例全等

观察者模式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 目标对象
class Subject{
  constructor() {
    this.subs = []
  }

  addSub(sub) {
    this.subs.push(sub)
  }

  notify() {
    this.subs.map(sub => {
      sub.update()
    })
  }
}

// 观察者
class Observer{
  update() {
    console.log('updating')
  }
}

// 测试
const subject = new Subject()
const observer = new Observer()
subject.addSub(observer)
subject.notify()

// 首先是目标的构造函数,他有个数组,用于添加观察者
// 还有个广播方法notify,遍历观察者数组后调用观察者们的update方法

发布订阅模式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class EventEmitter{
  constructor() {
    this._eventPool = {}
  }

  on(event, cb) {
    this._eventPool.event ?
    this._eventPool.event.push(cb)
      :
    this._eventPool[event] = [cb]
  }

  off(event) {
    delete this._eventPool[event]
  }

  emit(event, ...args) {
     if (this._eventPool[event]) {
      this._eventPool[event].map(cb => {
        cb(...args)
      })
    }
  }

  once(event, cb) {
    this.on(event, (...args) => {
      cb(...args)
      this.off(event)
    })
  }
}

// 测试
const emitter = new EventEmitter()

emitter.on('a', (aaa, bbb) => {
  console.log('fffffff', aaa, bbb)
})

emitter.emit('a', 'windy', 'tom')

emitter.once('b', (aaa, bbb) => {
  console.log('fffffff', aaa, bbb)
})
emitter.emit('b', 'windy', 'tom')
代码语言:javascript
代码运行次数:0
运行
复制

基于一个主题/事件通道,订阅者subscriber通过自定义事件订阅主题,发布者publisher通过发布主题事件的方式发布。

观察者模式和发布订阅模式区别

  1. 在观察者模式中,观察者需要直接订阅目标事件。在目标发出内容改变的事件后,直接接收事件并作出响应。
  2. 发布订阅模式相比观察者模式多了个主题/事件通道,订阅者和发布者不是直接关联的。
  3. 观察者模式两个对象之间有很强的依赖关系;发布/订阅模式两个对象之间的耦合度低。

函数柯里化

当我们没有重新定义toString与valueOf时,函数的隐式转换会调用默认的toString方法,它会将函数的定义内容作为字符串返回。

而当我们主动定义了toString/vauleOf方法时,那么隐式转换的返回结果则由我们自己控制了。其中valueOf的优先级会toString高一点。

柯里化好处:参数复用、延迟运行(返回函数,想什么时候运行什么时候运行)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function currying() {
 const [fn, ..._args] = [...arguments]
 const cb = function() {
 if (!arguments.length) {
 return fn.apply(this, _args)
    }
 _args.push(...arguments)
 return cb
  }

 // 可根据需要添加
 cb.toString = fn.apply(this, _args)

 return cb
}

// 测试柯里化
function add() {
 return [...arguments].reduce((a, b) => a + b)
}

const a = currying(add, 12, 24, 36)
console.log(a()) // 72
代码语言:javascript
代码运行次数:0
运行
复制

实现一个add方法,使结果满足如下预期

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function add() {
  let _args = [...arguments]
  const _adder = function() {
    _args.push(...arguments)
    return _adder
  }

  _adder.toString = function() {
    return _adder.reduce((a, b) => a + b)
  }
  return _adder
}

实现call和apply

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Function.prototype.myCall = function() {
  let [context, ...args] = [...arguments]
  if (!context) context = window

  context.fn = this
  const res = context.fn(...args)

  delete context.fn
  return res
}

Function.prototype.myApply = function() {
  let [context, args] = [...arguments]
  if (!context) context = window

  context.fn = this
  let res
  if (args) {
    res = context.fn(...args)
  } else {
    res = context.fn()
  }

  delete context.fn
  return res
}

// 测试
const person = {
  name: 'mike',
  getName: function(a, b) {
    console.log(this.name, a, b)
  }
}

function printName(a, b) {
  console.log(this.name, a, b)
}

printName.myCall(person, 'time', 'fly')
printName.myApply(person, ['time', 'fly'])

实现bind

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Function.prototype.myBind = function() {
  const [context, ...args] = [...arguments]
  const _this = this
  return function() {
    return _this.apply(context, args.concat(...arguments))
  }
}

const person = {
  name: 'mike',
  getName: function(a, b) {
    console.log(this.name, a, b)
  }
}

// 测试
const boy = {
  name: 'boy'
}

const getName2 = person.getName.myBind(boy, 'hhhh', 'yyyy')
getName2() // boy hhhh yyyy

实现instanceof

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function myInstanceof(left, right) {
  let leftVal = left.__proto__
  let rightVal = right.prototype

  while (true) {
    if (leftVal === null) return false
    if (leftVal === rightVal) return true
    leftVal = leftVal.__proto__
  }
}
代码语言:javascript
代码运行次数:0
运行
复制

new的本质

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function myNew(fun) {
  return function() {
  const obj = {
    __proto__: fun.prototype
  }

  fun.call(obj, ...arguments)
    return obj
  }
}

// 测试
function Person(name, age) {
  this.name = name
  this.age = age
}

const obj = myNew(Person)('yang', 18)
// Person { name: 'yang', age: 18 }
代码语言:javascript
代码运行次数:0
运行
复制

Object.create的基本原理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function myCreate(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
代码语言:javascript
代码运行次数:0
运行
复制

实现promise

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class MyPromise{
  constructor(process) {
    this.status = 'pending'
    this.msg = ''
    process(this.resolve.bind(this), this.reject.bind(this))
    return this
  }

  resolve(val) {
    this.status = 'fulfilled'
    this.msg = val
  }

  reject(val) {
    this.status = 'rejected'
    this.msg = val
  }

  then(fulfilled, reject) {
    if (this.status === 'fulfilled') {
      fulfilled(this.msg)
    }
    if (this.status === 'rejected'){
      reject(this.msg)
    }
  }
}

// 测试
const mm = new MyPromise((resolve, reject) => {
  resolve('123')
})

mm.then(res => {
  console.log(res, 'success')
})
代码语言:javascript
代码运行次数:0
运行
复制

防抖和节流

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。

区别:

  1. 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。
  2. 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

应用:进行窗口的resize、scroll,输入框内容校验或请求ajax时

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 防抖
function debounce(fn, time) {
  let timeout
  return function() {
    const _this = this
    const args = arguments

    if (timeout) clearTimeout(timeout)
    timeout = setTimeout(() => {
      fn.apply(_this, args)
    }, time || 500)
  }
}

// 节流
function throttle(fn, time) {
  let timeout
  return function() {
    const _this = this
    const args = arguments

    if (!timeout) {
      timeout = setTimeout(() => {
        fn.apply(_this, args)
        timeout = null
      }, time || 500)
    }
  }
}



function count() {
  console.log('counting')
}

window.onscroll = debounce(count, 1000)
window.onscroll = throttle(count, 1000)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制


for循环和reduce实现map和filter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// for循环实现map
Array.prototype.map2 = function() {
 const arr = this
 const [fn, thisArg] = [...arguments]
 let res = []

 for ( let i = 0; i < arr.length; i++) {
 res.push(fn.call(thisArg, arr[i], i, arr))
  }
 return res
}

// reduce实现map
Array.prototype.map3 = function() {
 const arr = this
 const [fn, thisArg] = [...arguments]

 return arr.reduce((acc, cur, i) => {
 acc.push(fn.call(thisArg, cur, i, arr))
 return acc
  }, [])
}

// 测试map
const m = [1,2,3,4,54].map2(item => item * item)
console.log(m) // [ 1, 4, 9, 16, 2916 ]

// for循环实现filter
Array.prototype.filter2 = function() {
 const arr = this
 const [fn, thisArg] = [...arguments]
 let res = []

 for ( let i = 0; i < arr.length; i++) {
 if (fn.call(thisArg, arr[i], i, arr)) {
 res.push(arr[i])
    }
  }
 return res
}

// reduce实现filter
Array.prototype.filter3 = function() {
 const arr = this
 const [fn, thisArg] = [...arguments]

 return arr.reduce((acc, cur, i) => {
 fn.call(thisArg, cur, i, arr) && acc.push(cur)
 return acc
  }, [])
}

// 测试filter
const n = [0, 1, 2, 3, 4, 5]
const n2 = n.filter3(item => item % 2)
console.log(n2) // [ 1, 3, 5 ]

使用for循环打印1-10, 每个数字出现间隔500ms

错误方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 结果虽然依次输出了1-10,但是每个数字之间没有间隔,是一次性输出的,所以不正确
for (var i = 1; i <= 10; i++) {
 setTimeout((function(i) {
   console.log(i);
 })(i), 500); 
}
代码语言:javascript
代码运行次数:0
运行
复制

正确方法:

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 使用闭包,注意setTimeout, 每隔500ms,因此每次传递的间隔时间要乘以i
for(var i=1;i<=10;i++){
 (function(i){
   setTimeout(function(){
     console.log(i);
   },500 * i);
 })(i);
}
代码语言:javascript
代码运行次数:0
运行
复制

或者使用let,let本身就是块级作用域

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for(let i=1;i<=10;i++){
 setTimeout(function(){
   console.log(i);
 },500 * i);
}

使用setTimeout模拟setInterval

代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function fn() {
  console.log('123')
}

setTimeout(function f() {
  fn()
  setTimeout(f, 500)
}, 500)

ES5实现继承

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Parent() {
  this.name = 'parent'
  this.play = [1, 2, 3]
}

function Child() {
  Parent.call(this)
  this.name = 'child'
}

Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child

// 测试
const ss = new Child()
console.log(ss instanceof Child, ss instanceof Parent) // true true
console.log(ss.constructor) // Child
代码语言:javascript
代码运行次数:0
运行
复制
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 下落木 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
require和import的区别
CommonJs 规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的 exports属性(即module.exports)是对外的接口,加载某个模块,其实是加载该模块的module.exports属性。
木子星兮
2020/07/16
1.2K0
10个最佳ES6特性
为了保证可读性,本文采用意译而非直译,并且对源代码进行了大量修改。另外,本文版权归原作者所有,翻译仅用于学习。
疯狂的技术宅
2019/03/28
5030
前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例
使用vue-cli可以规范项目,提高开发效率,但是使用vue-cli时需要一些ECMAScript6的知识,特别是ES6中的模块管理内容,本章先介绍ES6中的基础与模块化的内容再使用vue-cli开发vue项目。 一、ECMAScript6概要 ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaSc
张果
2018/03/30
1.8K0
前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例
前端模块化详解(完整版)
上例子通过jquery方法将页面的背景颜色改成红色,所以必须先引入jQuery库,就把这个库当作参数传入。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。
小生方勤
2019/06/01
2.2K0
前端模块化详解(完整版)
在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀,此时在JS方面就会考虑使用模块化规范去管理。 本文内容主要有理解模块化,为什么要模块化,模块化的优缺点以及模块化规范,并且介绍下开发中最流行的CommonJS, AMD, ES6、CMD规范。本文试图站在小白的角度,用通俗易懂的笔调介绍这些枯燥无味的概念,希望诸君阅读后,对模块化编程有个全新的认识和理解!
Nealyang
2019/09/29
1.3K0
前端模块化详解(完整版)
前端模块化的今生
众所周知,早期 JavaScript 原生并不支持模块化,直到 2015 年,TC39 发布 ES6,其中有一个规范就是 ES modules(为了方便表述,后面统一简称 ESM)。但是在 ES6 规范提出前,就已经存在了一些模块化方案,比如 CommonJS(in Node.js)、AMD。ESM 与这些规范的共同点就是都支持导入(import)和导出(export)语法,只是其行为的关键词也一些差异。
ConardLi
2019/12/17
7040
前端模块化-CommonJS,AMD,CMD,ES6
随着 JavaScript 工程越来越大,团队协作不可避免,为了更好地对代码进行管理和测试,模块化的概念逐渐引入前端。模块化可以降低协同开发的成本,减少代码量,同时也是“高内聚,低耦合”的基础。
李振
2021/11/26
4230
Javascript模块化详解
前端的发展日新月异,前端工程的复杂度也不可同日而语。原始的开发方式,随着项目复杂度提高,代码量越来越多,所需加载的文件也越来越多,这个时候就需要考虑如下几个问题:
Clearlove
2021/03/11
6290
Javascript模块化详解
深入理解 ES Module
Module是ES6 出现的一个新的语法,提供一种将 JavaScript 程序拆分为可按需导入的单独模块的机制。在未出现之前,我们可能使用 commonjs等模块规范。随着ES Module的普及和推广,浏览器已经支持原生的模块规范。
前端知知
2022/09/29
4340
深入理解 ES Module
【译】开始在web中使用JS Modules
原文:《Using JavaScript modules on the web》 https://developers.google.com/web/fundamentals/primers/modules 译者序 JS modules,即ES6的模块化特性,通过 <scripttype="modules">可以实现不经过打包直接在浏览器中import/export,此玩法确实让人眼前一亮。 先看看 <scripttype="modules">的兼容性。目前只有较新版本的chrome/firefox/saf
QQ音乐前端团队
2018/08/12
1.2K0
模块化的一些小研究
我们知道最常见的模块化方案有CommonJS、AMD、CMD、ES6,AMD规范一般用于浏览器,异步的,因为模块加载是异步的,js解释是同步的,所以有时候导致依赖还没加载完毕,同步的代码运行结束;CommonJS规范一般用于服务端,同步的,因为在服务器端所有文件都存储在本地的硬盘上,传输速率快而且稳定。
lhyt
2022/09/21
3320
【THE LAST TIME】深入浅出 JavaScript 模块化
随着互联网的发展,前端开发也变的越来越复杂,从一开始的表单验证到现在动不动上千上万行代码的项目开发,团队协作就是我们不可避免的工作方式,为了更好地管理功能逻辑,模块化的概念也就渐渐产生了。
Nealyang
2020/01/14
7090
【THE LAST TIME】深入浅出 JavaScript 模块化
五分钟带你回顾前端模块化发展史
CSS 早在 2.1 的版本就提出了 @import 来实现模块化,但是 JavaScript 直到 ES6 才出现官方的模块化方案 ES Module。尽管早期 JavaScript 语言规范上不支持模块化,但这并没有阻止 JavaScript 的发展。官方没有模块化标准,那么我们就自己动手创建标准。社区里的前辈们创建并实现了规范,这些规范便是前端模块化发展之路上智慧的结晶。
童欧巴
2020/03/30
8890
五分钟带你回顾前端模块化发展史
Vue学习-ES6的模块化实现
在实际编写js脚本时,可能会遇到多个js脚本中变量或函数重复命名的情况,如果全部为全局变量,则在使用的时候会产生很多麻烦。因此出现了模块化的概念,即可以把每一个js脚本当作一个独立的模块,不同模块间的内容互不干扰,这样在实际使用起来的时候会避免很多不必要的麻烦。
花猪
2022/02/17
4120
模块化的一些小研究0.前言1.script标签引入2.AMD与CMD3.CommonJS与ES64.循环依赖5.webpack是如何处理模块化的
我们知道最常见的模块化方案有CommonJS、AMD、CMD、ES6,AMD规范一般用于浏览器,异步的,因为模块加载是异步的,js解释是同步的,所以有时候导致依赖还没加载完毕,同步的代码运行结束;CommonJS规范一般用于服务端,同步的,因为在服务器端所有文件都存储在本地的硬盘上,传输速率快而且稳定。
lhyt
2018/10/31
1.3K0
50 种 ES6 模块,面试被问麻了
快来免费体验ChatGpt plus版本的,我们出的钱 体验地址:https://chat.waixingyun.cn可以加入网站底部技术群,一起找bug,...
前端小智@大迁世界
2024/02/12
1980
50 种 ES6 模块,面试被问麻了
【译】开始在web使用JS Modules
原文说的JS modules,实际上指的是ES6的模块化特性,通过<script type="module">可以实现不经过打包直接在浏览器中import/export,此玩法确实让人眼前一亮。
elson
2018/07/04
2K0
【译】开始在web使用JS Modules
[译]ES6 模块化入门
在 ES6 之前,我们已经知道了 RequireJS,AngularJS 的依赖注入,以及 CommonJS,具体可以看笔者的上一篇文章《JS模块化历史简介》。当我们学习 ES6 的模块化,就会发现它的发展深受 CommonJS 的影响。通过这篇文章,我们将看到 export 和 import 语句,以及 ES6 模块是怎么与 CommonJS 模块兼容的。
savokiss
2019/11/06
8260
【前端】:模块化 - 打包技术
ES modules export live bindings, not values, so values can be changed after they are initially imported as per.
WEBJ2EE
2020/09/01
1.5K0
【前端】:模块化 - 打包技术
javaScript模块化解析「建议收藏」
上面说提到的结构,就是模块;按照这种结构划分开发程序的过程,就是模块化开发的过程;
全栈程序员站长
2022/11/15
5040
javaScript模块化解析「建议收藏」
相关推荐
require和import的区别
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 单例模式
  • 观察者模式
  • 发布订阅模式
  • 函数柯里化
  • 实现一个add方法,使结果满足如下预期
  • 实现call和apply
  • 实现bind
  • 实现instanceof
  • new的本质
  • Object.create的基本原理
  • 实现promise
  • 防抖和节流
  • for循环和reduce实现map和filter
  • 使用for循环打印1-10, 每个数字出现间隔500ms
  • 使用setTimeout模拟setInterval
  • ES5实现继承
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档