金蝶云之家前端面经

目录

 

1、vue router路由钩子

完整的导航解析流程

2、浏览器强弱缓存

强缓存

弱缓存

3、v-show 是display:none // display opacity visibility

4、简单请求和复杂请求

5、http2

6、vuex可以直接更改state吗

7、权限路由

8、vue生命周期

9、双向绑定原理

10、实现跨域

11、同源策略

12、自适应和响应式的区别

13、em和rem

14、cookie不设置有效期多久过期

cookie的属性:

跨域解决方案

15、浏览器存储方法 localstorage、sessionstorage、

16、h5语义化优点

17、get和post的区别

18、懒加载原理实现方法

19、前端如何让页面渲染更快

一、减少请求资源大小或者次数 

二、代码优化相关

20、dom事件流三个阶段,怎么阻止冒泡

21、重绘回流

区别:

22、display visibility opacity

23、css水平垂直居中的方法

24、清除浮动的方法

25、css的两种盒模型

26、深拷贝和浅拷贝的区别、怎么实现深拷贝

27、js new的内部原理

32、js事件循环

33、宏任务和微任务有哪些

34、闭包、闭包缺点

35、call、apply、bind区别

36、js 基本类型和引用类型有哪些、区别

37、url到显示页面发生了什么

38、http在哪层?七层协议

39、常用http请求有哪些、get和post的区别

42、es5模拟块级作用域(闭包)


1、vue router路由钩子

vue router路由钩子,导航守卫。vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。

记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

路由钩子函数有三种:

            1:全局钩子: beforeEach、 afterEach

            2:单个路由里面的钩子:  beforeEnter、 beforeLeave

            3:组件路由:beforeRouteEnter、 beforeRouteUpdate、 beforeRouteLeave

 

(1)全局前置守卫 router.beforeEach()

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto proprouter.push 中的选项。

    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

(2)全局解析守卫 router.beforeResolve

在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

 

(3)全局后置钩子 router.afterEach

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:这些守卫与全局前置守卫的方法参数是一样的。

 

(4)组件内的守卫

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

 

 

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用离开守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

 

2、浏览器强弱缓存

浏览器向服务器请求某一资源时,会先判断本地有无该资源缓存,如果已有缓存,则获取该资源缓存的 header 信息,根据 header 中的 Control 和 Expires (即强缓存)来判断是否过期。这一时刻是没有向服务器发出请求的。

若显示已过期,浏览器会向服务器发送请求,通过 header 中的 Etag 和 Last-Modified(协商缓存)让服务器验证。若不需更新资源,返回状态码 304;若需要更新,则返回最新资源和状态码 200
 

浏览器缓存主要分为强缓存(也称本地缓存)和协商缓存(也称弱缓存)。

强缓存

 http1.1http1.0
强缓存

Cache-Control

强缓存利用的是max-age的值来实现缓存资源的最大生命周期,单位是秒。

Expires

它的值是一个绝对时间的GMT格式的时间字符串,代表资源失效时间。

协商缓存

Etag/If None Match

当资源被缓存时,服务器返回的 header 上有 Etag。

当资源文件向服务器确认缓存是否可用时,会向服务器发送一个 request header 带有 If-None-Match 字段,值为当前文件的 Etag。服务器根据浏览器上送的If-None-Match 值来判断是否命中缓存。

Last Modify/If Modify Since

浏览器第一次请求一个资源的时候,response header 会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。
 

弱缓存

Last-Modify/If-Modify-Since

Last-Modify(实体首部)/If-Modify-Since(请求首部)是 http1.0 的规范,格式:Last-Modify: Fri, 19 Apr 2019 01:34:53 GMT

浏览器第一次请求一个资源的时候,response header 会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。

如果命中缓存,返回304,则不会返回资源内容,并且不会返回 Last-Modify。

Etag和If-None-Match

Etag(响应首部)/If-None-Match(请求首部)是 http1.1 的规范,返回的是一个校验码,保证每一个资源是唯一的,格式: Etag:22FAA065-2664-4197-9C5E-C92EA03D0A16。

当资源被缓存时,服务器返回的 header 上有 Etag。当资源文件向服务器确认缓存是否可用时,会向服务器发送一个 request header 带有 If-None-Match 字段,值为当前文件的 Etag。服务器根据浏览器上送的If-None-Match 值来判断是否命中缓存。

与 Last-Modified 不一样的是,当命中缓存,服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

重点是,Etag 的优先级高于 Last-Modify,同时存在则优先判断 Etag,再判断 Last-Modify ,最后才决定是否返回304
 

 

3、v-show 是display:none // display opacity visibility

相同点:v-if与v-show都可以动态控制dom元素显示隐藏

不同点:v-if显示隐藏是将dom元素整个添加或删除(比如div会被删掉),而v-show隐藏则是为该元素添加css--display:none,dom元素还在。

需要注意的是,当一个元素默认在css中加了display:none属性,这时通过if-show修改为true是无法让元素显示的。原因是显示隐藏切换,只是会修改element style为display:""或者display:none,并不会覆盖掉或修改已存在的css属性。

详细区别:

1.手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐;

2.编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;

3.编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;

4.性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

5.使用场景:v-if适合运营条件不大可能改变;v-show适合频繁切换。

 

1.display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;

visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;

2.使用visibility:hidden比display:none性能上要好,

display:none切换显示时,页面产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流),

而visibility切换是否显示时则不会引起回流。

3.opacity: 0 是透明度为0

具体来说应该是: 

1 opacity=0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,
那么点击该区域,也能触发点击事件的

2 visibility=hidden,该元素隐藏起来了,但不会改变页面布局,
但是不会触发该元素已经绑定的事件

3 display=none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样,但是dom元素还在

 

4、简单请求和复杂请求

跨域资源共享(简称cors,后面使用简称)来解决跨域问题。会用到的两种请求。

1. 简单请求:

满足一下两个条件的请求。

(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-I
  • D
  • Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

 

2. 复杂请求:

非简单请求就是复杂请求。

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

预检请求为OPTIONS请求,用于向服务器请求权限信息的。

预检请求被成功响应后,才会发出真实请求,携带真实数据。

axios 都是复杂请求,ajax 可以是简单请求

 

5、http2

HTTP2.0和HTTP1.X相比的新特性

  • 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

  • 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

  • header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

  • 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

 

6、vuex可以直接更改state吗

       不通过mutation,而直接修改state修改确实生效了。这样子多人协作岂不是很容易出问题。对于这个问题,在创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,vue就会 throw error。

7、权限路由

全局路由守卫拦截然后vuex存在localstorage里判断

8、vue生命周期

9、双向绑定原理

10、实现跨域

1、 通过jsonp跨域

通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。


2、 document.domain + iframe跨域

此方案仅限主域相同,子域不同的跨域应用场景。

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

(1)父窗口(http://www.demo.com/a.html)

<iframe id="iframe" src="http://child.demo.com/b.html"></iframe>
<script>
    document.domain = 'demo.com';
    var user = 'admin';
</script>

(2)子窗口:(http://child.demo.com/b.html)

<script>
    document.domain = 'demo.com';
    // 获取父窗口中变量
    alert('get js data from parent ---> ' + window.parent.user);
</script>

3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域

11、同源策略

  源是协议、域名和端口号。若地址里面的协议、域名和端口号均相同则属于同源。

       域名和对应的IP之间请求算跨域。

  同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

  • 不受同源策略限制的
  1. 页面中的链接重定向以及表单提交是不会受到同源策略限制的。
  2. 跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。

      JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题,比如a标签、script标签、甚至form标签(可以直接跨域发送数据并接收数据)等。

同源策略限制以下几种行为:

1、Cookie、LocalStorage 和 IndexDB 无法读取
2、 DOM 和 Js对象无法获得
3、 AJAX 请求不能发送

 

12、自适应和响应式的区别

1.什么是响应式布局

响应式布局就是实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。换句话说就是一个网站能够兼容多个终端,而不是为了每一个终端做一个特定的版本。

2.什么是自适应式布局:

自适应布局就是指能忘了使网页自适应的显示在不同大小终端设备上的新网页设计方式及技术,它需要开发多套界面来适应不同的终端。

3.区别

(1)响应式布局通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容。

自适应布局通过检测视口分辨率,来判断当前访问的设备是:pc端、平板、手机,从而请求服务层,返回不同的页面。

(2)自适应布局需要开发多套界面,而响应式布局只需要开发一套界面就可以了。

(3)自适应(媒体查询)对页面做的屏幕适配是在一定范围:比如pc端一般要大于1024像素,手机端要小于768像素。

而响应式布局是一套页面全部适应。

(4)自适应布局如果屏幕太小会发生内容过于拥挤。而响应式布局正是为了解决这个问题而衍生出的概念,它可以自动识别屏幕宽度并做出相应调整的网页设计。

总之,响应式布局还是要比自适应布局要好一点,但是自适应布局更加贴切实际,因为你只需要考虑几种状态就可以了而不是像响应式布局需要考虑非常多状态。所以的说无论哪种设计都有它们各自的特点,我们要根据项目的需求来选择适合的布局方式。

自适应对差别大的更加友好,在某些范围内可以响应式。

 

13、em和rem

在css中单位长度用的最多的是px、em、rem,这三个的区别是:

  px是固定的像素,一旦设置了就无法因为适应页面大小而改变。

  em和rem相对于px更具有灵活性,他们是相对长度单位,意思是长度不是定死了的,更适用于响应式布局。

       对于em和rem的区别一句话概括:em相对于父元素,rem相对于根元素。

rem中的r意思是root(根源),这也就不难理解了。

em:

  • 子元素字体大小的em是相对于父元素字体大小(如果没有就是浏览器默认字体大小)
  • 元素的width/height/padding/margin用em的话是相对于该元素的font-size

浏览器字体大小有两个需要注意的地方,有时候会碰到兼容性的问题。
第一,是浏览器默认的字体大小是16px,所以重置css的时候将字体大小默认改为10px是这样改的:

html,body {font-size: 62.5%;}

后面设置字体大小rem,em都依据body的字体大小计算比较方便。

 

第二、chrome的字体最小为12px 设置成10px 显示还是12px

顺便解决chrome字体最小为12px的方法用css3

     .small-font{
            font-size: 12px;
            -webkit-transform-origin-x: 0;
            -webkit-transform: scale(0.90);

        }

  利用css3的缩放,其最终大小就是:12px * 0.9(缩放比例) = 10.8px;

  居然行得通。但回头一想,这么写的话,IE7 IE8会不会不兼容,还是12px呢?不出所料,果然不兼容。此时,又回头一想,要不再加个样式font-size?试了一下,果然兼容谷歌,IE7,IE8,代码如下:

         .small-font{    

     font-size:12px; 
            -webkit-transform-origin-x: 0;
            -webkit-transform: scale(0.90);
        }


        .smallsize-font {
     font-size:10.8px;

        }

  <p style="color: #FF0000;" class="small-font smallsize-font">温馨提示:</p>

 

14、cookie不设置有效期多久过期

 

设置Cookie的失效时间:

如果Cookie没有设置expires属性(默认-1?),那么 cookie 的生命周期只是在当前的会话中,

关闭浏览器意味着这次会话的结束,此时 cookie 随之失效。

cookie.Expires   =   DataTime.MaxValue   ;//永不过期

cookie的属性:

name字段为一个cookie的名称。

value字段为一个cookie的值。

domain字段为可以访问此cookie的域名。无法设置除当前域名或者其父域名之外的其他domain,

如在www.wo.cao.baidu.com  域名下只能设置 cao.baidu.com,baidu.com

不能设置 da.jia.wo.cao.baidu.com的cookie。

domain属性可以使多个web服务器共享cookie。domain属性的默认值是创建cookie的网页所在服务器的主机名。不能将一个cookie的域设置成服务器所在的域之外的域。
例如让位于order.example.com的服务器能够读取catalog.example.com设置的cookie值。如果 catalog.example.com的页面创建的cookie把自己的path属性设置为“/”,把domain属性设置成 “.example.com”,那么所有位于catalog.example.com的网页和所有位于orlders.example.com的网页,以 及位于example.com域的其他服务器上的网页都可以访问这个cookie。

跨域解决方案

1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域

path字段为可以访问此cookie的页面路径。 比如domain是abc.com,path是/test,那么只有/test路径下的页面可以读取此cookie。

expires/Max-Age 字段为此cookie超时时间。若设置其值为一个时间,那么当到达此时间后,此cookie失效。不设置的话默认值是Session,意思是cookie会和session一起失效。当浏览器关闭(不是浏览器标签页,而是整个浏览器) 后,此cookie失效。

Expires指定一个绝对的过期时间(GMT格式),这么做会导致至少2个问题:(绝对时间)
1)客户端和服务器时间不同步导致Expires的配置出现问题;
2)很容易在配置后忘记具体的过期时间,导致过期来临出现浪涌现象;

max-age 指定的是从文档被访问后的存活时间(秒),这个时间是个相对值(比如:3600s),相对的是文档第一次被请求时服务器记录的Request_time(请求时间)(相对时间)

 

Size字段 此cookie大小。(4kb)

http字段  cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie。

那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性。

secure 字段 设置是否只能通过https协议来传递此条cookie


 

15、浏览器存储方法 localstorage、sessionstorage、

16、h5语义化优点

语义化优点:

  • 易于用户阅读,样式丢失的时候能让页面呈现清晰的结构
  • 有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重
  • (seo:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名
  • 方便其他设备解析,如盲人阅读器根据语义渲染网页
  • 有利于开发和维护,语义化更具可读性,代码更好维护,与CSS3关系更和谐。

 

17、get和post的区别

get参数通过url传递,post放在request body中。

get请求在url中传递的参数是有长度限制的,而post没有。

get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。

get请求只能进行url编码,而post支持多种编码方式

get请求会浏览器主动cache,而post支持多种编码方式。

get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。

GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

GET产生一个TCP数据包;POST产生两个TCP数据包。

 

18、懒加载原理实现方法

19、前端如何让页面渲染更快

一、减少请求资源大小或者次数 

1、尽量和并和压缩css和js文件。(将css文件和并为一个。将js合并为一个)
  原因:主要是为了减少http请求次数以及减少请求资源的大小
  打包工具:
  webpack
  gulp
  grunt
.  ....
2、尽量所使用的字体图标或者SVG图标来代替传统png图
  因为字体图标或者SVG是矢量图,代码编写出来的,方大不会变形,而且渲染速度快

3、采用图片的懒加载(延迟加载)
  目的为了,减少页面第一次加载过程中http的请求次数
  具体步骤:
    1、页面开始加载时不去发送http请求,而是放置一张占位图
    2、当页面加载完时,并且图片在可视区域再去请求加载图片信息

4、能用css做的效果,不要用js做,能用原生js做的,不要轻易去使用第三方插件。
  避免引入第三方大量的库。而自己却只是用里面的一个小功能

5、使用雪碧图或者是说图片精灵
  把所有相对较小的资源图片,绘制在一张大图上,只需要将大图下载下来,然后利用
  图片定位来讲小图展现在页面中(background-position:百分比,数值)

6、减少对cookie的使用(最主要的就是减少本地cookie存储内容的大小),因为客户端操作cookie的时候,这些信息总是在客户端和服务端传递。如果上设置不当,每次发送

一个请求将会携带cookie

7、前端与后端进行数据交互时,对于多项数据尽可能基于json格式来进行传送。相对于使用xml
  来说传输有这个优势
  目的:是数据处理方便,资源偏小

8、前端与后端协商,合理使用keep-alive

9、前端与服务器协商,使用响应资源的压缩

10、避免使用iframe
  不仅不好管控样式,而且相当于在本页面又嵌套其他页面,消耗性能会更大。因为还回去加载这个嵌套页面的资源

11、在基于ajax的get请求进行数据交互的时候,根据需求可以让其产生缓存(注意:这个
缓存不是我们常看到的304状态码,去浏览器本地取数据),这样在下一次从相同地址获取是数据
时,取得就是上一次缓存的数据。(注意:很少使用,一般都会清空。根据需求来做)

二、代码优化相关

1、在js中尽量减少闭包的使用
  原因:使用闭包后,闭包所在的上下文不会被释放

2、减少对DOM操作,主要是减少DOM的重绘与回流(重排)
  关于重排(回流)的分离读写:如果需要设置多个样式,把设置样式全放在一起设置,不要一条一条的设置。使用文档碎片或者字符串拼接做数据绑定(DOM的动态创建)

3、在js中避免嵌套循环和"死循环"(一旦遇到死循环,浏览器就会直接卡掉)

4、把css放在body上,把js放在body下面
  让其先加载css(注意:这里关于优化没有多大关系)

5、减少css表达式的使用

6、css选择器解析规则所示从右往左解析的。减少元素标签作为对后一个选择对象

7、尽量将一个动画元素单独设置为一个图层(避免重绘或者回流的大小)
  注意:图层不要过多设置,否则不但效果没有达到反而更差了

8、在js封装过程中,尽量做到低耦合高内聚。减少页面的冗余代码

9、css中设置定位后,最好使用z-index改变盒子的层级,让盒子不在相同的平面上

10、css导入的时候尽量减少@import导入式,因为@import是同步操作,只有把对应的样式导入后,才会继续向下加兹安,而link是异步的操作

11、使用window.requestAnimationFrame(js的帧动画)代替传统的定时器动画
  如果想使用每隔一段时间执行动画,应该避免使用setInterval,尽量使用setTimeout
  代替setInterval定时器。因为setInterval定时器存在弊端:可能造成两个动画间隔时间
  缩短

12、尽量减少使用递归。避免死递归
  解决:建议使用尾递归

13、基于script标签下载js文件时,可以使用defer或者async来异步加载

14、在事件绑定中,尽可能使用事件委托,减少循环给DOM元素绑定事件处理函数。

15、在js封装过程中,尽量做到低耦合高内聚。减少页面的冗余代码

16、减少Flash的使用

三、存储

1、结合后端,利用浏览器的缓存技术,做一些缓存(让后端返回304,告诉浏览器去本地拉取数据)。(注意:也有弊端)可以让一些不太会改变的静态资源做缓存。比如:一些图片,js,cs

2、利用h5的新特性(localStorage、sessionStorage)做一些简单数据的存储,
  避免向后台请求数据或者说在离线状态下做一些数据展示。

四、其他优化

1、避免使用iframe不仅不好管控样式,而且相当于在本页面又嵌套其他页面,消耗性能会更大。因为还回去加载这个嵌套页面的资源

2、页面中的是数据获取采用异步编程和延迟分批加载,使用异步加载是数据主要是为了避免浏览器失去响应。如果你使用同步,加载数据很大并且很慢
  那么,页面会在一段时间内处于阻塞状态。目的:为了解决请求数据不耽搁渲染,提高页面的
  渲染效率。解决方法:需要动态绑定的是数据区域先隐藏,等数据返回并且绑定后在让其显示
  延迟分批加载类似图片懒加载。减少第一次页面加载时候的http请求次数

3、页面中出现音视频标签,我们不让页面加载的时候去加载这些资源(否则第一次加载会很慢)
  解决方法:只需要将音视频的preload=none即可。
  目的:为了等待页面加载完成时,并且音视频要播放的时候去加兹安音视频资源

4、尽量将一个动画元素单独设置为一个图层(避免重绘或者回流的大小)
  注意:图层不要过多设置,否则不但效果没有达到反而更差了

 

20、dom事件流三个阶段,怎么阻止冒泡

事件流描述的是从页面接收事件的顺序。

IE提出是事件流是事件冒泡流,Netscape Communicator提出的是事件捕获流。

IE事件冒泡流:

点击了div那么

div-> body -> html -> document(ie9、firefox、chrome、safari会冒泡至window)

事件捕获则相反。在事件到达预定目标之前捕获他。

 

dom2级事件规定的事件流包括三个阶段:

事件捕获阶段、处于目标阶段、事件冒泡阶段。

 

事件冒泡过程,是可以被阻止的。防止事件冒泡而带来不必要的错误和困扰。
这个方法就是:stopPropagation()

阻止事件冒泡:w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

取消默认事件:w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;

原生js取消事件冒泡

    try{
        e.stopPropagation();//非IE浏览器
    }
    catch(e){
        window.event.cancelBubble = true;//IE浏览器
    }    

原生js阻止默认事件

if ( e && e.preventDefault ) {
            e.preventDefault()//非IE浏览器
} else { window.event.returnValue = false; } //IE浏览器

 

vue.js取消事件冒泡

<div @click.stop="doSomething($event)">vue取消事件冒泡</div>

vue.js阻止默认事件

<div @click.prevent="doSomething($event)">vue阻止默认事件</div>

在Vue中,由于事件捕获和冒泡的存在,当点击某个元素时会引发其父元素(父父元素、父父父元素…)的点击事件发生,使得点击某个元素时达不到想要的效果。.self修饰符可以很好的解决这一情况,.self修饰符只有在点击事件绑定的元素当前被点击元素一致时才触发点击事件。

.stop 是阻止冒泡行为,不让当前元素的事件继续往外触发,如阻止点击div内部事件,触发div事件
.prevent 是阻止事件本身行为,如阻止超链接的点击跳转,form表单的点击提交
.self 是只有是自己触发的自己才会执行,如果接受到内部的冒泡事件传递信号触发,会忽略掉这个信号
.capture 是改变js默认的事件机制,默认是冒泡,capture功能是将冒泡改为倾听模式
.once 是将事件设置为只执行一次,如 .click.prevent.once 代表只阻止事件的默认行为一次,当第二次触发的时候事件本身的行为会执行

.self和.stop区别: .self只是阻止自身不执行冒泡触发,不会阻止冒泡继续向外部触发,.stop是从自身开始不向外部发射冒泡信号

 

21、重绘回流

区别:

他们的区别很大:
回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流
当页面布局和几何属性改变时就需要回流
比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变

 

22、display visibility opacity

23、css水平垂直居中的方法

transform的translate(-50%,-50%)

或者

margin:auto; postion:absolute; left/right/top/bottom:0;

24、清除浮动的方法

父元素overflow:hidden

父元素::after{

   content:"";clear:both;display:block;

}

子元素后加兄弟div clear:both

1.额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear:both;)(不推荐)

2.父级添加overflow属性(父元素添加overflow:hidden)(不推荐)

3.使用after伪元素清除浮动(推荐使用)

4.使用before和after双伪元素清除浮动

 

25、css的两种盒模型

标准盒模型:box-sizing:content-box   content的宽高为宽高

IE盒模型:box-sizing:border-box        content padding border一起的宽高为宽高

 

26、深拷贝和浅拷贝的区别、怎么实现深拷贝

浅拷贝与深拷贝

一、数据类型
数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。

基本数据类型的特点:直接存储在栈(stack)中的数据
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

五、深拷贝的实现方式

  1. JSON.parse(JSON.stringify())
    //数组非函数
  2. 手写递归方法  递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
  3. 函数库lodash  _.cloneDeep
  4. a.concat()
  • 第一级是深拷贝,以后各级是浅拷贝
  • B复制A —— A变B变,浅拷贝 ;A变B不变,深拷贝
 

第一级是深拷贝:

let a = {James: {age: 18}}

let b = Object.assign({}, a)

b.James = 20

console.log(b) // { James: 20 }

console.log(a) // { James: { age: 18 } }

 

以后各级是浅拷贝:

let a = {James: {age: 18}}

let b = Object.assign({}, a)

b.James.age = 20

console.log(b) // { James: { age: 20 } }

console.log(a) // { James: { age: 20 } }

 

27、js new的内部原理

28、箭头函数和普通函数的区别

 

29、怎么不用const和let实现块级作用域

30、let、const、var

31、es6新特性

32、js事件循环

33、宏任务和微任务有哪些

宏队列,macrotask,也叫tasks。 一些异步任务的回调会依次进入macro task queue,等待后续被调用,这些异步任务包括:

  • setTimeout
  • setInterval
  • setImmediate (Node独有)
  • requestAnimationFrame (浏览器独有)
  • I/O
  • UI rendering (浏览器独有)

微队列,microtask,也叫jobs。 另一些异步任务的回调会依次进入micro task queue,等待后续被调用,这些异步任务包括:

  • process.nextTick (Node独有)
  • Promise
  • Object.observe
  • MutationObserver
  • async await

 

34、闭包、闭包缺点

闭包就是能够读取其他函数内部变量的函数。

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中,不会在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

(1)由于闭包会携带包含它的函数的作用域链,比其他函数消耗更多的内存,过度使用,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。解除对匿名函数的引用。

(2)作用域链这种配置作用的副作用是,闭包只能取得包含函数中任何变量的最后一个值。闭包保存的是整个变量对象,不是某个特殊的变量。每个作用域链中都保存着外层函数的活动对象,他们引用的也都是里面同一个变量,而不是几个不同的变量副本。比如for循环后,只保存了一个i。

(3)匿名函数的执行具有全局性,this对象通常指向window。每个匿名函数被调用自动获取两个值this和arguments。内部函数在搜索这两个变量,只会搜索到其活动对象为止,因此永远不会直接访问外部函数中的这两个值。除非用var that = this保存起来再访问。arguments也是同理。

(4)内存泄漏

IE9之前对Jscript对象和COM对象使用不同的垃圾收集例程。闭包在这些版本会导致一些特殊问题。比如如果闭包内保存着一个html元素,那么意味着该元素将无法被销毁,占用的内存永远不会被回收。

function assignHandler(){
    var element = document.getElementById("someElement");
    element.onclick() = function(){
        alert(element.id)
    }
}

解决办法:

function assignHandler(){
    var element = document.getElementById("someElement");
    var id = element.id;
    element.onclick() = function(){
        alert(id)
    }
    element = null;
}

把element.id保存在变量中,消除循环引用。把element设置成null,消除对DOM对象的引用。

 

35、call、apply、bind区别

在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。
在说区别之前还是先总结一下三者的相似之处:
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。

call调用 将方法中的this指向call中第一个参数,当第一个参数为null、undefined时,默认指向window; call中第一个参数之后是要传递给方法的参数列表。

call(obj, a1, a2, a3)

apply与call相似,不同之处在于传递给方法的参数形式不一致。apply传递给方法的参数是数组的形式。

apply(obj, [a1, a2, a3])

bind 方法 与 apply 和 call 比较类似,也能改变函数体内的 this 指向。不同的是,bind 方法的返回值是函数,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。

bind(obj, a1, a2, a3)()

 

36、js 基本类型和引用类型有哪些、区别

 

37、url到显示页面发生了什么

基本面试必问了,有空出个专门的blog好好总结一下最全面的an

 

38、http在哪层?七层协议

应用层

物理层-数据链路层-网络层-传输层-会话层-表示层-应用层

 

39、常用http请求有哪些、get和post的区别

序号方法描述
1GET

发送请求来获得服务器上的资源,请求体中不会包含请求数据,请求数据放在协议头中。另外get支持快取、缓存

、可保留书签等。幂等

2POST

和get一样很常见,向服务器提交资源让服务器处理,比如提交表单、上传文件等,可能导致建立新的资源或者对

原有资源的修改。提交的资源放在请求体中。不支持快取。非幂等

3HEAD

本质和get一样,但是响应中没有呈现数据,而是http的头信息,主要用来检查资源或超链接的有效性或是否可以可达、检

查网页是否被串改或更新,获取头信息等,特别适用在有限的速度和带宽下。

4PUT

和post类似,html表单不支持,发送资源与服务器,并存储在服务器指定位置,要求客户端事先知

道该位置;比如post是在一个集合上(/province),而put是具体某一个资源上(/province/123)。所以put是安全的,

无论请求多少次,都是在123上更改,而post可能请求几次创建了几次资源。幂等

5DELETE请求服务器删除某资源。和put都具有破坏性,可能被防火墙拦截。如果是https协议,则无需担心。幂等
6CONNECT

HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。就是把服务器作为跳板,去访问其他网页

然后把数据返回回来,连接成功后,就可以正常的get、post了。

7OPTIONS获取http服务器支持的http请求方法,允许客户端查看服务器的性能,比如ajax跨域时的预检等。
8TRACE

回显服务器收到的请求,主要用于测试或诊断。一般禁用,防止被恶意攻击或盗取信息。

、项目中的难题

41、事件代理

 

42、es5模拟块级作用域(闭包)

使用IFE立即执行函数形成闭包

(function(){

   //块级作用域

})();

用立即执行函数包裹for循环,情况就不一样了:
 

function outputNumbers(count){

    (function(){

        for(var i = 0; i < count; ++i){

        console.log(i);

    }})();

    console.log(i);//Uncaught ReferenceError: i is not defined

}

outputNumbers(5);

//结果 0 1 2 3 4

此时i绑定在内部立即执行函数的变量对象上,立即执行函数执行完毕就会销毁,i也会随之销毁,变量不会在外部还能使用。

根据闭包机制,内部的立即执行函数也可以访问到count。这样就实现了块级作用域——无论在立即执行函数中声明什么变量都不会影响外部变量的使用。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值