前端问答个人页面-阿里云开发者社区

个人头像照片 前端问答 TA的个人档案
个人头像照片

个人介绍

前端问答小助手

擅长的技术

  • Java
  • 前端开发
获得更多能力
通用技术能力:
  • 前端开发
    高级

    能力说明:

    掌握企业中如何利用常见工具,进行前端开发软件的版本控制与项目构建和协同。开发方面,熟练掌握Vue.js、React、AngularJS和响应式框架Bootstrap,具备开发高级交互网页的能力,具备基于移动设备的Web前端开发,以及Node.js服务器端开发技能。

    获取记录:

云产品技术能力:

暂时未有相关云产品技术能力~

阿里云技能认证

详细说明
  • 高分内容
  • 最新动态
  • 文章
  • 问答
  • 提交了问题 2020-01-02

    用JavaScript实现一个队列?

  • 提交了问题 2019-12-24

    谈谈你对UDP的认识?

  • 提交了问题 2019-11-25

    【精品问答】前端面试手册之算法/笔试题篇

  • 提交了问题 2019-11-24

    【精品问答】前端面试手册

  • 提交了问题 2019-11-24

    【精品问答】前端面试手册之JavaScript篇

正在加载, 请稍后...
滑动查看更多

2020年01月

  • 01.06 12:56:14
    回答了问题 2020-01-06 12:56:14

    Js面向对象的几种方式?

    1.对象的字面量 var obj = {}

    2.创建实例对象 var obj = new Object();

    3.构造函数模式 function fn(){} , new fn();

    4.工厂模式:用一个函数,通过传递参数返回对象。function fn(params){var obj =new Object();obj.params = params; return obj;},fn(params);

    5.原型模式:function clock(hour){} fn.prototype.hour = 0; new clock();

    首先,每个函数都有一个prototype(原型)属性,这个指针指向的就是clock.prototype对象。而这个原型对象在默认的时候有一个属性constructor,指向clock,这个属性可读可写。而当我们在实例化一个对象的时候,实例newClock除了具有构造函数定义的属性和方法外(注意,只是构造函数中的),还有一个指向构造函数的原型的指针,ECMAScript管他叫[[prototype]],这样实例化对象的时候,原型对象的方法并没有在某个具体的实例中,因为原型没有被实例。

    踩0 评论0
  • 01.06 12:55:23
    提交了问题 2020-01-06 12:55:23

    Js面向对象的几种方式?

  • 01.06 12:53:55
    回答了问题 2020-01-06 12:53:55

    谈谈对html5的了解?

    1.良好的移动性,以移动设备为主。

    2.响应式设计,以适应自动变化的屏幕尺寸

    3.支持离线缓存技术,webStorage本地缓存

    4.新增canvas,video,audio等新标签元素。新增特殊内容元素:article,footer,header,nav,section等,新增表单控件:calendar,date,time,email,url,search。

    5.地理定位...

    6.新增webSocket/webWork技术

    踩0 评论0
  • 01.06 12:53:46
    提交了问题 2020-01-06 12:53:46

    谈谈对html5的了解?

  • 01.06 12:47:38
    回答了问题 2020-01-06 12:47:38

    编写一个方法去掉一个数组的重复元素?

    [...new Set(myArray )]
    
    踩0 评论0
  • 01.06 12:42:56
    提交了问题 2020-01-06 12:42:56

    编写一个方法去掉一个数组的重复元素?

  • 01.02 20:35:42
    回答了问题 2020-01-02 20:35:42

    简述jpg,gif,png-8,png-24的区别,及其各自的使用场景?

    gif、jpg、png格式的图片在网站制作中的区别

    Gif格式特点:

      1.透明性,Gif是一种布尔透明类型,既它可以是全透明,也可以是全不透明,但是它并没有半透明(alpha透明)。

      2.动画,Gif这种格式支持动画。

      3.无损耗性,Gif是一种无损耗的图像格式,这也意味着你可以对gif图片做任何操作也不会使得图像质量产生损耗。

      4.水平扫描,Gif是使用了一种叫作LZW的算法进行压缩的,当压缩gif的过程中,像素是由上到下水平压缩的,这也意味着同等条件下,横向的gif图片比竖向的gif图片更加小。例如50010的图片比10500的图片更加小

      5.间隔渐进显示,Gif支持可选择性的间隔渐进显示

      由以上特点看出只有256种颜色的gif图片不适合照片,但它适合对颜色要求不高的图形(比如说图标,图表等),它并不是最优的选择,我们会在后面中看到png是最优的选择。

    Jpeg(jpg)格式特点:

      1.透明性,它并不支持透明。

      2.动画,它也不支持动画。

      3.损耗性,除了一些比如说旋转(仅仅是90、180、270度旋转),裁切,从标准类型到先进类型,编辑图片的原数据之外,所有其它操作对jpeg图像的处理都会使得它的质量损失。所以我们在编辑过程一般用png作为过渡格式。

      4.隔行渐进显示,它支持隔行渐进显示(但是ie浏览器并不支持这个属性,但是ie会在整个图像信息完全到达的时候显示)。

      由上可以看出Jpeg是最适web上面的摄影图片和数字照相机中。

    Png格式特点:

      1.类型,Png这种图片格式包括了许多子类,但是在实践中大致可以分为256色的png和全色的png,你完成可以用256色的png代替gif,用全色的png代替jpeg

      2.透明性,Png是完全支持alpha透明的(透明,半透明,不透明),尽管有两个怪异的现象在ie6(下面详细讨论)

      3.动画,它不支持动画

      PNG图片格式现在包含三种类型:

      1.PNG8256色PNG的别名

      2.PNG24全色PNG的别名

      3.PNG32全色PNG的别名

      基本上PNG32就是PNG24,但是附带了全alpha通道。就是说每个像素上不仅存储了24位真色彩信息还存储了8位的alpha通道信息,就如同GIF能存储透明和不透明信息一样。当我们把图片放到不太搭配的背景上的时候,透明PNG图片的边缘会显示得更加平滑。

      当然,我也知道你的想法,“但是Photoshop也能生成带透明通道的PNG图片!”我也知道,它只是表面上这么说是PNG24,让我也产生困惑了。

      作为一个伤感的Fireworks倡导者,我只使用PNG32支持附带alpha通道的真色彩图片。不管怎样,如果你习惯使Photoshop,你就应该知道,Photoshop在“存储为WEB格式”中只提供PNG8和PNG24两种PNG格式。

      我敢肯定你经常会勾选“支持透明”选项,以获得带有透明度的PNG图片,但是这样你就获取了一张PNG32图片。——Photoshop只是觉得把PNG32这个名称给隐藏掉了。。。。

    对png8的误解

      Png8的在ie中的怪异表现:

      半透明的png8在ie6以下的浏览器显示为全透明。

      Alpha透明的全色PNG(png32)在ie6中会出现背景颜色(通常是灰色)。

      由上面可以总结:

      (a)全透明的png8可以在任一浏览器正常显示(就像gif一样)。半透明的png8在除了ie6及其以下的浏览器下错误的显示成全透明,其它浏览器都能正常显示半透明。这个bug并不需要特殊对待,因为在不支持半透明的浏览器下只是显示为全透明,对用户体验影响不大,它反而是透明gif的加强版。

      (b)第二个bug没有什么好的方法解决,只能通过影响性能的方法AlphaImageLoader与需要加特殊标签(VML)。

      因此得出结论就是:请使用PNG8。

    Png8的软件问题:

      Photoshop只能导出布尔透明的PNG8。

      Fireworks既能导出布尔透明的PNG8,也能导出alpha透明的PNG8.

    踩0 评论0
  • 01.02 20:33:45
    提交了问题 2020-01-02 20:33:45

    简述jpg,gif,png-8,png-24的区别,及其各自的使用场景?

  • 01.02 19:39:52
    回答了问题 2020-01-02 19:39:52

    请写出至少20个HTML5标签?

    <article> 
    <aside> 
    <nav> 
    <section>
    <video> 
    <audio>  
    <canvas>  
    <datalist>    
    <details> 
    <embed>  
    <figcaption> 
    <figure>  
    <footer>  
    <header>  
    <hgroup>  
    <keygen>  
    <mark>     
    <time>   
    <summary> 
    <command>
    <meter> 
    <output>  
    <progress>  
    <source>
    
    踩0 评论0
  • 01.02 19:39:38
    提交了问题 2020-01-02 19:39:38

    请写出至少20个HTML5标签?

  • 01.02 18:43:52
    回答了问题 2020-01-02 18:43:52

    JavaScript实现一个链表?

    概念

    链表是一个线性结构,同时也是一个天然的递归结构。链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

    image.png

    实现

    单向链表

    class Node {
      constructor(v, next) {
        this.value = v
        this.next = next
      }
    }
    class LinkList {
      constructor() {
        // 链表长度
        this.size = 0
        // 虚拟头部
        this.dummyNode = new Node(null, null)
      }
      find(header, index, currentIndex) {
        if (index === currentIndex) return header
        return this.find(header.next, index, currentIndex + 1)
      }
      addNode(v, index) {
        this.checkIndex(index)
        // 当往链表末尾插入时,prev.next 为空
        // 其他情况时,因为要插入节点,所以插入的节点
        // 的 next 应该是 prev.next
        // 然后设置 prev.next 为插入的节点
        let prev = this.find(this.dummyNode, index, 0)
        prev.next = new Node(v, prev.next)
        this.size++
        return prev.next
      }
      insertNode(v, index) {
        return this.addNode(v, index)
      }
      addToFirst(v) {
        return this.addNode(v, 0)
      }
      addToLast(v) {
        return this.addNode(v, this.size)
      }
      removeNode(index, isLast) {
        this.checkIndex(index)
        index = isLast ? index - 1 : index
        let prev = this.find(this.dummyNode, index, 0)
        let node = prev.next
        prev.next = node.next
        node.next = null
        this.size--
        return node
      }
      removeFirstNode() {
        return this.removeNode(0)
      }
      removeLastNode() {
        return this.removeNode(this.size, true)
      }
      checkIndex(index) {
        if (index < 0 || index > this.size) throw Error('Index error')
      }
      getNode(index) {
        this.checkIndex(index)
        if (this.isEmpty()) return
        return this.find(this.dummyNode, index, 0).next
      }
      isEmpty() {
        return this.size === 0
      }
      getSize() {
        return this.size
      }
    }
    
    踩0 评论0
  • 01.02 18:43:22
    提交了问题 2020-01-02 18:43:22

    JavaScript实现一个链表?

  • 01.02 18:42:26
    回答了问题 2020-01-02 18:42:26

    用JavaScript实现一个队列?

    概念

    队列是一个线性结构,特点是在某一端添加数据,在另一端删除数据,遵循先进先出的原则。

    image.png

    实现

    这里会讲解两种实现队列的方式,分别是单链队列和循环队列。

    单链队列

    class Queue {
      constructor() {
        this.queue = []
      }
      enQueue(item) {
        this.queue.push(item)
      }
      deQueue() {
        return this.queue.shift()
      }
      getHeader() {
        return this.queue[0]
      }
      getLength() {
        return this.queue.length
      }
      isEmpty() {
        return this.getLength() === 0
      }
    }
    
    

    因为单链队列在出队操作的时候需要 O(n) 的时间复杂度,所以引入了循环队列。循环队列的出队操作平均是 O(1) 的时间复杂度。

    循环队列

    class SqQueue {
      constructor(length) {
        this.queue = new Array(length + 1)
        // 队头
        this.first = 0
        // 队尾
        this.last = 0
        // 当前队列大小
        this.size = 0
      }
      enQueue(item) {
        // 判断队尾 + 1 是否为队头
        // 如果是就代表需要扩容数组
        // % this.queue.length 是为了防止数组越界
        if (this.first === (this.last + 1) % this.queue.length) {
          this.resize(this.getLength() * 2 + 1)
        }
        this.queue[this.last] = item
        this.size++
        this.last = (this.last + 1) % this.queue.length
      }
      deQueue() {
        if (this.isEmpty()) {
          throw Error('Queue is empty')
        }
        let r = this.queue[this.first]
        this.queue[this.first] = null
        this.first = (this.first + 1) % this.queue.length
        this.size--
        // 判断当前队列大小是否过小
        // 为了保证不浪费空间,在队列空间等于总长度四分之一时
        // 且不为 2 时缩小总长度为当前的一半
        if (this.size === this.getLength() / 4 && this.getLength() / 2 !== 0) {
          this.resize(this.getLength() / 2)
        }
        return r
      }
      getHeader() {
        if (this.isEmpty()) {
          throw Error('Queue is empty')
        }
        return this.queue[this.first]
      }
      getLength() {
        return this.queue.length - 1
      }
      isEmpty() {
        return this.first === this.last
      }
      resize(length) {
        let q = new Array(length)
        for (let i = 0; i < length; i++) {
          q[i] = this.queue[(i + this.first) % this.queue.length]
        }
        this.queue = q
        this.first = 0
        this.last = this.size
      }
    }
    
    踩0 评论0
  • 01.02 12:25:19
    提交了问题 2020-01-02 12:25:19

    用JavaScript实现一个队列?

  • 01.02 12:21:18
    回答了问题 2020-01-02 12:21:18

    用JavaScript实现一个栈结构?

    每种数据结构都可以用很多种方式来实现,其实可以把栈看成是数组的一个子集,所以这里使用数组来实现

    class Stack {
      constructor() {
        this.stack = []
      }
      push(item) {
        this.stack.push(item)
      }
      pop() {
        this.stack.pop()
      }
      peek() {
        return this.stack[this.getCount() - 1]
      }
      getCount() {
        return this.stack.length
      }
      isEmpty() {
        return this.getCount() === 0
      }
    }
    
    踩0 评论0
  • 01.02 12:20:45
    提交了问题 2020-01-02 12:20:45

    用JavaScript实现一个栈结构?

2019年12月

  • 12.30 12:53:32
    回答了问题 2019-12-30 12:53:32

    JavaScript外观模式?

    外观模式提供了一个接口,隐藏了内部的逻辑,更加方便外部调用。

    举个例子来说,我们现在需要实现一个兼容多种浏览器的添加事件方法

    function addEvent(elm, evType, fn, useCapture) {
      if (elm.addEventListener) {
        elm.addEventListener(evType, fn, useCapture)
        return true
      } else if (elm.attachEvent) {
        var r = elm.attachEvent("on" + evType, fn)
        return r
      } else {
        elm["on" + evType] = fn
      }
    }
    
    

    对于不同的浏览器,添加事件的方式可能会存在兼容问题。如果每次都需要去这样写一遍的话肯定是不能接受的,所以我们将这些判断逻辑统一封装在一个接口中,外部需要添加事件只需要调用 addEvent 即可。

    踩0 评论0
  • 12.30 12:53:23
    提交了问题 2019-12-30 12:53:23

    JavaScript外观模式?

  • 12.30 12:51:12
    回答了问题 2019-12-30 12:51:12

    JavaScript发布-订阅模式?

    发布-订阅模式也叫做观察者模式。通过一对一或者一对多的依赖关系,当对象发生改变时,订阅方都会收到通知。在现实生活中,也有很多类似场景,比如我需要在购物网站上购买一个产品,但是发现该产品目前处于缺货状态,这时候我可以点击有货通知的按钮,让网站在产品有货的时候通过短信通知我。

    在实际代码中其实发布-订阅模式也很常见,比如我们点击一个按钮触发了点击事件就是使用了该模式

    <ul id="ul"></ul>
    <script>
        let ul = document.querySelector('#ul')
        ul.addEventListener('click', (event) => {
            console.log(event.target);
        })
    </script>
    
    

    在 Vue 中,如何实现响应式也是使用了该模式。对于需要实现响应式的对象来说,在 get 的时候会进行依赖收集,当改变了对象的属性时,就会触发派发更新。

    踩0 评论0
  • 12.30 12:50:57
    提交了问题 2019-12-30 12:50:57

    JavaScript发布-订阅模式?

正在加载, 请稍后...
滑动查看更多
  • 发表了文章 2019-11-22

    test

正在加载, 请稍后...
滑动查看更多
  • 回答了问题 2020-01-06

    Js面向对象的几种方式?

    1.对象的字面量 var obj = {}

    2.创建实例对象 var obj = new Object();

    3.构造函数模式 function fn(){} , new fn();

    4.工厂模式:用一个函数,通过传递参数返回对象。function fn(params){var obj =new Object();obj.params = params; return obj;},fn(params);

    5.原型模式:function clock(hour){} fn.prototype.hour = 0; new clock();

    首先,每个函数都有一个prototype(原型)属性,这个指针指向的就是clock.prototype对象。而这个原型对象在默认的时候有一个属性constructor,指向clock,这个属性可读可写。而当我们在实例化一个对象的时候,实例newClock除了具有构造函数定义的属性和方法外(注意,只是构造函数中的),还有一个指向构造函数的原型的指针,ECMAScript管他叫[[prototype]],这样实例化对象的时候,原型对象的方法并没有在某个具体的实例中,因为原型没有被实例。

    踩0 评论0
  • 提交了问题 2020-01-06

    Js面向对象的几种方式?

  • 回答了问题 2020-01-06

    谈谈对html5的了解?

    1.良好的移动性,以移动设备为主。

    2.响应式设计,以适应自动变化的屏幕尺寸

    3.支持离线缓存技术,webStorage本地缓存

    4.新增canvas,video,audio等新标签元素。新增特殊内容元素:article,footer,header,nav,section等,新增表单控件:calendar,date,time,email,url,search。

    5.地理定位...

    6.新增webSocket/webWork技术

    踩0 评论0
  • 提交了问题 2020-01-06

    谈谈对html5的了解?

  • 回答了问题 2020-01-06

    编写一个方法去掉一个数组的重复元素?

    [...new Set(myArray )]
    
    踩0 评论0
  • 提交了问题 2020-01-06

    编写一个方法去掉一个数组的重复元素?

  • 回答了问题 2020-01-02

    简述jpg,gif,png-8,png-24的区别,及其各自的使用场景?

    gif、jpg、png格式的图片在网站制作中的区别

    Gif格式特点:

      1.透明性,Gif是一种布尔透明类型,既它可以是全透明,也可以是全不透明,但是它并没有半透明(alpha透明)。

      2.动画,Gif这种格式支持动画。

      3.无损耗性,Gif是一种无损耗的图像格式,这也意味着你可以对gif图片做任何操作也不会使得图像质量产生损耗。

      4.水平扫描,Gif是使用了一种叫作LZW的算法进行压缩的,当压缩gif的过程中,像素是由上到下水平压缩的,这也意味着同等条件下,横向的gif图片比竖向的gif图片更加小。例如50010的图片比10500的图片更加小

      5.间隔渐进显示,Gif支持可选择性的间隔渐进显示

      由以上特点看出只有256种颜色的gif图片不适合照片,但它适合对颜色要求不高的图形(比如说图标,图表等),它并不是最优的选择,我们会在后面中看到png是最优的选择。

    Jpeg(jpg)格式特点:

      1.透明性,它并不支持透明。

      2.动画,它也不支持动画。

      3.损耗性,除了一些比如说旋转(仅仅是90、180、270度旋转),裁切,从标准类型到先进类型,编辑图片的原数据之外,所有其它操作对jpeg图像的处理都会使得它的质量损失。所以我们在编辑过程一般用png作为过渡格式。

      4.隔行渐进显示,它支持隔行渐进显示(但是ie浏览器并不支持这个属性,但是ie会在整个图像信息完全到达的时候显示)。

      由上可以看出Jpeg是最适web上面的摄影图片和数字照相机中。

    Png格式特点:

      1.类型,Png这种图片格式包括了许多子类,但是在实践中大致可以分为256色的png和全色的png,你完成可以用256色的png代替gif,用全色的png代替jpeg

      2.透明性,Png是完全支持alpha透明的(透明,半透明,不透明),尽管有两个怪异的现象在ie6(下面详细讨论)

      3.动画,它不支持动画

      PNG图片格式现在包含三种类型:

      1.PNG8256色PNG的别名

      2.PNG24全色PNG的别名

      3.PNG32全色PNG的别名

      基本上PNG32就是PNG24,但是附带了全alpha通道。就是说每个像素上不仅存储了24位真色彩信息还存储了8位的alpha通道信息,就如同GIF能存储透明和不透明信息一样。当我们把图片放到不太搭配的背景上的时候,透明PNG图片的边缘会显示得更加平滑。

      当然,我也知道你的想法,“但是Photoshop也能生成带透明通道的PNG图片!”我也知道,它只是表面上这么说是PNG24,让我也产生困惑了。

      作为一个伤感的Fireworks倡导者,我只使用PNG32支持附带alpha通道的真色彩图片。不管怎样,如果你习惯使Photoshop,你就应该知道,Photoshop在“存储为WEB格式”中只提供PNG8和PNG24两种PNG格式。

      我敢肯定你经常会勾选“支持透明”选项,以获得带有透明度的PNG图片,但是这样你就获取了一张PNG32图片。——Photoshop只是觉得把PNG32这个名称给隐藏掉了。。。。

    对png8的误解

      Png8的在ie中的怪异表现:

      半透明的png8在ie6以下的浏览器显示为全透明。

      Alpha透明的全色PNG(png32)在ie6中会出现背景颜色(通常是灰色)。

      由上面可以总结:

      (a)全透明的png8可以在任一浏览器正常显示(就像gif一样)。半透明的png8在除了ie6及其以下的浏览器下错误的显示成全透明,其它浏览器都能正常显示半透明。这个bug并不需要特殊对待,因为在不支持半透明的浏览器下只是显示为全透明,对用户体验影响不大,它反而是透明gif的加强版。

      (b)第二个bug没有什么好的方法解决,只能通过影响性能的方法AlphaImageLoader与需要加特殊标签(VML)。

      因此得出结论就是:请使用PNG8。

    Png8的软件问题:

      Photoshop只能导出布尔透明的PNG8。

      Fireworks既能导出布尔透明的PNG8,也能导出alpha透明的PNG8.

    踩0 评论0
  • 提交了问题 2020-01-02

    简述jpg,gif,png-8,png-24的区别,及其各自的使用场景?

  • 回答了问题 2020-01-02

    请写出至少20个HTML5标签?

    <article> 
    <aside> 
    <nav> 
    <section>
    <video> 
    <audio>  
    <canvas>  
    <datalist>    
    <details> 
    <embed>  
    <figcaption> 
    <figure>  
    <footer>  
    <header>  
    <hgroup>  
    <keygen>  
    <mark>     
    <time>   
    <summary> 
    <command>
    <meter> 
    <output>  
    <progress>  
    <source>
    
    踩0 评论0
  • 提交了问题 2020-01-02

    请写出至少20个HTML5标签?

  • 回答了问题 2020-01-02

    JavaScript实现一个链表?

    概念

    链表是一个线性结构,同时也是一个天然的递归结构。链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

    image.png

    实现

    单向链表

    class Node {
      constructor(v, next) {
        this.value = v
        this.next = next
      }
    }
    class LinkList {
      constructor() {
        // 链表长度
        this.size = 0
        // 虚拟头部
        this.dummyNode = new Node(null, null)
      }
      find(header, index, currentIndex) {
        if (index === currentIndex) return header
        return this.find(header.next, index, currentIndex + 1)
      }
      addNode(v, index) {
        this.checkIndex(index)
        // 当往链表末尾插入时,prev.next 为空
        // 其他情况时,因为要插入节点,所以插入的节点
        // 的 next 应该是 prev.next
        // 然后设置 prev.next 为插入的节点
        let prev = this.find(this.dummyNode, index, 0)
        prev.next = new Node(v, prev.next)
        this.size++
        return prev.next
      }
      insertNode(v, index) {
        return this.addNode(v, index)
      }
      addToFirst(v) {
        return this.addNode(v, 0)
      }
      addToLast(v) {
        return this.addNode(v, this.size)
      }
      removeNode(index, isLast) {
        this.checkIndex(index)
        index = isLast ? index - 1 : index
        let prev = this.find(this.dummyNode, index, 0)
        let node = prev.next
        prev.next = node.next
        node.next = null
        this.size--
        return node
      }
      removeFirstNode() {
        return this.removeNode(0)
      }
      removeLastNode() {
        return this.removeNode(this.size, true)
      }
      checkIndex(index) {
        if (index < 0 || index > this.size) throw Error('Index error')
      }
      getNode(index) {
        this.checkIndex(index)
        if (this.isEmpty()) return
        return this.find(this.dummyNode, index, 0).next
      }
      isEmpty() {
        return this.size === 0
      }
      getSize() {
        return this.size
      }
    }
    
    踩0 评论0
  • 提交了问题 2020-01-02

    JavaScript实现一个链表?

  • 回答了问题 2020-01-02

    用JavaScript实现一个队列?

    概念

    队列是一个线性结构,特点是在某一端添加数据,在另一端删除数据,遵循先进先出的原则。

    image.png

    实现

    这里会讲解两种实现队列的方式,分别是单链队列和循环队列。

    单链队列

    class Queue {
      constructor() {
        this.queue = []
      }
      enQueue(item) {
        this.queue.push(item)
      }
      deQueue() {
        return this.queue.shift()
      }
      getHeader() {
        return this.queue[0]
      }
      getLength() {
        return this.queue.length
      }
      isEmpty() {
        return this.getLength() === 0
      }
    }
    
    

    因为单链队列在出队操作的时候需要 O(n) 的时间复杂度,所以引入了循环队列。循环队列的出队操作平均是 O(1) 的时间复杂度。

    循环队列

    class SqQueue {
      constructor(length) {
        this.queue = new Array(length + 1)
        // 队头
        this.first = 0
        // 队尾
        this.last = 0
        // 当前队列大小
        this.size = 0
      }
      enQueue(item) {
        // 判断队尾 + 1 是否为队头
        // 如果是就代表需要扩容数组
        // % this.queue.length 是为了防止数组越界
        if (this.first === (this.last + 1) % this.queue.length) {
          this.resize(this.getLength() * 2 + 1)
        }
        this.queue[this.last] = item
        this.size++
        this.last = (this.last + 1) % this.queue.length
      }
      deQueue() {
        if (this.isEmpty()) {
          throw Error('Queue is empty')
        }
        let r = this.queue[this.first]
        this.queue[this.first] = null
        this.first = (this.first + 1) % this.queue.length
        this.size--
        // 判断当前队列大小是否过小
        // 为了保证不浪费空间,在队列空间等于总长度四分之一时
        // 且不为 2 时缩小总长度为当前的一半
        if (this.size === this.getLength() / 4 && this.getLength() / 2 !== 0) {
          this.resize(this.getLength() / 2)
        }
        return r
      }
      getHeader() {
        if (this.isEmpty()) {
          throw Error('Queue is empty')
        }
        return this.queue[this.first]
      }
      getLength() {
        return this.queue.length - 1
      }
      isEmpty() {
        return this.first === this.last
      }
      resize(length) {
        let q = new Array(length)
        for (let i = 0; i < length; i++) {
          q[i] = this.queue[(i + this.first) % this.queue.length]
        }
        this.queue = q
        this.first = 0
        this.last = this.size
      }
    }
    
    踩0 评论0
  • 提交了问题 2020-01-02

    用JavaScript实现一个队列?

  • 回答了问题 2020-01-02

    用JavaScript实现一个栈结构?

    每种数据结构都可以用很多种方式来实现,其实可以把栈看成是数组的一个子集,所以这里使用数组来实现

    class Stack {
      constructor() {
        this.stack = []
      }
      push(item) {
        this.stack.push(item)
      }
      pop() {
        this.stack.pop()
      }
      peek() {
        return this.stack[this.getCount() - 1]
      }
      getCount() {
        return this.stack.length
      }
      isEmpty() {
        return this.getCount() === 0
      }
    }
    
    踩0 评论0
  • 提交了问题 2020-01-02

    用JavaScript实现一个栈结构?

  • 回答了问题 2019-12-30

    JavaScript外观模式?

    外观模式提供了一个接口,隐藏了内部的逻辑,更加方便外部调用。

    举个例子来说,我们现在需要实现一个兼容多种浏览器的添加事件方法

    function addEvent(elm, evType, fn, useCapture) {
      if (elm.addEventListener) {
        elm.addEventListener(evType, fn, useCapture)
        return true
      } else if (elm.attachEvent) {
        var r = elm.attachEvent("on" + evType, fn)
        return r
      } else {
        elm["on" + evType] = fn
      }
    }
    
    

    对于不同的浏览器,添加事件的方式可能会存在兼容问题。如果每次都需要去这样写一遍的话肯定是不能接受的,所以我们将这些判断逻辑统一封装在一个接口中,外部需要添加事件只需要调用 addEvent 即可。

    踩0 评论0
  • 提交了问题 2019-12-30

    JavaScript外观模式?

  • 回答了问题 2019-12-30

    JavaScript发布-订阅模式?

    发布-订阅模式也叫做观察者模式。通过一对一或者一对多的依赖关系,当对象发生改变时,订阅方都会收到通知。在现实生活中,也有很多类似场景,比如我需要在购物网站上购买一个产品,但是发现该产品目前处于缺货状态,这时候我可以点击有货通知的按钮,让网站在产品有货的时候通过短信通知我。

    在实际代码中其实发布-订阅模式也很常见,比如我们点击一个按钮触发了点击事件就是使用了该模式

    <ul id="ul"></ul>
    <script>
        let ul = document.querySelector('#ul')
        ul.addEventListener('click', (event) => {
            console.log(event.target);
        })
    </script>
    
    

    在 Vue 中,如何实现响应式也是使用了该模式。对于需要实现响应式的对象来说,在 get 的时候会进行依赖收集,当改变了对象的属性时,就会触发派发更新。

    踩0 评论0
  • 提交了问题 2019-12-30

    JavaScript发布-订阅模式?

正在加载, 请稍后...
滑动查看更多