前端开发知识点总结

1、如何将数据非常大的数据渲染而不卡顿  / js完成一个无限循环的动画

  • 定时器setInterval,做数据分割,批次渲染
  • 高级进阶:requestAnimationFrame  (H5新特性)cancalAnimationFrame
    • 帧动画,每一帧会执行一次的定时器,一般每秒60帧(1000/60)
    • 优势
      • requestAnimationFrame会把每一帧中的DOM操作集中起来,完成一次重回或回流,接着就刷新浏览器频率
      • 隐藏和不可见的元素中,requestAnimationFrame将不会进行重绘和回流,这意味减少CPU、 GPU、内存的消耗

2、性能优化

  • 网络
    • DNS预解析  dns-prefetch,文档顶部插入DNS预解析,先查询IP,用的时候可以直接拿对应的IP
      • <link rel="dns-prefetch" href="https://www.baidu.com">
    • 缓存
      • 强缓存
        • expires   受限本地时间,如果修改本地时间,可能会造成缓存过期
        • cache-control   
          • no-catch
            • 使用缓存前,会向服务器发起请求,
            • 确认资源是否更改(Etag),返回304,表示可以使用缓存
            • 通常配合 private 属性, 表示内容只缓存到私有缓存中
          • no-store 绝对禁止缓存,所用内容都不被缓存
          • max-age=30 (1 属性)   30秒后过去
          • cache-control的优先级要高于expires
        • 协商缓存(缓存校验)1 客户端和服务端共同实现 last-modified 、Etag
          • 1
            • Last-Modified 服务器检查缓存时间与服务器资源最后修改的时间是否一致
              • 一致返回 304,表示可以使用浏览器缓存
              • 不一致返回200,表示使用最新的资源
            • Etag 标识符,弥补last-modified 缺陷,只要内容被修改,Etag就会改变。避免修改时间改变,内容没变情况,服务器对资源进行hash运算
          • 请求发送的时候会在缓存中寻找是否有对应的请求
          • 如果没有,则重新向服务器请求数据
          • 如果有,则有俩中情况
            • 如果有请求没有过期,则使用缓存结果
            • 如果请求过期,则带上缓存的标识,重新请求
              • 如果服务器返回304,表示请求资源没有更新,客户端则使用缓存
              • 如果服务器返回200,表示请求资源有更新,使用新的请求结果,并和请求标识重新保持到缓存中。
            • 频繁变动的资源,可以使用cache- control: no-cache;
            • 总结:
              • cache-control / expires 第一层,以绝对时间和相对时间校验资源
              • last-modified / etag 第二层,浏览器和服务器通讯,两者校验资源是否更新
              • 还有缓存 service Worker独立线程,离线缓存、消息推送、网络代理   push cache 属于http2内容
            • 响应文件采用GZIP压缩
            • 预加载  preload
              • <link rel="preload" href="">
              • 降低首屏的加载时间
            • 预渲染  prerend
              • <link rel="prerend" href="">
              • 提高页面的加载速度,但要确保用户一定会打开,比如首页
            • 懒执行
              • 让某些逻辑延迟到使用时候计算,用于首屏优化
            • 懒加载
              • 不关键的资源延后加载,可见区域,按需加载 observe,或者图片loading=“lazy”属性
              • 路由懒加载
                • const hello = () => import('./hello.vue');
                • conponent: relsove => require(['@/view/hello.vue'], relsove)
              • 组件懒加载
                • const hello = () => import(/* webpackChunkName: "hello" */, './hello.vue')
              • 打包后的懒加载文件,路由访问时,通过script标签引入对应的JS文件,prefetch 空闲加载css
            • 文件优化
              • 图片优化
                • 一些修饰性的小图标可以用css替代
                • 小图片可以转换成base64
                • 多个小图标可以合成一张雪碧图
                • 支持webp的可以使用webp
                • 根据不同屏幕选择不同尺寸的图片
              • CSS放在head中
              • JS放在body下方,避免堵塞HTML渲染
              • 在JS引用可以加async或 defer进行异步加载
                • defer 是有序加载和执行,等DOM加载完才执行
                • async是无序的,加载完即执行,不与DOM操作有关,一般用于第三方
              • CDN
                • 静态资源尽量使用CDN加载,因为浏览器对单个域名并发请求有上限。
                • 静态资源的CDN避免和主域名重名,因为相同域名在请求时会带上cookie参数,有安全风险。
              • webpack优化
                • 打包使用mode: production模式,productSourceMap: false; 这样会自动开启代码压缩
                • ES6模块开始tree-shaking,移除没有使用的代码
                • 打包时添加哈希值,实现浏览器缓存文件
                • 代码分割splitchunk.catchgroup,插件 splitCkunkPlugin
              • UI 框架组件,按需引入模块
              • SSR服务器渲染
                • 利用服务器优选渲染部分重要内容,其他内容可以懒加载,如js \ next.js
                • nuxtjs对应的是vue
                  • 基于js的通用应用框架
                  • SSR服务器渲染静态页面,在服务端生成HTML,然后发送给客户端
                  • 异步加载数据,中间件支持,布局支持
                  • 有利于SEO,加载速度快,自动配置路由
                  • 依赖node和npm npx
                  • 优势:
                    • 有利于SEO:不同爬虫工作原理只爬取源码,不执行网站的脚本,除了google的高级爬虫会执行脚本后渲染的页面。而单页面SPA大多数页面是JS动态生成,因此抓取的页面是空白页面
                    • 更有利于首屏渲染:因为客户端直接从服务端获取完整HTML内容并解析渲染,无需请求数据,等待响应渲染,而且SPA单页面应用首次加载打包后的文件比较大,会一个较长的等待时间。
                  • 缺点:
                    • 服务端压力大
                    • 学习成本相较高

3、安全

同源策略,协议、域名、端口号必须都相同,否则视为跨域,这是一种保护网页不受入侵的策略。

  • XSS
    • 跨站脚步攻击
    • 原理:
      • 攻击者在网站注入恶意的代码,利用恶意的代码对客户端进行篡改,从而在用户访问页面时,控制浏览器行为或获取用户的私密数据的一种攻击方式。
      • 共同行为:将一些私密数据,如cookie、session发给攻击者,或将受害者重定向到一个有攻击者控制的网站,从而在受害者机器是进行操作。
    • 方式
      • 存储型XSS
        • 将恶意代码保存到目标网站的服务器中,如博客、社交论坛等
        • 行为
          • 攻击者将一条包含XSS代码的留言后者其他数据提交到服务器
          • 当目标用户浏览时,XSS内容会从服务器解析之后加载出来。
          • 浏览器将恶意代码当着正常脚本来执行,从而获取浏览器所具有的权限命令
        • 反射行XSS
          • 通过引诱用户点击以一个恶意代码链接跳到目标网站来实现。
          • 行为
            • A给B发送一个恶意的URL
            • B点击URL跳转到具有恶意的网站
            • 网站在B的浏览器中执行JS,可以执行B具有的权限命令
          • 防御
            • 输入检查:检查输入不合法的特殊字符
            • 输出检查 :使用HTML、URL编码,转义输入的内容
            • 使用httpOnly:禁止页面的JS带有httpOnly属性的cookie,主要对抗XSS之后防止cookie被劫持,服务器向浏览器设置cookie,Set-Cookie: HttpOnly
            • 输入长度限制
            • 开启CSP(Content Security Policy)安全策略:指定可信的内容来源,如脚本、图片、style等远程资源,实质是白名单制度。
              • 在HTTPS头信息的Content-Security-Policy字段设置
              • 在网页中设置 <meta>标签 <meta http-equiv="Content-Security-Policy" content="">
            • CSRF
              • 跨站伪造请求:攻击者构造出一个后端请求地址,诱导用户点击或者通过某些途径自动发起请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户校验,冒充用户执行某些操作
              • 原理:
                • 受害者登录正常A站,并保留了登录凭证
                • 攻击者诱使受害者访问B站
                • B站向A站发起请求,浏览器默认会携带A点的Cookie
                • A站接收请求后会对其进行验证,且误认为是受害者发起的请求,同时以受害者身份执行对应的操作
              • 方式
                • GET类型
                  • 一般利用 img 标签发起,在受害者访问恶意网站时,浏览器会自动向src指向的地址发送请求
                • POST类型
                  • 通常是构造一个自动提交的表单在页面上,模拟用户去完成一次POST操作
                • 链接类型
                  • 通常是需要诱骗用户点击才会触发
                • 防御:
                  • 请求时附带验证信息,如验证码或token
                    • 客户端使用账号和密码登陆后,服务器接收到请求,验证账号密码,正确后会生成一个token,将token返回给客户端,客户端将token存在cookie或者localStorage中,以后每次请求都会带上token作为身份识别。如果放在session Storage中,那么每次关掉会话重新打开都要频繁认证。
                    • 一定要在https中加密传输token
                  • 设置 sameSite 属性,设置Cookie不随跨域请求发送
                  • 设置Referer,检验请求发送的域名是不是第三方网站发起的
                  • get请求不对数据进行修改
                  • 不让第三方网站访问到用户cookie
                  • 阻止第三方网站请求接口
                • 点击劫持
                  • 在页面中覆盖一层透明化的内容层,用底层的内容诱导用户去点击,实际上是触发透明层的点击事件,从而执行用户不知情的操作
                  • 特点
                    • 盗取用户资金
                    • 获取用户敏感信息
                    • 与XSS和CSRF相结合,诱骗用户点击恶意链接
                  • 防御
                    • 服务器可设置X-Frame-Options
                  • Session 和 Token:都是服务端存储,解决两个无状态的请求关联问题
                    • session 是空间换时间,存储在服务端,消耗服务端内存,对比session是否一致
                    • Token 是时间换空间,就是每次请求都要经过 token 算法,比较计算的token和携带的token是否一致

3、跨域

  • 协议、域名、端口号,只要有一个不同就是跨域
  • JSONP
    • 利用script标签没有跨域限制实现,但是它只能使用get请求
    • 非正式传输协议,允许用户传递一个callback给服务端,然后服务端返回数据时将这个JSON数据作为参数放在callback中,这样用户的就可以通过callback调用自定函数,使用传入的JSON数据。
    • 不是正真的AJAX
      • ajax的核心是通过XMLHttpRequest来实现
      • var xhr = new XMLHttpRequest();
         xhr.open('POST', '/server', true); // 异步
         xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
         xhr.send(data);
         xhr.onreadystatechange = function() {
              if (xhr.readyState === 4 && xhr.status === 200) {
                  ...      
              }
         }
      • jsonp的核心是调用服务器提供的js脚本
      • 只支持get,ajax支持get和post
  • 跨域资源共享CORSaccess-control-allow-origin: *,需要服务器配置运行跨域请求
  • domain= 'test.com'   表示子域名相通可以实现跨域
  • postMessage通常用于获取潜入页面的第三方页面数据
  • nginx代理跨域
  • // 发送消息
    
    window.parent.postMessage('message', 'https://test.com')
    
    // 接收信息
    
    var mc = new MessageChannel()
    
    mc.addEventListener('message', event => {
    
        var origin = event.origin || event.originalEvent.origin;
    
        if (origin === 'https://test.com') {
    
            ...    
    
        }
    
    })

4、浏览器渲染机制

  • 解析HTML文件并构建DOM树
  • 解析CSS并构建CSSOM树
  • 将DOM和CSSOM合并成渲染树(render tree)
  • 根据渲染树来布局,计算每个节点的位置
  • 调用GPU绘制,合成图层,显示在屏幕上
    • 构建CSSOM树会阻塞渲染,十分消耗性能,层级越多,执行速度越慢
    • CSSOM树构建会阻塞到JS执行和DOM渲染

5、Load和DOMContentLoaded

  • load事件触发代表页面中的DOM、CSS、JS、图片都加载完毕
  • DOMContentLoaded 事件触发代表初始的HTML被完全加载和解析,不需要等待CSS、JS、图片等

6、重绘与回流

  • 重绘是当节点需要更改外观而不影响布局,比如改变color,background-color
  • 回流是布局或者几何属性需要改变
    • 添加或删除可见的DOM
    • 改变元素的位置,尺寸
    • 页面初始化、浏览器窗口resize变化
    • 获取某些属性:Top、scrollTop、width、height
  • 回流必定重绘,重绘不一定发生回流,回流所需的成本比重绘要高
  • 避免回流和重绘:
    • 尽可能在DOM树的最末端改变class,这样对前面DOM不产生影响
    • 避免设置多层内联样式
    • 动画效果尽量应用到脱离文档元素,如absolute / fixed
    • 避免使用table,改动一点,全部要回流
    • 使用CSS3硬件加速,让transform、opacity、filters等动画效果不引起回流重绘
    • 避免用JS去直接修改样式,使用添加和删除 class
    • 避免频繁操作DOM,使用虚拟DOM
    • 元素的隐藏和现实可以使用display来实现

7、算法

  • 1+2+3+...+n  递归
  • // 求和
    
    function sum(n) {
    
        if (n === 1) return 1;
    
        return sum(n - 1) + n;
    
    }
    
    // 求阶乘
    
    function fn(n) {
    
        if (n === 1) return 1;
    
        return fn(n-1)*n
    
    }
    
    // 求斐波那契数列 1,1,2,3,5
    
    function fb(n) {
    
        if (n === 1 || n === 2) return 1;
    
        return fb(n-1) + fb(n-2);
    
    }
    
    // 递归处理导航菜单数据

  • 深度拷贝,递归
    • 递归:函数内部调调其本身,必须有return,否则死循环
    • 如下:
      // 深拷贝:JSON.parse(JSON.stringify(obj))
      
      // 浅拷贝:Object.assign(obj), 只拷贝指针,object只拷贝第一层
      
      var deepCopy = function(obj) {
      
          if (typeof obj !== 'object') return;
      
          var newObj = obj instanceof Array ? [] : {};
      
          for(var key in obj) {
      
              if (obj.hasOwnProperty(key)) {
      
                  newObj[key] = typeof obj[key] === 'object'
      
                  ? deepCopy(obj[key])
      
                  : obj[key];        
      
              }
      
          }
      
          return newObj;
      
      }

  • 多维数组转为一维数组
  • 如下:

    // [1, [2],[3, [4, 5]]] 转 [1,2,3,4,5]
    
    const flatten = (arr) => {
    
        let res = [];
    
        arr.forEach((item, i, curArr) => {
    
            if (Array.isArray(item)) {
    
                res = res.concat(flatten(item))        
    
            } else {
    
                res.push(item)        
    
            }
    
        })
    
        return res;
    
    }

  • 数组去重ld
  •  如下:

    // 1、Set  [...new Set(arr)]
    
    // 高效率 利用obj唯一key,Object.keys(obj)
    
    function unique(arr) {
    
        var result = {};
    
        for (var i = 0; i < arr.length; i++) {
    
            if (!result[arr[i]]) {
    
                result[arr[i]] = true;        
    
            }
    
        }
    
        return Object.keys(arr);
    
    }
    
    // 2、forEach + indexOf (缺点 arr.indexOf(NaN) === -1)
    
    // 3、filter + indexOf (缺点 arr.indexOf(NaN) === -1)
    
    arr.filter((val, index, item) => {
    
        return arr.indexOf(val) === index;  // indexOf返回第一个匹配元素的下标
    
    })
    
    // 4、reduce + includes
    
    arr.reduce((per, cur) => {
    
        return per.includes(cur) ? per : per.concat(cur); // concat可以并入非数组
    
    }, [])
    
    // 5、forEach + includes

8、闭包机制

  • 外部函数可以访问函数内部的变量,本质就是在一个函数内部创建另一个函数
    • 特点
      • 函数的嵌套函数,子函数的对象可以访问父函数的对象,反之不可以
      • 能够读取其他函数内部私有化变量,
      • 参数和变量不被垃圾回收机制回收
        • 垃圾回收机制:为了防止内存泄露,垃圾回收机制不断的寻找那些不再使用的变量,并释放它所指向的内存。
        • 解释:一个对象不被引用,或者两个对象相互引用,但不被第三个函数引用,这两个情况下的对象都会被垃圾回收机制回收
          • 标记清除:大部分浏览器使用这种方式
            • 当变量进入执行环境时,垃圾回收器会对该变量进行打标,当该变量离开环境时,则会再次打标,随之清除
          • 引用计数:低版本常常引起内存泄露
            • 追踪一个引用类型的引用次数,当一个变量赋值该引用类型时,引用次数加1,当该变量赋值其他值时,该引用类型减1,当引用次数为0,则对引用类型进行垃圾回收。
          • 好处:
            • 可以读取函数内部变量
            • 可以让这些变量的值始终保持在内存中,即缓存。
          • 缺点:
            • 因为函数内的变量无法被垃圾回收机制所回收,因此会消耗内存,如果变量很多,则有可能会造成内存泄露
          • 两种情况
            • 如果函数没有别外部变量引用,而直接执行,那么垃圾回收机制会回收变量
            • 如果函数被外部变量引用,那么垃圾回收机制不会回收闭包中的变量
              • 将变量赋值为 null 可消除占用内存
              • // 闭包的实际应用,私有变量始终保存在内存中,可以改变它的值,并不立即释放,因为内部变量赋值给了外部全局变量,外部全局变量不知道什么时候会被引用。
                
                function fun() {
                
                    var i = 0;
                
                    return function() {
                
                        console.log(i++);    
                
                    }
                
                }
                
                fun();   // 没有打印,因为返回的是函数,垃圾机制会将变量 i 会被回收
                
                fun()();   // 0,因为i++,先赋值再加, ++i,先加再赋值,i=1存在内存中
                
                fun()();   // 0,重新运行fun导致i重新赋值为0
                
                var f1 = fun(), f2 = fun();  // 先取出return的匿名函数,重新赋值i=0
                
                f1(); // 0,i++的原因,此时内存中 i = 1;
                
                f1(); // 1,此时没有重新运行fun,而是return的匿名函数,读取内存中的i
                
                f2(); // 0,f2是重新运行了fun导致i重新赋值为0

9、HTTP 状态码

  • 200 请求成功
  • 301 资源永久被转移到了其他URL
  • 302 临时转移
  • 304  客户端有缓存可以使用
  • 400 客户端请求的语法错误,无法理解
  • 401 请求要求用户的身份认证
  • 403 服务器理解客户端请求,但拒绝执行此请求
  • 404 请求资源不存在,找不到了
  • 500 内部服务器错误
  • 502 网关或代理服务器接收到无效响应
  • 503 超载或系统维护,服务器暂时无法处理请求

11、常见的内存泄露

  • 函数中的全局变量:每次执行该函数时都会生成该变量,并且不会随着函数执行结束后而释放
  • 未清除的定时器:它内部引用变量不会释放
  • 脱离DOM的元素引用:一个DOM容器删除之后,变量未设置null,则其内部的dom元素不会释放
  • 持续绑定的事件:函数中addEventListener绑定事件,函数执行多次,绑定便会产生多次,产生内存泄露
  • 闭包
  • log:console.log的对象是不会被垃圾回收

12、HTTP与HTTPS

  • http默认端口号:80/8080,是HTTP协议运行在TCP之上。所有传输内容都是明文,客户端与服务器端都无法验证对方的身份
  • https默认端口号:443,是HTTP运行在SSL之上,所有传输的内容都经过加密。
  • HTTP1、0和HTTP3.0的区别
    • 0
      • 线程阻塞,在同一时间,同一域名的请求有一定的数量限制,超过则会阻塞
    • 1 (目前最常用 TCP链接)
      • 缺陷:TCP 按顺序发送,排队堵塞
      • 改进:
        • 持久连接,建立TCP连接,需要加 Connection: keep-alive
        • 管道机制,一个TCP中客户端可以发送多个请求
        • 分块传输编码
        • 新增请求方式:Put、Delete、Options、connect、trace
      • 0 - 过渡协议
        • 特点:
          • 采用二进制格式而非文本格式,
          • 服务器推送
          • 完全多路复用,只需一个连接即可实现并行
          • 使用报头压缩,降低开销
        • 0
          • 彻底解决排队阻塞问题
          • 采用UDP协议,不需要3次握手和4次挥手,传输速度更快
          • TLS支持,加密性更好
          • QUIC协议自定义了连接机制和重传机制
          • 自定义流量控制
        • TCP/IP是一个四层协议系统,数据链路层、网络层、传输层、应用层
          • IP 为上层协议提供无状态、无连接、不可靠的服务。
            • 无状态:IP双方不同步传输数据行,数据包的传输和接受是相互独立
            • 无连接:IP双方不能长时间维持对方的任何信息,每次发送数据都要指明对方的IP地址
            • 不可靠:IP协议不能确保IP数据包准确的到达接受端。
          • TCP:面向连接、可靠的、面向字节流传输,三次握手,四次挥手,耗时长
          • UDP:无连接、不可靠、面向报文传输。
        • WebSocke:H5的一种新协议,允许服务端向客户端传递信息,实现双通信。
          • 建立在TCP协议之上,与http协议良好兼容
          • 数据比较轻量级、性能开销小,通讯高效
          • 可发送文本或二进制
          • 没有同源限制,可与任意服务器通信

13、优雅降级和渐进增强

  • 优雅降级:是从一个复杂的现状开始,试图减少用户体验,来兼容不同环境的正常运行
  • 渐进增强:是从一个基础的现状开始,逐步扩充功能,适应未来更新的需求。

14、typeof、instanceOf、constructer

  • typeof会返回一个变量的基本类型(null除外),不能准确的判断引用数据的类型(’object‘),除了function
  • instanceOf返回一个布尔值,可以准确的判断引用数据类型,但不能正确判断基础数据的类型
    • 原理:判断右边参数的原型(prototype)是否在左边参数(__proto__)的原型链上
    • isArray区别
      • prototype 也是Array   Array.isArray(Array.prototype)   // true    Array.prototype instanceof Array // false
      • isArray({__proto__: Array.prototype})   // false    {__proto__: Array.prototype} instanceof Array  // true
      • instanceof 不能跨iframe工作,而isArray可以
    • const a = {};   a instanceof Object;  // true
  • constructor
    • 除了undefined和null以外都能判断 , 比instanceof更为准确
    • const a = {};  a.constructor === Object;  // true
    • // instanceof 和 Array.isArray
      
      // instanceof 判断右边参数的原型(prototype)是否在左边参数(__proto__)的原型链上
      
      Array.isArray(Array.prototype) // true
      
      Array.prototype instanceof Array  // false
      
      
      
      
      const a = { __proto__: Array.prototype };
      
      Array.isArray(a);  // false;
      
      a instanceof Array; // true   a.__proto__ === Array.prototype;

15、GET和POST区别

  • get请求不安全,post安全
  • get请求数据有大小限制,受浏览器URL的长度限制,chrome最大长度8182byte,超过服务器返回414标识
  • get参数显示在URL中,容易被别人窃取,POST在请求体中
  • post需要设置请求体
  • get是从服务器请求数据,post是向服务器发送数据

16、箭头函数和普通函数

  • 普通函数
    • 可以通过bind、call、apply改变this方向
    • 可以使用new,因为有原型
      • 与构造函数的区别
        • 构造函数首字母大写
        • 构造函数必须要用new实例化,普通函数可以直接调用
        • 构造函数创建时,内部会创建一个新的对象,并返回这个对象
        • 构造函数内部this指向其实例,普通函数this执行调用的对象,没有则指向window
      • 箭头函数
        • 不可以使用new,因为箭头函数没有constructor
        • 不可以通过bind、call、apply改变this方向
        • 本身没有this,因为没有原型
        • 它的this是其包裹它的外部普通函数,如果没有则指向window,返回undefined
        • 如果包裹它的外部普通函数的this发生改变,那么箭头函数中的this也会发生改变
      • call、apply、bind的相同点和区别
        • 相同点
          • 都能改变this指向
          • 第一个参数就是this要指向的对象
          • 都可以传入参数
        • 不同点
          • call、bind的参数是依次传入,而apply只有两个参数,第二个参数是数组
          • call和apply是函数调用返回结果,而bind方法返回的仍是一个函数,需要再执行一次
        • 如果传入的第一个值是this,则表示预设初始参数
        • // call实现
          
          Function.prototype.call = function(context) {
          
              const ctx = context || window;
          
              ctx.fn = this;  // this相当于将Function的实例,即调用的函数,作为ctx的方法
          
              // 获取实参, 类数组转数组,从下标1开始去参数
          
              const args = Array.from(arguments).slice(1);
          
              // 调用ctx的实例,传入参数,如果没有则在ctx找
          
              const res = arguments.length > 1 ? ctx.fn(..args) : ctx.fn();
          
              // 删除该方法,防止污染
          
              delete cxt.func
          
              return res;
          
          }
          
          
          
          
          // apply实现
          
          Function.prototype.apply = function(context) {
          
              const ctx = context || window;
          
              ctx.fn = this;  // 绑定实例
          
              // 获取实参
          
              const args = arguments[1];  // argunments是获取不定的参数
          
              // ctx调用实参方法,传入参数
          
              const res = argunments.length > 1 ? ctx.fn(...args) : ctx.fn();
          
              // 删除方法
          
              delete cxt.func
          
              return res;  // 返回运行结果
          
          }
          
          
          
          
          // bind实现,注意返回的是函数
          
          Function.prototype.bind = function(context) {
          
              const fn = this;
          
              const ctx = context || window;
          
              const args = Array.from(arguments).slice(1);
          
              // Array.from对类数组或可迭代的对象新建一个浅拷贝的数组,arguments类数组对象
          
              return function proxy() {            
          
                  ctx.fn = fn;
          
                  const res = ctx.fn(...args);
          
                  delete ctx.fn;
          
                  return res;
          
              }
          
          }

17、同步和异步

  • 同步是阻塞模式,如果一个请求需要等待回调,那么后面代码会一直等待下去,知道返回结果
  • 异步是非阻塞模式,无需等前面代码回调,即可执行下去

18、事件循环机制,宏任务和微任务

  • JS运行过程中主要执行事件循环:同步任务和异步任务
    • 主程序从上而下执行同步任务
    • 异步任务会被放入异步任务队列中
    • 当同步任务执行完成后,才会去异步任务队列中执行异步事件
  • 同步任务 -》微任务 -》宏任务
  • 微任务:在DOM渲染之前触发
    • Promise 、 async/await、nextTick 、Object.observe
  • 宏任务:在DOM渲染之后触发
    • script标签内运行代码、DOM事件、AJAX、setTimeout、setInterval

19、Cookie、sessionStorage、localStorage、indexdb、Service Work

  • service work 是运行在浏览器后台的独立线程,一般用来实现缓存功能
  • 传输协议必须是HTTPS
  • service work的缓存与浏览器其他内建的缓存机制不同,他可以控制缓存文件、匹配缓存、读取缓存,并且缓存是连续性
  • 存储大小:cookie只有4kb,sessionStoarge和localStorage是5M
  • 有效期:
    • cookie可以设置有效期,超过有效期就会自动清除,如:标记用户与跟踪用户行为
      • 会话状态管理:如登录状态,购物车信息,
      • 个性化设置:如自定主体、设置
      • 浏览器行为跟踪:如历史脚印,关注的类目
    • sessionStorage是会话缓存,关闭选项卡或者关闭浏览器就会清除,如:敏感账号一次性登录
    • localStorage是永久存储,除非手动清除,如:大量商品数据
  • 存储位置:cookie不设置有效期,存储在内存中,设置有效期存储在硬盘中,Storage只存储在浏览器端
  • 作用域:
    • sessionStorage:同一个浏览器手动输入地址的新tab是不共享的,
    • cookie和LocalStorage同个浏览器同源页面是共享的
  • indexDB存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexDB
  • service worker 归功于PWA的流行
    • 是运行在浏览器后台的独立线程,一般用来实现缓存功能
    • 传输协议必须是HTTPS,本地也可以通过http://localhost跑起来
    • service work的缓存与浏览器其他内建的缓存机制不同,他可以控制缓存文件、匹配缓存、读取缓存,并且缓存是连续性

42、Worker 实现多线程

  • worker,它能向浏览器申请开辟一个线程来处理js,

一般用来优化UI展示、交互的任务,用来完成耗时操作,

如大量操作DOM,复杂的计算、大文件上传、主流程加载速度优化,

  • var work = new Worker('js文件的路径');
  • postMessage('hello')
  • onmessage = function (event) {}

20、async/await、Promise

  • async/await代码简洁,使异步代码看起来像同步
  • async/await和Promise都是非阻塞式
  • async/await是基于Promise实现,是解决地狱回调,async是Generator的语法糖,*转换async,yield转换await
    • Promise有三种状态(pending等待,fulfilled已完成,reject已拒绝),不可逆的
      • pending:不会触发then和catch
      • fulfilled:会触发后续的then
      • reject: 会触发catch
      • then正常返回resolve,报错则返回reject
      • catch正常返回resolve,报错则返回reject
      • promise 三个方法: all、any、race,将所有promise组成一个promise
        • all  只有所有promise都成功才算成功
        • any  只要有一个成功就算成功,除非全部拒绝
        • race  看第一个完成的promise的状态
      • 优点:
        • 解决地狱回调问题
        • 对象不受外界影响
        • 状态一旦发生改变就不能更改,不可逆
      • 缺点:
        • 一旦执行,不可终止
        • 内部报错,需要回调抛出,用try / catch 捕获

21、document.ready 和 document.onload

  • ready表示文件结构已经加载完毕(不包含图片),可以多次
  • onload表示页面包括图片在内的所有元素都加载完成,只能有一个,多个会覆盖

22、原生(内置)对象和宿主(浏览器)对象

  • 所有内置对象都是原生对象,Date 、Array、Object、RegExp、Number
  • 宿主对象是宿主环境,如浏览器的对象,Location、Navgator、 Document

23、New 一个对象的过程

  • 创建一个新对象,新对象的原型__proto__指向new的构造函数的原型prototype
  • 将this指向这个新对象,并执行构造函数的代码,为新对象添加属性
  • 最后 隐式 return this 返回新的对象,如果return其他结果,则返回其他
  • 对象创建的方法:
    • 字面量的方式创建 {}
    • 通过 new Object() 创建
    • 通过构造函数 new Person() 创建

24、原型和原型链

  • 原型
    • 每个构造函数都一个原型对象,实例化出来的对象都有一个原型,指向的是构造函数的原型对象,原型对象里面有个指针constructor,它指向构造函数。
    • 所有原型对象都是Object构造函数的实例,实例的原型(__proto__)都是指向Object的原型对象(prototype)
    • Object的原型对象(prototype)的原型(__proto__)是null
  • 原型链
    • 当实例化的对象访问一个属性时,首先会在该对象内部寻找,如果找不到,则会向其(__proto__)指向的原型(构造函数的原型对象)中寻找,如果还未找到,则继续向原型中__proto__指向的原型中寻找,直到找到或者null(prototype.__protot__)为止,这样形成的链式就是原型链
  • 原型作用:实现属性和方法的继承,共享数据,节约内存空间
  • 获取原型的方法
    • __proto__
    • getPrototypeOf()
    • prototype
    • function Foo(){}
      
      const foo = new Foo();
      
      foo.__proto__ === Foo.prototype
      
      Foo._proto__ === Function.prototype
      
      Foo.prototype.__proto__ === Object.prototype

25、for...in  for...of 和 object.keys

  • ..in 会遍历自身属性和继承的原型属性,使用hasOwnProperty可以判断自身属性
  • ..of ES6新增,遍历所有数据结构的统一方法,遍历数组,Set和Map、某些类似数组的对象,如arguments对象,DOM对象,Generator对象
  • keys 只遍历自身属性,不会遍历继承的原型属性

26、set 、 map 、object

  • Map是键值对,键和值可以是任何类型,object的键只能是String、number或symbol,Set是值的集合
  • Map可以通过get获取值,set设置值,size获取长度,..of遍历,Object可以通过属性获取值,通过遍历获取长度。
  • Set通过has来判断是否有值,且值是唯一性,用于去重
    • from(arr):可将一个类数组的对象或者可遍历对象转换成一个正真的数组
    • [...new Set(arr)]
  • Map可以作为存储数据

27、防抖和节流

  • 防抖:一段时间后执行,如果有重复触发,则重新计时
    • 场景:登陆按钮、窗口调整大小resize、输入框实时保存
  • 节流:一段时间内只执行一次,不论触发多少次
    • scroll滚动事件,一定时间内只执行一次
    • 浏览器播放时间,一定时间内读取一次后续数据

28、require 和 import

  • require 对应导出的方法是export,import对应的方法是export 、export default
  • require 对应是CommonJs的语法,commonjs是nodejs中的模块化规范,import是ES6的语法
  • require是动态加载,运行时加载模块的所有方法,import是静态加载,编译的时候调用,代码提升顶部
  • require 引入的是整个模块里面的对象,import按需加载模块中的对象
  • require 导出的是值的拷贝,import导出的是值的引用

export {} 对应 import {}

export default xx 对应 import xx

29、谈谈你对ES6的理解

  • 新增模版字符串
  • 箭头函数
  • ..of
    • .in 循环出来的是key,for...of 循环出来的是value,forEach 不能使用break、continue、return语句
  • arguments 指向不定参数和默认参数替代
  • 提供promise
  • 增加 let 和 const
  • 增加块级作用域
  • 新增API:from Array.map Array.reduce Objec.keys Object.vuales Object.assign
  • 引入module模块的概念

30、事件冒泡、事件捕获

  • 事件冒泡:事件按照从最特定的事件目标到最不特定的事件目标的顺序触发,
    • 一般都是把原本需要绑定到子元素上面的事件委托给父元素,让父元素去监听事件。
    • 事件委托:利用事件冒泡指定一个事件处理程序,来处理其内部的某一类型的所有事件。
    • 事件冒泡三个阶段:事件捕获、目标阶段、事件冒泡
  • 阻止事件冒泡
    • stopPropagation()
  • 事件捕获:事件从最不特定的事件目标到最特定的事件目标的顺序触发
  • 阻止事件默认
    • preventDefault()
  • 添加事件时用addEventListener(event, fn, useCapture),第三个参数时bool,用来设置事件时捕获时执行,还是事件冒泡时执行

30、H5新特性

  • 语义化标签
    • header、nav、footer、section、aside、article等
  • 增强型表单
    • type:number 、email、time、tel、data、color等
    • 元素:datalist、keygen、output
    • 属性:placeholder、required、min、max、multipe、autofocus、step
  • 新增标签 audio、video
  • canvas
  • 地理定位getCurrentPosition
  • 拖拽 drag
    • dragstart  开始拖拽被拖拽元素时触发, 作用被拖拽元素
    • drag  正被拖拽元素时触发, 作用被拖拽元素
    • dragend   被拖拽元素结束时触发,作用被拖拽元素
    • 通过dataTransfer.setData()   getData() 来传值。
    • dragenter  被拖拽元素移进入目标元素时触发, 作用目标元素
    • dragover 被拖拽元素在目标元素内移动时触发, 作用目标元素
    • dragleave 被拖拽元素移出目标元素时触发, 作用目标元素
    • drop  目标元素接受被拖拽元素时触发, 作用目标元素
  • 本地存储 sessionStorage 、localStorage
  • 新事件:onresize、ondrage、onscroll、onerror、onplay、onpause
  • webSocket
    • 单个TCP链接上进行全双工通讯的协议,
    • 下一代 H5通讯协议,持久化协议,实现服务器与客户端全双工通信,
    • 更好的节省服务器资源和宽带,打到实时通讯目的。
  • 块级元素和行内元素

31、JSON.stringify() 特性

  • 对 undefined、函数和symbol的值
    • 对象:stirngify({a: undefined})序列化时会忽略跳过
    • 数组:stirngify([undefined、Fn、symbol]) === null 序列化后变成 null
    • 单独:stirngify(undefined/Fn/symbol) === undefined 序列化后变成 undefined

32、数组方法

  • 改变数组:
    • push:从后面添加元素并返回新数组的长度
    • pop:从后面删除元素并返回删除的元素
    • shift:从前面删除元素并返回删除的元素
    • unshift:从前面添加元素并返回新数组的长度
    • splice(i, len, newVal, newVal1):删除或添加元素,i下标,len删除的长度,newVal是添加的参数,返回删除元素的数组,没有删除则返回空数组
    • sort:对数组进行排序,返回排序后的数组,注意数字都是转换字符,按位比较,而不是大小
      • 顺序,数字排序 -> 字母排序 -> null -> undefined
    • reverse:对数组进行反转,返回反转后的数组
  • 不改变数组:
    • slice(start, end):从下标start开始截取,到下标end前,不包括end,如果是负数,则表示从取最后几位,返回截取的数组
      • slice(-3)  截取最后三位
      • slice(-3, -1)  截取倒数第三和第二
    • join(undefined):将数组的元素取出来,按照传入的字符组合成字符串,返回组合的字符串
      • 如果传入空  或者 undefined,则默认逗号隔开
      • 如果数组中有undefined或者null,会被重置为空,但是间隔符号还在。
    • concat:合并数组,重复数据不覆盖,返回合并后的数组
    • indexof:读取元素下标,如果没有则返回-1
    • includes:判断数组是否有该元素,返回boolean值
    • forEach:遍历数组,执行函数,不能break、continue,可以if return
    • map:遍历数组,执行函数,返回新的数组
    • filter:遍历数组,最满足条件的元素进行重组,生成新的数组。
    • reduce:求和
    • every: 所以都满足才返回true
    • some: 一项满足就返回true
    • arr.reduce((pre, cur, index, arr) => {
      
          // pre表示上一个求和值,开始则表示传入的init
      
          // cur 当期要处理的元素,index表示当前元素的下标,arr表示原数组
      
      }, init)

33、数据类型

  • 基础数据类型:Number、String、Unll、Undefined、Boolean、Symbol、BigInt
    • Number(null) 返回 0,被定义了,但是空值
    • Number(undefined) 返回 NaN,未被定义
      • typeof NaN 是 number  typeof null === 'object'
        • 判断方法
          • typeof NaN === 'number' 且 isNaN判断
          • 特性,NaN !== NaN
          • is() 两个值是否相等,不会隐士转换,利用NaN特性,自身不全等自身
            • is(-0, +0);  // false
            • is(0, -0);   // false
            • is(0, +0);  // true
            • is(NaN, NaN);  // true
            • is(NaN, 0/0);  // true
          • 引用数据类型:Object(array,function、object、Date、regExp、Math)

34、v-html 和  @click、class不生效

  • @click改为onclick,将method里的点击事件赋值到window方法上
  • class不生效:可以说使用  /deep/  或 >>>  穿透,新建style,不含scoped

35、Vue 子与子传值

  • 使用bus
  • vuex
  • 通过父组件传递 $ref,storage 、provide / inject

36、nextTick使用场景

  • 在created操作dom,此时DOM并没有渲染
  • 某个操作改变数据,并改变dom

37、关于富文本图片放大

  • 使用v-html,点击事件@click,传入$event
  • 通过比较target.tagName === 'IMG'判断,然后将e.traget.src赋值给data,最后渲染出来

38、首屏白屏优化

  • 减少文件体积,HTML,CSS压缩
  • css放在头部,js放在body后,异步加载
  • 图片合成雪碧图,图片压缩,图片CDN加载,减小服务器并发
  • 懒加载,不可视区域不加载
  • 尽量减少异步数据容量
  • 使用本地缓存
  • 服务端渲染

39、ref作用,获取真实DOM

40、JS中获取位置间距

  • clientHeight  可见区域的高度,不包含滚动条和border
  • offsetHeight  可见区域的高度,包含滚动条和border
  • scrollHeight 整个文档高度,包含滚动隐藏的部分
  • clientTop  border的高度,一般是0
  • scrollTop 滚动隐藏的高度,相对于文档顶部的距离

41、输入一个URL到页面过程发生了什么

  • 首选在浏览器输入URL
  • 查找缓存,看看浏览器缓存-系统缓存-路由缓存中是否该地址资源
  • DNS解析,向DNS服务器发送请求,DNS服务器解析成IP,DNS基于UDP协议
  • 建立TCP连接
  • 发起HTTP请求:将请求报文作为三次握手第三次数据发送给服务器
  • 服务器发送响应的数据
  • 关闭TCP连接:四次挥手释放TCP
  • 浏览器渲染
    • 构建DOM树
    • 构建CSS规则树
    • 结合DOM树和CSS规则树,构建渲染树
    • 计算每个节点在页面的位置
    • 通过GPU进行渲染绘制

43、SEO优化

  • head中的title
  • js 服务端渲染
  • h1标签,只能存在一个
  • keywords 网页关键字,网页的关键字
  • description  告诉搜索引擎站点的主要内容
  • H5语义化标签: header、nav、aside、footer、section、article
  • 隐藏SEO关键字,网络爬虫识别文字,如:logo不用图标,而是用a标签的背景图,标签内SEO关键字,设置font-size: 0;
  • 集中权重,不重要的链接设置 rel="nofollow",让爬虫忽略跟踪。
  • 扁平化结果,尽量减少网站的结构层,目录结构不超过3层,有利爬取
  • 提高加载速度,一旦超时爬虫就放弃抓取
  • og:富媒体对象
    • og:title,og:type,og:url,image、og.site_name
    • 便于社交媒体分享抓取关键信息

44、工作中遇到什么问题(技术)

  • 跨域问题
  • 本地开发接口,本地代理 (proxy, tableproxy)
  • 资源未更新,加hash值,清缓存
  • 地狱回调,promise或async await
  • 数据更新不及时,nextTick
  • 首屏加载慢或白屏时间过长
  • 移动端bug调试,抓包工具whistle
  • 数据去重,Set
  • 多重嵌套表单数据校验
  • 浏览器兼容,样式兼容

45、看过那些书,推荐一些

  • JavaScript高级程序设计(红宝书)
  • JavaScript权威指南 (犀牛书)
  • 你不知道的JavaScript
  • JavaScript DOM编程艺术
  • 锋利的jQuery
  • 深入浅出js
  • js权威指南

46、如果学习一个新的框架要用多久

  • 如果只是拿来实现一些常用的功能的话,一天就可以了
  • 如果是掌握框架的每个要点,可能要4、5天

47、怎么实现0.5px边框

  • 使用伪元素,相对定位absolute,设置1pxborder,在缩小5,scale(0.5)
  • 使用border,渐变色,黑色渐变透明色,视觉效果

48、关注并想学习的框架

论坛 gitHub的issue 、stackoverflow、google、官方文档 、CSDN、MDN、codeProject

  • Vue3、vite、ts、小程序
  • Electron、Tauri 应用桌面端
  • Svelte 、solidjs,相对React、Vue
  • js,React服务器渲染框架
  • Remix,React服务器渲染框架
  • js,Vue服务器渲染框架

49、H5的兼容性问题

  • IOS端键盘收起来后页面不归位
    • 问题:输入内容,软键盘弹起,页面整体内容上移,但是收起键盘,页面内容不滑下
    • 分析:软键盘占位并没有随着收起而消失
    • 解决:在失去焦点时给了事件,重置滚到到当前的位置scrollTo(0, 100)
  • IOS端H5页面上下滑动时卡顿,页面缺失
    • 问题:IOS滑动到下一屏时会有时会出现卡顿,页面部分显示不全
    • 解决:*{ -webkit-overflow-scrolling: touch; },控制元素在移动设备是否有滚动回弹效果
  • IOS移动端click事件300ms的延迟
    • 解决:
      • js可以解决手机点击延迟
      • zepto的touch模块
      • tap事件
      • ontouchstart事件
    • IOS端绑定click事件到非button元素上,不触发事件
      • 给元素添加样式: cursor: pointer;

50、计算页面白屏事件

在header中和body后打印一个时间,两者相减即可

51、rem计算原理

  • 将屏幕的宽度分为10等分,每一等分即为1rem,整个屏幕即为10rem
  • rem以 HTML 中的font-size为准,1rem = fontSize px
  • window.resize = function() {
    
        var width = document.doucmentElement.clientWidth || document.body.clientWidth;
    
        document.documentElement.style.fontSize = width / 10 + 'px';
    
    }

52、H5的混合开发项目:H5与原生的通信技术  jsbridge

53、CSS布局:table布局、float布局、flxe布局、响应式布局、grid布局

  • 静态布局
  • 流式布局(栅栏、百分比、vw、vh):宽高随着屏幕大小等比例缩放
  • 自适应布局(@media):不同尺寸屏幕布局会改变,但元素大小不会变
  • 响应式布局(@media 和 流式布局):不同尺寸屏幕布局和元素大小都会改变
  • 弹性布局(rem / em)

1、屏幕自适应 大屏:1200px   pad:1023px-768px,手机 :480px - 767px

改变一般是导航栏、头部和尾部,中间主体采用flex响应式布局

  • CSS @media
    • @media screen and (max-width: 980px) { }
  • 在head 中使用 link 链接,media属性用于查询
    • <link rel="stylesheet" type="text/css" href="moxie.css" media="screen and (max-width=980px)" />
  • 在vue css中 @import 导入css文件
    • @import url('css/moxie.css') screen and (max-width: 980px);

2、Css优先级:important > 内联样式 > ID选择器 》 类、属性、伪类(:hover,:actived)选择器 > 标签 、伪元素(::before, ::after)选择器 > * 通配符

3、Css sprites: 为了应对多次http请求造成服务器并发运行负担,因此将多个小图片合成一张雪碧图,极好的减少了网页的http请求,从而大大的提高页面的性能。然后通过background-image/repeate/position来实现图标渲染

54、IE和标准和模型的区别

  • IE:width包括 content、border和padding
  • 标准:width只有 content

55、垂直居中布局

  • position:absolute + transform:translate(-50%, -50%);
  • position: absolute  +  margin;
  • display: flex; jusitify-content: center; align-items: center;
  • gird布局
  • table-cell

56、Git和SVN区别

  • Git 分布式管理,由本地仓库,可离线本提交保存
    • 可以独立开发自己的需求
    • 不需要等待其他人的项目,可以发布上线
  • SVN 集中式管理,没有本地仓库,必须联网才能提交
    • 版本控制系统管理所有文件的修订版本,所有协同开发都能获取到最新的代码,必须在规定的时间保质保量的完成所有需求才能统一发布上线。
    • 管理员可以管理所有开发人员的权限
    • 后提交代码可能会与前面其他人提交的代码有冲突,需要解决
    • 如果服务器出现故障,所有开发者都不能提交和拉取

57、说说JS实现继承的几种方法

  • 原型继承
    • 继承父类的实例对象:
      • prototype = new Animal();
      • constructor重新指回 Cart :prototype.constructor = Cart;
    • 直接继承父类原型:
      • prototype = Animal.prototype;
      • constructor重新指回 Cart :prototype.constructor = Cart;
    • 经典继承
      • 构造函数改变this:在其中的一个函数中,执行 apply/call(this, arguments)
    • 组合继承方式(原型继承 + 经典继承)
      • Cat 函数中执行 Animal.apply(this, arguments);
        
        Cat.prototype = new Animal();
        
        Cat.prototype.constructor = Cart

    • 寄生组合方式
      • Cat 函数中执行 Animal.apply(this, arguments);
        
        Cat.prototype = Object.create(Animal.prototype);
        
        Cat.prototype.constructor = Cart

58、异步图片加载的方法

loadImageAsync('./loading.jpg').then(image => document.body.appendChild(image));

function loadImageAsync(url) {

    return new Promise(function(res, rej) {

        const image = new Image();

        image.src = url;

        image.onload = function() {

            res(image)        

        }   

        image.onerror = function() {

            rej(new Error('没有加载图片'))        

        }

    })

}

59、BFC盒子模型

  • 看作隔离了的独立容器,容器里面的元素不会在布局上影响外部元素
  • 如:overflow,position, dispaly: inline-block、flex

60、对象创建的方式

  • 字面量: var obj = { a: 1 };
  • Object构造函数: var obj = new Object();
  • 工厂模式:函数封装字面量,传参,然后return对象
  • 构造函数:new 构造函数来生成对象
    • new 方法:先建一个新对象,然后将新对象的__proto__指向构造函数的原型prototype
    • 将 this 指向新对象,然后执行构造函数代码,为新对象添加属性
    • 最后隐式 return this 对象

62、[] == ![]   true

  • ![] 转成boolean
  • == 类型转换number ,boolean转换0
  • []转换number 也是 0

63、可视化拖拽布局思路

  • 首先中间是个布局主体,它的数据是一个数组componentData,这个数组是来渲染主体
  • 其次要封装一些常用组件,每个组件都要有唯一的标识符ID
  • 遍历这些组件,将其渲染到左侧的组件库列表中,添加draggeable 属性, 提供拖拽功能
  • 将组件拖入主体,通过  dragstart、drop 事件 getData('id') 获取对应的组件,并渲染到主体容器中。
    • 通过遍历 componentData 循环 <component :is="name" />
  • 再通过右侧该组件的相关的配置项进行数据配置
  • 保持配置的数据后,该数据会被写入 componentData 对应的该组件数据中
  • 其他组件同样操作,组成完整的 componentData ,遍历渲染出整个页面。

1、主体容器中移动组件

    • 容器设置relative,组件设置 absolute
    • 根据 mousedown 记录当前坐标,mousemove 每次鼠标移动,计算xy距离进行改变组件位置,mouseup 鼠标抬起,结束移动

2、组件排序和删除

    • 排序可以通过拖拽的位置来判断
      • 记录每个组件垂直中心距离文档顶部高度,集合一个数组;
      • 然后拖拽组件所距离文档顶部高度,和数组中数据比较,处于哪两个之间
      • 最后获取第一个下标,然后通 splice 将该组件的数据删除、插入重新排序
    • 删除可以通过 当前组件的ID,遍历整个模板的数据数组进行删除即可

难点:

1、怎么将每个组装的组件渲染出来

    • 使用 动态组件 <template :is="tplname" :data="data">

2.、组件排序拖拽怎么实现

    • 记录每个组件垂直中心距离文档顶部高度,集合一个数组;
    • 然后拖拽组件所距离文档顶部高度,和数组中数据比较,处于哪两个之间
    • 最后获取第一个下标,然后通 splice 将该组件的数据删除、插入重新排序

3、吸附功能怎么做

    • 假设一个组件位置已经确定好了,然后移动另一个组件
    • 移动组件的时候,动态获取该组件的(x/y offset())坐标和宽高
    • 判断移动组件在目标组件的方位,方法:目标组件坐标 + 目标组件宽/高 > 移动组件对应的坐标
    • 这差值如果 小于3 就可以吸附,将左侧总和值赋值给右边值

4、组件库数量过多,打包后文件很大

    • 按需加载: import 引入当下需要渲染的组件

5、新老版本组件同类型同名问题

    • 在组件数据中加上 版本号字段
    • 循环遍历 import 的路径带上 版本号标识 作为路径加载组件

64、平时遇到的问题

  • 1、秒杀活动怎么处理高并发和数据请求失败
    • 页面数据缓存
    • 静态页面处理,放到CDN上,动态数据通过ajax请求
    • 安全性能,防刷、限流
  • 2、页面不可视区域接口提前加载
    • observe 监听
  • 3、数据量大的渲染操作
    • 将数据进行分割,按需渲染

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值