js--------面经

1.内存泄漏场景和解决方案

泄漏点:
1.DOM/BOM 对象泄漏
2.script 中存在对DOM/BOM 对象的引用导致
3.Javascript 对象泄漏
4.通常由闭包导致,比如事件处理回调,导致DOM对象和脚本中对象双向引用,这个是常见的泄漏原因

1.闭包
function fn1(){
    var n=1;
}
//我想取到里面的局部变量n
function fn1(){
    var n=1;
    function fn2(){//在加一个fn2当他的子集
        alert(n);
    }
 
}
function fn1(){
    var n=1;
    function fn2(){//在加一个fn2当他的子集
        alert(n);
    }
return fn2(); 
//return出来后 他就给 window了
//所以一直存在内存中。因为一直在内存中,
// 在IE里容易造成内存泄漏
}
fn1();

尽量书写的时候,避免这种情况。

2.意外的全局变量
function foo(arg) {
    bar = "aaaaa";
}
 
// 实际上等价于
function foo(arg) {
    window.bar = "aaaaa";
}

为了防止这种错误的发生,可以在你的 JavaScript 文件开头添加 ‘use strict’; 语句

3.定时器setTimeout setInterval

当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。比如:vue使用了定时器,需要在beforeDestroy 中做对应销毁处理。js也是一样的。

clearTimeout(***)
clearInterval(***)
4.如果在mounted/created 钩子中使用了$on,需要在beforeDestroy 中做对应解绑($off)处理
beforeDestroy() {
  this.bus.$off('****');
}
5.反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)
for(i = 0; i < 5000; i++) { 
   hostElement.text = "asdfasdfasdf"; 
} 

这种方式相当于定义了5000个属性!

2. 前端性能优化篇

1)使Ajax可缓存

Ajax的目地是为突破web本质的开始—停止交互方式,向用户显示一个白屏后重绘整个页面不是一种好的用户体验。

异步与即时

Ajax的一个明显的有点就是向用户提供了即时反馈,因为它异步的从后端web服务器请求信息。

用户是否需要等待的关键因素在于Ajax请求是被动的还是主动的。被动请求是为了将来来使用而预先发起的,主动请求是基于用户当前的操作而发起的

什么样的AJAX请求可以被缓存?

POST的请求,是不可以在客户端缓存的,每次请求都需要发送给服务器进行处理,每次都会返回状态码200。(可以在服务器端对数据进行缓存,以便提高处理速度)

GET的请求,是可以(而且默认)在客户端进行缓存的,除非指定了不同的地址,否则同一个地址的AJAX请求,不会重复在服务器执行,而是返回304。

Ajax请求使用缓存

在进行Ajax请求的时候,可以选择尽量使用get方法,这样可以使用客户端的缓存,提高请求速度。

2) 配置ETag

以前浏览器缓存的就会失效。

什么是ETag?

实体标签(EntityTag)是唯一标识了一个组件的一个特定版本的字符串,是web服务器用于确认缓存组件的有效性的一种机制,通常可以使用组件的某些属性来构造它。

条件GET请求
如果组件过期了,浏览器在重用它之前必须首先检查它是否有效。浏览器将发送一个条件GET请求到服务器,服务器判断缓存还有效,则发送一个304响应,告诉浏览器可以重用缓存组件。

那么服务器是根据什么判断缓存是否还有效呢?有两种方式:

ETag(实体标签);

最新修改日期;

最新修改日期

原始服务器通过Last-Modified响应头来返回组件的最新修改日期。

3)服务器端(后端)技术

除了优化前端,服务器端技术也可以用来加速加载时间。这些技术都值得考虑,但不会在本文中介绍:

缓存HTTP重定向来加速重复访问;
合并HTTP重定向链来减少重定向;
使用HTTP压缩来减少数量的字节(Gzip或缩小)。

4)数据量过大大导致的页面卡顿

后台的接口访问速度慢,查看接口速度原因,数据量多的情况下,可以考虑分批发送和缓存处理。

3. 跨域问题

什么是跨域?

浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。

跨域限制

1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
2、无法接触非同源网页的 DOM
3、无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)

如何解决跨域问题?

跨域实践: Fiddle 处理前端本地开发跨域问题

目前我了解的解决跨域的几种方式: 手写过滤器,手写拦截器,jsonnp,注解方式,配置nginx反向代理

1、jsonp跨域
JSONP(JSON with Padding:填充式JSON),应用JSON的一种新方法,
JSON、JSONP的区别:
 1、JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用)
 2、JSONP 只支持get请求、不支持post请求
 (类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)
 
2、nginx反向代理:
www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html
3、PHP端修改header
header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
在这里插入图片描述

4、document.domain【实现不同window之间的相互访问和操作】

跨域分为两种:
一种xhr不能访问不同源的文档,
另一种是不同window之间不能进行交互操作;

document.domain主要是解决第二种情况,且只能适用于主域相同子域不同的情况;
  document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com中某个文档的document.domain可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。
兼容性:所有浏览器都支持;
优点:
 可以实现不同window之间的相互访问和操作;
缺点:
 只适用于父子window之间的通信,不能用于xhr;
 只能在主域相同且子域不同的情况下使用;
使用方式:
 不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:
 
5、window.name

关键点:window.name在页面的生命周期里共享一个window.name;
兼容性:所有浏览器都支持;
优点:
 最简单的利用了浏览器的特性来做到不同域之间的数据传递;
 不需要前端和后端的特殊配制;
缺点:
 大小限制:window.name最大size是2M左右,不同浏览器中会有不同约定;
 安全性:当前页面所有window都可以修改,很不安全;
 数据类型:传递数据只能限于字符串,如果是对象或者其他会自动被转化为字符串,如下;
在这里插入图片描述

4. 深拷贝实现方式

  1. 使用递归的方式实现深拷贝
    //使用递归的方式实现数组、对象的深拷贝
    function deepClone1(obj) {
      //判断拷贝的要进行深拷贝的是数组还是对象,
      // 是数组的话进行数组拷贝,对象的话进行对象拷贝
      var objClone = Array.isArray(obj) ? [] : {};
      //进行深拷贝的不能为空,并且是对象或者是
      if (obj && typeof obj === "object") {
        for (key in obj) {
          if (obj.hasOwnProperty(key)) {
            if (obj[key] && typeof obj[key] === "object") {
              objClone[key] = deepClone1(obj[key]);
            } else {
              objClone[key] = obj[key];
            }
          }
        }
      }
      return objClone;
    }

  1. 通过 JSON 对象实现深拷贝
  //通过js的内置对象JSON来进行数组对象的深拷贝
    function deepClone2(obj) {
      var _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
      return objClone;
    }
    JSON对象实现深拷贝的一些问题 
    *无法实现对对象中方法的深拷贝
  1. 通过jQuery的extend方法实现深拷贝
    var array = [1,2,3,4];
    var newArray = $.extend(true,[],array);

  1. Object.assign(), slice, concat拷贝
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
  1. lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
5.删除数组中某个数的方法
  1. splice()
  2. delete

6.删除一段长度的数组的方法

7.重绘和重排(repaints and reflows)

1,重排
就是渲染树的一部分必须要更新 并且节点的尺寸发生了变化。这就会触发重排操作。

2,重绘

部分节点需要更新,但是没有改变他的集合形状,比如改变了背景颜色,这就会触发重绘。
下面任何操作都会触发重绘或者重排:

增加或删除DOM节点
设置 display: none;(重排并重绘) 或者 visibility: hidden(只有重排)
移动页面中的元素
增加或者修改样式
用户 改变窗口大小,滚动页面等

css中哪些属性能避免重排
transform、opacity、filters

8.axios

Ajax(Asynchronous JavaScript and XML):异步网络请求。Ajax能够让页面无刷新的请求数据。

Axios,可以理解为ajax i/o system,这不是一种新技术,本质上还是对原生XMLHttpRequest的封装,可用于浏览器和nodejs的HTTP客户端,只不过它是基于Promise的,符合最新的ES规范。具备以下特点:

在浏览器中创建XMLHttpRequest请求
在node.js中发送http请求
支持Promise API
拦截请求和响应
转换请求和响应数据
取消要求
自动转换JSON数据
客户端支持防止CSRF/XSRF(跨域请求伪造)

拦截器interceptors

拦截器是指当发送请求或者得到响应被then或catch处理之前对它们进行拦截,拦截后可对数据做一些处理,比如给请求数据添加头部信息,或对响应数据进行序列化,然后再传给浏览器,这些都可以在拦截器中进行

//添加一个请求拦截器
axios.interceptors.request.use(config=>{
    //在请求之前做一些事
    return config;
},err=>{
   //请求错误的时候做一些事
    return Promise.reject(err);
});

//添加一个响应拦截器
axios.interceptors.response.use(response=>{
    //对返回的数据做一些处理
    reutrn response;
},err=>{
   //对返回的错误做一些处理
    return Promise.reject(err);
});

//移除拦截器
const myInterceptor = axios.interceptors.request.use(config=>{return cofig})
axios.interceptors.request.eject(myInterceptor);

//在一个axios实例中使用拦截器
var instance = axios.create();
instance.interceptors.request.use(function(){/*...*/});

在请求拦截中,错误拦截较少,通常都是配置相关的拦截

在响应拦截中,若成功,则主要是对数据进行过滤;若失败,则可以根据starus判断报错的状态码,来跳转到不同的错误提示页面

8.遍历对象方法for in 和for of的区别

for in可以遍历对象和数组

使用for in遍历时,会有以下问题

index索引为字符串型数字(注意,非数字),不能直接进行几何运算
遍历顺序有可能不是按照实际数组的内部顺序(可能按照随机顺序)

使用for-in会遍历数组所有的可枚举属性,包括原型方法method和name属性都会被遍历出来,通常需要配合hasOwnProperty()方法判断某个属性是否该对象的实例属性,来将原型对象从循环中剔除

所以for-in更适合遍历对象且配合hasOwnProperty()方法一起使用,通常是建议不要使用for-in遍历数组

for of 只能遍历数组,不能遍历对象

for of可以简单有效的遍历数组,并且不会遍历原型上的method和name

如果想要遍历,可通过Object.keys()把对象转化为数组再遍历

他有如下优点:

这是最简洁、最直接的遍历数组元素的语法

这个方法避开了for-in循环的所有缺陷

与forEach()不同的是,它可以正确响应break、continue和return语句

简单总结就是

for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值
for-in得到的是对象的key或数组、字符串的下标
for-of得到的是对象的value或数组、字符串的值,另外还可以用于遍历Map和Set

9.Object.defineProperty的用法详解

该方法是es5的方法(千万不要以为是es6的哦),作用是直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。(切记只能用在对象身上不能用在数组身上

语法:Object.defineProperty(obj, prop, descriptor)
参数说明:
obj:必需。目标对象
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性

访问器属性

Configurable:和数据属性的 [[Configurable]] 一样,表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true

Enumerable:和数据属性的 [[Configurable]] 一样,表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true

Get:一个给属性提供 getter 的方法(访问对象属性时调用的函数,返回值就是当前属性的值),如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined

Set:一个给属性提供 setter 的方法(给对象属性设置值时调用的函数),如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值