部分面试题

1、介绍影响深刻的项目,担任角色,遇到的问题,怎么解决的

2、js数据类型,区分基本类型和引用类型的方法

基本数据类型:Number 、 String、Boolean 、 Null 、undefined
引用数据类型是保存在堆内存中的对象Object: Array 、 Function 、Date 、RegExp 、Error 自定义封装的类等。

判断 
1.typeof : 用于判断基本数据类型;引用数据类型不能被准确检测(除了Function),其他都返回object字符串。

2.instanceof: 只有引用数据类型(Function 、Array、Object)被精确判断,其他基本数据类型不能被判断。 instanceof是测试一个对象在原型链中是否存在一个构造函数的prototype属性,即判断对象是否是某一数据类型的实例。

3.constructor
  constructor属性指向的是创建这个对象的构造函数,
  console.log(([]).constructor) // ƒ Array() { [native code] }
  console.log(([]).constructor === Array) //true

4.Object.prototype.toString.call()
   可以判断基本数据类型和引用数据类型 返回字符串'[object 具体类型]'
  console.log(Object.prototype.toString.call(false)) //'[object Boolean]'
            

3、元素不可见方式和使用场景


display: nonevisibility: hiddenopacity: 0
是否占有空间×
是否可以进行DOM事件监听××
是否可以点击××
是否可以被子元素继承×
子元素能否通过改变属性值来改变继承自父亲的隐藏状态××

1. display: none

  • **DOM 结构:**浏览器不会渲染 display 属性为 none 的元素,会让元素完全从渲染树中消失,渲染的时候不占据任何空间;
  • **事件监听:**无法进行 DOM 事件监听,不能点击;
  • **性能:**修改元素会造成文档重绘重排( repaint 与reflow ),读屏器不会读取display: none元素内容,性能消耗较大;
  • **继承:**是非继承属性,由于元素从渲染树消失,造成子孙节点消失,即使修改子孙节点属性子孙节点也无法显示,毕竟子类也不会被渲染;
  • **属性值从 none 改为非 none 时的效果:**显示出原来这里不存在的结构;
  • **transition:**transition 不支持 display。
  • **用途:**虽然会造成大量的重绘重排,但是也是对复杂结构减少重绘重排常用的办法。常常将一个“会被大量修改结构和视觉效果”的结构先赋予 display:none 属性,让其在 DOM 树中消失,然后进行 DOM 操作,操作完再让其显示。更多有关重绘重排的方法可以参考这篇文章:前端性能优化之重排和重绘

2. visibility: hidden

  • **DOM 结构:**不会让元素从渲染树消失,渲染元素继续占据空间,但是内容不可见;
  • **事件监听:**无法进行 DOM 事件监听,不能点击;
  • **性能:**修改元素只会造成本元素的重绘(repaint),是重绘操作,比重排操作性能高一些,性能消耗较少;读屏器读取visibility: hidden元素内容;
  • **继承:**是继承属性,子孙节点消失是由于继承了visibility: hidden,子元素可以通过设置 visibility: visible 来取消隐藏;
  • **属性值从 hidden 改为 visible 时的效果:**显示不会导致页面结构发生变动,不会撑开;
  • **transition:**transition 支持 visibility,visibility 会立即显示,隐藏时会延时。

3. opacity: 0

  • **DOM 结构:**透明度为 100%,不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见;
  • **事件监听:**可以进行 DOM 事件监听,可以点击;
  • 性能:提升为合成层,是重建图层,不和动画属性一起则不会产生repaint(不脱离文档流,不会触发重绘),性能消耗较少;
  • **继承:**会被子元素继承,且子元素并不能通过 opacity: 1 来取消隐藏;
  • **场景:**可以跟transition搭配;
  • **transition:**transition 支持 opacity,opacity 可以延时显示和隐藏。

打个比方display: none: 从这个世界消失了, 不存在了; opacity: 0: 视觉上隐身了, 看不见, 可以触摸得到; visibility: hidden: 视觉和物理上都隐身了, 看不见也摸不到, 但是存在的;

附加题:CSS 隐藏页面上的一个元素有哪几种方法?

  1. display:none,visibility:hiden,opacity:0 这三种;
  2. 设置 fixed 并设置足够大负距离的 left top 使其“隐藏”;
  3. 用层叠关系 z-index 把元素叠在最底下使其“隐藏”;
  4. 用 text-indent:-9999px 使其文字隐藏。

3、浏览器存储方法

特性cookielocaStoragesessionStorageindexedDB
数据生命周期expires设置过期时间除非主动清理,否则一直存在页面关闭就清理除非主动清理,否则一直存在
存储大小4K5M5M5M
与服务器通信每次请求都会携带在header中,消耗性能不参与不参与不参与

cookie :如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。

document.cookie 

localStorage :以键值对(Key-Value)的方式存储,键值对总是以字符串的形式存储,永久存储,永不失效,除非手动删除

sessionStorage :以键值对(Key-Value)的方式存储, 临时会话,受同源策略限制

window.localStorage.setItem(key,value);  // 设置

IndexedDB 就是浏览器提供的本地数据库, 内部采用对象仓库(object store)存放数据,它可以被网页脚本创建和操作,IndexedDB 允许储存大量数据,提供查找接口,还能建立索引

4、简述Vue的生命周期

常用的有8个(生命周期不仅仅是8个),都是成对出现。分别是

beforeCreate阶段、created阶段;

beforeMount阶段、mounted阶段;

beforeUpdate阶段、updated阶段;

beforeDestroy阶段、destroyed阶段;

简述react的生命周期

componentWillMount() – 在渲染之前执行,在客户端和服务器端都会执行。

componentDidMount() – 仅在第一次渲染后在客户端执行。

componentWillReceiveProps() – 当从父类接收到 props 并且在调用另一个渲染器之前调用。

shouldComponentUpdate() – 根据特定条件返回 true 或 false。如果你希望更新组件,请返回true 否则返回 false。默认情况下,它返回 false。

componentWillUpdate() – 在 DOM 中进行渲染之前调用。

componentDidUpdate() – 在渲染发生后立即调用。

componentWillUnmount() – 从 DOM 卸载组件后调用。用于清理内存空间。

5、Vue父子传值

父传子 props
子传父 $emit
Vuex
v-mode
eventBus

6、数组方法

push 向数组的末尾添加新内容

pop 删除数组的最后一项

unshift 向数组首位添加新内容

shift 删除数组的第一项

slice :截取数组

splice :对数组进行增删改

join 用指定的分隔符将数组每一项拼接为字符串

concat : 拼接数组

index:检测当前值在数组中第一次出现的位置索引

lastIndexOf: 检测当前值在数组中最后一次出现的位置索引

includes :判断一个数组是否包含一个指定的值,返回布尔值

sort:排序

let ary11 = [32,44,23,54,90,12,9]; 

  ary11.sort(function(a,b){        
       // return a-b;  // 结果[9, 12, 23, 32, 44, 54, 90]
       return b-a;  // 结果[90, 54, 44, 32, 23, 12, 9]  
  })  

   console.log(ary11);

reverse :倒序

forEach: 遍历

map: 遍历数组,需要返回return。

7、什么是跨域?怎么解决?

当协议,主机,和端口号有一个不同时,就是跨域。

跨域解决方案

1)(后端)服务器配置CORS(跨域资源共享)

2) (后端)node.js或nginx,反向代理,把跨域改造成同域

3)(前端)将JSON升级成JSONP,在JSON的基础上,利用script 标签可以跨域的特性,加上头设置

8、ES6新特性

箭头函数和普通函数

//普通函数可以有匿名函数,也可以有具名函数。
// 具名函数
function func(){
}
// 匿名函数
let func=function(){    
}     

// 箭头函数全都是匿名函数
let func=()=>{
}

(1).箭头函数是匿名函数,普通函数可以有匿名函数,也可以有具名函数;
(2).箭头函数没有自己的this,this指向外层作用域;
(3).箭头函数箭头函数不能用于构造函数;
(4).箭头函数没有arguments对象

(5).箭头函数不能Generator函数。
(6).箭头函数不具有prototype原型对象。
(7).箭头函数不具有super。
(8).箭头函数不具有new.target。

9、HTTP状态码

1XX : 信息提示 这些状态代码表示临时的响应。

2xx - 成功 这类状态代码表明服务器成功地接受了客户端请求

3xx - 重定向 客户端浏览器必须采取更多操作来实现请求。

4xx - 客户端错误。

5xx - 服务器错误

10、二级事件监听 addEventListener()

  • 参数:三个, 要处理的事件名,作为事件处理程序的函数 、一个布尔值。
  • true,表示在捕获阶段调用事件处理程序;false,表示在冒泡阶段调用事件处理程序。
var btn= document.getElementById("clickBtn");
btn.addEventListener("click",function(){
      alert(this.id);
},false);

js事件处理机制: js中事件的发生包括捕获和冒泡两个阶段,两个阶段的传播顺序为 捕获:从最外边父元素节点传递至发生事件的元素节点,即由外到内; 冒泡:从发生事件的元素节点传递至最外边父元素节点,即由内到外;

11、使用什么代码管理工具,代码怎么管理

使用git (分布式版本控制系统)

常用命令

初始化

git init
git clone [url]

拷贝 一个git 仓库到本地 (可选https 或 SSH)

代码提交

git add .  添加到暂存区
git commit -m ""  提交到本地仓库
git push   上传远程代码并合并

查看、回退

git log 查看提交记录

gitstatus 查看查看仓库状态

git reset  回退版本(不同分支开发)
git revert 回退版本(多人使用同一分支开发)

拉取、合并、推送

git pull     下载远程代码并合并 ,相当于fetch加merge
git fetch    从远程获取代码库,但不合并
git merge    合并代码(以合并时间为准)
git rebase   合并代码(把你最新的修改放在最前)

12、flx布局

解决某元素的子元素的布局方式,为布局提供最大的灵活性

  1. 开启弹性布局:display: flex;

  2. 设置属性

    1. flex-direction – 设置 主轴方向

      • row - 横向为主轴 X (默认)
      • column - 纵向为主轴 Y
    2. justify-content – 设置主轴对齐方式

      • justify-content: flex-start; – 位于容器的开头
      • justify-content: flex-end; – 位于容器的末尾
      • justify-content: center; – 水平居中(常用)
      • justify-content: space-between; – 两边贴边,中间留空 (常用)
      • justify-content: space-around; – 平分剩余空间
    3. align-items – 设置侧轴对齐方式

      • align-items: stretchl; – 默认值,拉伸填满
      • align-items: center; – 设置垂直居中(常用)
      • align-items: flex-start; – – 位于容器的开头
      • align-items: flex-end; – 位于容器的末尾
      • align-items: baselinel; – 位于容器基线上
    4. align-content – 设置多行时的对齐方式

      • align-content: stretch; – 默认值,拉伸自适应

      • align-content: flex-start; – 位于容器的开头

      • align-content: flex-end; – 位于容器的末尾

      • align-content: center; – 水平垂直居中 (常用)

      • align-content: space-between; – 两边贴边,中间留空 (常用)

      • align-content: space-around; – 平分剩余空间

    5. flex-wrap – 设置是否换行

      • nowrap – 不换行
      • wrap – 换行
    6. order: num; – 设置排列顺序,默认为 0

    7. align-self – 设置元素自身,在侧轴上的对齐方式。脱离原来的排序限制。

    8. flex: num; – 设置子元素占用空间份数

1、重绘、回流(也叫重排)

DOM性能 浏览器的性能大部分都是被这两个问题所消耗
重绘:
DOM树没有元素增加或删除,只是样式的改变,针对浏览器对某一元素进行单独的渲染,这个过程就叫做重绘
重排:
DOM树中的元素被增加或者删除,导致浏览器需要重新的去渲染整个DOM树,回流比重绘更消耗性能,发生回流必定重绘,重绘不一定会导致回流。

因为重绘和回流的存在导致真实DOM性能不佳,所以VUE和recat还有angular等框架增加了虚拟DOM技术,就是为了减少DOM的重绘和重排从而减少浏览器性能消耗,这就是虚拟DOM的好处。

重排(重构/回流/reflow):当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为重排(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

重绘和重排的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。

触发重排的条件:任何页面布局和几何属性的改变都会触发重排,比如:
  1、页面渲染初始化;(无法避免)

2、添加或删除可见的DOM元素;

3、元素位置的改变,或者使用动画;

4、元素尺寸的改变——大小,外边距,边框;

5、浏览器窗口尺寸的变化(resize事件发生时);

6、填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变;

7、读取某些元素属性:(offsetLeft/Top/Height/Width, clientTop/Left/Width/Height, scrollTop/Left/Width/Height, width/height, getComputedStyle(), currentStyle(IE) )

当需要对DOM元素进行一系列操作,可以通过以下步骤来减少重绘和重排的次数:
1、使元素脱离文档流(重排)
2、对应用多重改变
3、把元素带回文档(重排)

有三种基本方法可以使DOM脱离文档流:
1、隐藏元素,应用修改,重新显示
2、使用文档片段在当前DOM之外构建一个子树,再把它拷贝回文档(推荐)
3、将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换原始元素。

2.Vue的双向数据绑定,Model如何改变View ,View如何改变Model

实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅
实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。

3、移动端页面怎么适配,有遇过rem不能解决的问题吗?最后怎么解决的

例如百分比,rem适配,栅格布局,vh/vw等等

IE9以下有些不兼容rem,rem 是根据 html 标签的根字体大小来计算客户端需要适配的大小

在微信、QQ 浏览器中内容变大问题

一下根字节的大小,重新计算了样式的宽高。

确实是因为我设置的根节点太小

( 1 :10(750px 的设计稿)在移动端差不多 html 的 font-size: 5px;)

导致有些浏览器识别不了那么小的字体就用浏览器默认最小字体代替导致的样式错乱

解决

  html {
       font-size: calc(100vw / 750 * 100);
      }

1rem=100px=13.333333vw

4、前端网络安全问题

  1. XSS 跨脚本攻击

  2. CSRF 跨站点请求伪造

  3. iframe 滥用

  4. 恶意第三方库,如之前 npm 的包如:event-stream 被爆出恶意攻击数字货币;

  5. HTTPS ,黑客将HTTPS降为HTTP

  6. 避免重要用户信息存在浏览器缓存中

XSS攻击包括

服务端:

  • 存储型攻击:比如说存储用户信息:评论区,
  • 反射型攻击:比如说URL传参,进行网页刷新跳转

JS自身漏洞

  • DOM型攻击:前端JS取出并执行恶意代码

如何预防?

  1. 输入验证:比如一些常见的数字、URL、电话号码、邮箱地址等等做校验判断
  2. 对HTML代码进行充分转译 使用正则匹配,替换
  3. DOM型,规范JS代码,如尽量使用setAttribute()、.textContent代替innerHTML、document.write()
  4. 严格的CSP,即建立白名单,告诉浏览器,哪些外部资源是可以加载并且执行的,如设置meta标签的http-equiv属性(文件头)
  5. 开启浏览器XSS防御:Http Only cookie,禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
  6. 验证码

CSRF

称为“跨站请求伪造”,攻击者诱导受害者进入第三方网站

攻击类型

\1. 自动发起 Get 请求

\2. 自动发起 POST 请求

\3. 引诱用户点击链接

如何·预防

  1. 针对实际情况将一些关键的 Cookie 设置为 Strict 或者 Lax 模式,这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。
  2. 验证请求的来源站点,通过Header中的Origin Header 、Referer Header 确定,但不同浏览器可能会有不一样的实现,不能完全保证
  3. CSRF Token:在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。将CSRF Token输出到页面中(通常保存在Session中),页面提交的请求携带这个Token,服务器验证Token是否 正确

iframe

一个内联框架被用来在当前 HTML 文档中嵌入另一个文档。

  • i)嵌入第三方 iframe 会有很多不可控的问题,同时当第三方 iframe 出现问题或是被劫持之后,也会诱发安全性问题
  • ii)点击劫持
    • 攻击者将目标网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,诱导用户点击。
  • iii)禁止自己的 iframe 中的链接外部网站的JS

预防方案:

  • i)为 iframe 设置 sandbox 属性,通过它可以对iframe的行为进行各种限制,充分实现“最小权限“原则
  • ii)服务端设置 X-Frame-Options Header头,拒绝页面被嵌套,X-Frame-Options 是HTTP 响应头中用来告诉浏览器一个页面是否可以嵌入
  • iii)设置 CSP 即 Content-Security-Policy 请求头
  • iv)减少对 iframe 的使用

5、浏览器缓存策略

浏览器缓存过程:

1.浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器请求下载下来,并把response header及请求的返回时间一并缓存(要与Cache-control和Expires做对比)

2.下一次加载资源的时候,先比较当前时间和上一次返回200时的时间差,如果没有超过Cache-control的max—age,则没有过期直接命中强缓存,不发请求直接从本地缓存读取该文件(如果浏览器不支持http1.1 , 则使用Expires判断是否过期)

3.如果过期,服务器则查看header里面的 If-None-Match和If-Modified-Since;

4.服务器优先根据Etag的值(服务器返回资源后时设置的哈希值If-None-Match)判断被请求的文件有没有做修改,下一次加载请求是Etag值一致则没有修改,命中协商缓存,返回304,如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回200

5.如果服务器收到的请求没有Etag值,则将If-Modified-Since和被请求文件的最后修改时间作对比,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200;

使用协商缓存是为了进一步降低数据传输量,如果数据没有改变,就不必要再传一遍

浏览器每次发起请求时,先在本地缓存中查找结果以及缓存标识,根据缓存标识来判断是否使用本地缓存。如果缓存有效,则使 用本地缓存;否则,则向服务器发起请求并携带缓存标识。根据是否需向服务器发起HTTP请求,将缓存过程划分为两个部分: 强制缓存和协商缓存,强缓优先于协商缓存。

  • 强缓存,服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用本地缓存,不在时间内,执行比较缓存策略。Cache-control是一个相对时间(优先级高),Expires是一个绝对时间
  • 协商缓存,让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,将缓存信息中的Etag和Last-Modified(字段告知客户端,资源最后一次被修改的时间),每次请求都会去服务器进行校验。服务器对比最后修改时间如果相同则返回304,浏览器直接使用缓存。不同返回200以及资源内容。****

6、讲一讲MVVM吗?

MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。

8、js如何把一个字符串的大小写取反

let str = '124BBBBBgsdff'
str = str.replace(/[a-zA-Z]/g, content => {
    console.log(content)
    // content : 每一次正则匹配的结果  BBBBBgsdff
    return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase()
})
console.log(str)

9、单页面多页面开发

单页面:单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。

多页面:每一次页面跳转的时候,后台服务器都会给返回一个新的html文档,这种类型的网站也就是多页网站,也叫做多页应用

单页面:

优点:

-减小服务器压力。

-增强用户体验,增加app的使用流畅性

单页应用没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象。

-单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。

-良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化

缺点:-首次加载耗时比较多。(解决办法:可以采用基于HTTP Chunk 的首屏数据渐进式预加载方案,)

多页面:

优点:给用户提供一个完美的视觉方向,重点是没有很多的菜单,简洁明了的SEO管理。由于可以针对每页一个关键字优化应用程序

缺点:后端和移动客户端不能同时使用,前端和后端开发紧密结合。开发变得相当复杂。开发人员需要为客户端和服务器端使用框架。这导致应用程序开发时间更长。

SEO:可以查询到该网站搜索各大引擎的信息,可以一目了然的看到当前该域名的相关信息,及时调整网页优化等

12、setTimeout、promise、async/await 的区别

setTimeout属性宏任务,Promise里面的then方法属于微任务,Async/Await中await语法后面紧跟的表达式是同步的,但接下来的代码是异步的,属于微任务。

宏任务优先级:
主代码块 > setImmediate > MessageChannel > setTimeout / setInterval

微任务优先级
微任务microtask:process.nextTick > Promise = MutationObserver

setTimeout
console.log("script start");
   setTimeout(function () {
       console.log('setTimeout')
   }, 0);
console.log('script end');

输出script start -> script end -> set

Promise:
Promise本身是同步的,但在执行resolve或者rejects时是异步的,即then方法是异步的。

   console.log("script start");
    let promise1 = new Promise(function(resolve) {
        console.log("promise1");
        resolve();
        console.log("promise1 end");
    }).then(function(){
        console.log('promise2');
    })
setTimeout(function () {
    console.log('setTimeout');
}, 0)
console.log('script end');

输出顺序: script start -> promise1 -> promise1 end -> script end -> promise2 ->setTimeout

async/awaitasync function async1(){
        console.log('async1 start');
        await async2();
        console.log('async1 end')
    }
    async function async2(){
        console.log('async2')
    }
console.log('script start');
async1();
console.log('script end')

输出顺序:script start -> async1 start -> async2 -> script end -> async1 end

async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。

await后面跟一个表达式,async方法执行时,遇到await后会立即执行表达式,然后把表达式后边的代码放到微任务队列中,让出执行栈让同步代码先执行;

setTimeout

 console.log("script start");
    setTimeout(function () {
        console.log('setTimeout')
    }, 0);
    console.log('script end');

输出顺序: script start -> script end -> setTimeout

13、什么是防抖和节流?有什么区别?如何实现?

/** 防抖:
 * 应用场景:当用户进行了某个行为(例如点击)之后。不希望每次行为都会触发方法,而是行为做出后,一段时间内没有再次重复行为,
 * 才给用户响应
 * 实现原理 : 每次触发事件时设置一个延时调用方法,并且取消之前的延时调用方法。(每次触发事件时都取消之前的延时调用方法)
 *  @params fun 传入的防抖函数(callback) delay 等待时间
 *  */
const debounce = (fun, delay = 500) => {
    let timer = null //设定一个定时器
    return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fun.apply(this, args)
        }, delay)
    }
}
/** 节流
 *  应用场景:用户进行高频事件触发(滚动),但在限制在n秒内只会执行一次。
 *  实现原理: 每次触发时间的时候,判断当前是否存在等待执行的延时函数
 * @params fun 传入的防抖函数(callback) delay 等待时间
 * */

const throttle = (fun, delay = 1000) => {
    let flag = true;
    return function (...args) {
        if (!flag) return;
        flag = false
        setTimeout(() => {
            fun.apply(this, args)
            flag = true
        }, delay)
    }
}

14、call、aplay 和 bind 三者之间的区别?

重点:箭头函数,不能改变this指向,只有普通function函数,能改变this指向

  • call方法与apply方法, 传参方法不一样
  • apply传入的参数是包含多个参数的数组
  • call传入的参数是若干个参数列表
  • bind方法会创建一个新的函数,当被调用的时候,将其this关键字设置为提供的值,我们必须手动去调用

call apply 都是立即执行函数
参数1,都是改变的this指向,其他参数,是原始函数的形参(可以有,也可以没有)

call方法是通过其他多个参数来实现:

语法: 函数.call(参数1,其他参数…可以是多个或者没有 )

apply方法是通过一个数组参数,来实现

语法: 函数.apply(参数1,参数2) 只有两个参数

15、Vue路由跳转方式 push 、go、router-link、replace

this.$router.push() (函数里面调用)

1.  不带参数
 
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
 
2. query传参 
 
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
 
// html 取参  $route.query.id
// script 取参  this.$route.query.id
 
3. params传参
 
this.$router.push({name:'home',params: {id:'1'}})  // 只能用 name
 
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
 
// html 取参  $route.params.id
// script 取参  this.$route.params.id
 
4. query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
 
params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失

this.$router.replace() (用法同上,push)

router-link (声明式路由)

1. 不带参数
 
<router-link :to="{name:'home'}"> 
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name  
// 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
 
2.带参数
 
<router-link :to="{name:'home', params: {id:1}}">  
 
// params传参数 (类似post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id" 
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留

this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数

16、简述javascript原型、原型链?有什么特点?

原型:每一个构造函数都有一个prototype属性指向一个对象,这个对象就是构造函数实例的原型

原型链:每一个实例都有一个__proto__属性执行原型对象,来获取原型对象上的属性和方法,原型对象也有一个__proto

属性指向另外一个原型对象,以此类推,直到原型链的最终端null为止,这个串成链的过程就是原型链

特点:实现继承 一个对象可以拿到另一个对象上的属性和方法

构造函数都有一个prototype属性指向原型对象

原型对象都有一个consttuctor属性指向构造函数

构造函数new实例化实例对象

实例对象上有__proto属性指向原型

17、js事件处理程序

流程包括 事件源,事件,事件处理程序

  • 事件源:网页元素,如按钮、输入框
  • 事件,事件为浏览器或用户的行为。如鼠标点击,屏幕滚动、选中数输入框等
  • 事件处理程序则是响应某个事件的函数。如,onClick,onLoad等。

事件处理程序分为HTML处理程序,DOM0级事件处理程序,DOM2级事件处理程序

  1. HTML处理程序

直接在HTML中添加事件处理程序,弊端:代码耦合性太强,不利于项目维护,且在不同浏览器会出现差异。

		<button type="button" onclick="alert('消息框');" onmouseout="console.log('控制台')">Html事件处理程序</button>
		<button type="button" onclick="fun1();" onmouseout="console.log('控制台')">Html事件处理程序</button>	

		<script type="text/javascript">
			//Html事件处理程序
			function fun1(){
				alert("消息框");
			}
			
			//加载事件 load   当页面中元素和引入的资源加载完毕之后执行里面的代码
			window.onload = function(){
					alert("加载完成");
			}
		</script>
  1. DOM0级处理程序

使用JavaScript指定事件处理程序,将一个函数赋值给一个事件处理程序属性,弊端:不能给同一个元素绑定同一个事件多次

        <button type="button" id="but1">DOM0级事件处理程序</button>
		<script type="text/javascript">

			//获取元素
			var but1 = document.getElementById("but1");
			// 2.给元素绑定事件
			but1.onclick = function(){
				console.log('DOM0级事件处理程序1');
			}
			//添加的第二的Click事件起作用,第一个被覆盖
			but1.onclick = function(){
				console.log('DOM0级事件处理程序2');
			}
		</script>
  1. DOM2级处理程序

定义了addEventListener()和removeEventListener()方法来定义和删除事件处理程序。

<button type="button" id="but2">DOM2级事件处理程序</button>
		<button type="button" id="but3">删除DOM2级事件处理程序</button>
		<script type="text/javascript">
			//DOM2级事件处理程序
			//获取元素
			var but2 = document.getElementById("but2");
			var but3 = document.getElementById("but3");
			
			but2.addEventListener("click",function(){
				console.log("DOM2级事件处理程序1");
			});
			but2.addEventListener("click",function(){
				console.log("DOM2级事件处理程序2");
			});
			
			function fun3(){
				console.log("有方法名的处理程序");
			}
			but2.addEventListener('mouseover',fun3);
				
			//移除but2的某个事件
			but3.addEventListener("click",function(){
				but2.removeEventListener('mouseover',fun3);
			});
		</script>

跨浏览器的事件处理程序

 <button id="myBtn">点击我</button>

//此代码可以兼容所有浏览器
    //addEventListener attachEvent
    var EventUtil = {
        addHandler:function(element,type,handler){
            //绑定事件
            //chrome,firefox.IE9等, addEventListener
            //IE8及IE8以下的浏览器,attachEvent
            if(element.addEventListener){
                element.addEventListener(type,handler,false);
            }else if(element.attachEvent){
                element.attachEvent("on"+type,handler);
            }else{
                element["on"+type] = null
            }
        }// removeHandler:function(element,type,handler){
        //     //移除事件
        //     //chrome,firefox.IE9等, removeEventListener
        //     //IE8及IE8以下的浏览器,detachEvent
        //     if(element.removeEventListener){
        //         element.removeEventListener(type,handler,false);
        //     }else if(element.detachEvent){
        //         element.detachEvent("on"+type,handler);
        //     }else{
        //         element["on"+type] = null
        //     }
        // }
	
    }
    
    var btn = document.getElementById("myBtn");
    var handler = function(){
        alert("Clicked");
    }
    EventUtil.addHandler(btn,"click",handler);  //添加事件
    // EventUtil.removeHandler(btn,"click",handler); //移除事件

Promise状态完成后不会再改变

then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。
then方法的特点
返回一个新的Promise实例,并接收两个参数onResolved(fulfilled状态的回调);onRejected(rejected状态的回调,该参数可选)

const p = new Promise(function(resolve,reject){
  resolve('success');
});

p.then(function(value){
  console.log(value);
});
console.log('first');
//输出结果
// first
// success

Promise 应用场景 (https://www.php.cn/js-tutorial-451746.html)

1:多个请求合并在一起发

具体描述:一个页面,有多个请求,我们需求所有的请求都返回数据后再一起处理渲染

如果发多个的话,每个请求的loading状态要单独设置,使用Promise.all 汇总请求结果,从开始到结束,我们只设置一个 loading 即可。

2:合并请求结果并处理错误

描述:我们需求单独处理一个请求的数据渲染和错误处理逻辑,有多个请求,我们就需要在多个地方写

3:验证多个请求结果是否都是满足条件

描述:在一个微信小程序项目中,做一个表单的输入内容安全验证,调用的是云函数写的方法,表单有多7个字段需要验证,都是调用的一个 内容安全校验接口,全部验证通过则 可以 进行正常的提交

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值