一,前端解决跨域问题(常用)

1,后端设置cors允许跨域,一般指定ip,也可以允许全部
2,jsonp,利用浏览器对script加载完自动执行的特新来实现的,需要客户端和服务器端两端的同时配合,因此需要特别处理的接口可以使用,一般传统的后台接口不会采用这种方式进行跨域。
3,Nginx反向代理,一般利用vue-cli全家桶,开发时在vue.config.js中设置接口在同一个后端域名和端口,正式服务则使用Nginx确保在统一域名下。

二,常见web安全及防护

防护:
1,对用户输入内容进行限制和校验
2,对所有关键数据进行加密
3,接口提交方式严格规范,数据提交不使用get
攻击方式:
sql注入,xss(恶意注入js和网页元素),csrf(代替用户完成交互并访问危险网站)

三,js垃圾回收机制

js的垃圾回收机制是自动执行的,且不可发现的。垃圾回收的对象分为:全局变量和局部变量(函数内变量)。全局变量只有在页面被关闭时才被回收,局部变量在所属函数调用结束后回收。回收方式分为两类一种是标记清除,一种是引用计数。

四,前端性能优化

1,尽量压缩css和js文件大小
2,采用less或者sass
3,图片懒加载
4,精灵图和雪碧图
5,接口尽可能做到重复使用
6,数据请求异步操作,防止页面卡顿

五,闭包理解

闭包就是一个函数,两个函数嵌套在一起,内部函数就是闭包。形成闭包的条件:内部函数需要通过return返回出来。

function f1(){

        function f2(){

            alert("我是js闭包!");

        }

        return f2;

    }

    var f=f1();

    f();  //弹出:我是js闭包!

内部函数可以调用外部函数的参数。
用得非常多,包括异步请求,vue的函数嵌套,非常常见,有时候写起来,根本想不起来闭包啥的。

六,cookie和session的区别

1,存储位置有区分,cookie存在浏览器缓存中,session存储在服务器上
2,存储大小和数量 cookie小于session
3,保密性 cookie对游览器和用户可见 session存在服务器上,保密性更佳
4,服务器压力 session对服务器压力更大
重点!!!
在实际开发过程中,cookie和session都很少使用,更为常用的是token,它比上两个优势更大,更好用,安全性高,可扩展性强,多平台跨域,无状态。可实现,单点登录和多点登录等功能。
重点!!!
请不要混淆session和sessionStorage,前者是身份验证(类似于令牌),后者是一种存储方式,数据保存在浏览器缓存中(localStorage存储在本地需要手动删除才会消失),关闭浏览器和标签页就会消失。
重点!!!
有种说法是cookies和localStorage和sessionStorage是同一类,都是储存方式,只是大小,保存位置,保存时间不一样
大小 cookies<sessionStorage=localStorage
保存位置 本地
时间 cookies有指定时间 sessionStorage关闭页面 localStorage不主动清除一直存在

七,那些操作会造成内存泄漏

1,什么是内存泄漏
看上面的垃圾回收机制,当有变量和对象,应该被回收,而没有被回收时,一直占用和停留在堆内存中,这就产生内存泄漏。
2,内存泄漏影响
内存泄漏会导致内存被占用过多无法释放,从而导致系统内存分配不足,造成了内存溢出从而导致应用Crash(浏览器崩溃)。
3,前端造成内存泄漏的操作
1,闭包
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,过多的使用闭包,不及时释放,会导致内存泄漏。
2,意外全局
函数中定义参数,var 定义,会成为全局变量,建议使用es6的let
3,定时器
4,生命周期中使用全局函数,未释放
5,echarts
6,keep-alive组件
其实在vue中一般这些是不会造成内存泄漏,只有程序猿自己写的bug才会导致,还有对于现在电脑来说,一些内存泄漏并不影响。

八,重构的理解

重构不是重写项目!!!重构不是重写项目!!!重构不是重写项目!!!

重构是一种对软件内部结构的改善,包括去除重复、简化复杂逻辑和澄清模糊的代码,甚至可能是变更一个参数名。
重构和重写之间的差异在于: 重构是在标准化流程和方法的指导下,给正在跑的车换轮子,乘客(业务方)不受影响。重写是推倒重来,比较理想的结果是你把新车造好了让乘客跳过来,但真能做到的团队不多,需要很高的工程管理能力。

九,常见浏览器内核

1,edge的edgeHTML
2,火狐的Gecko
3,Safari的webKit
4,Chrome的Blink

十,DOM创建,添加,移动,复制,查找,删除节点,

1,创建 document.creatElement(‘a’) //创建a元素节点 多用于下载操作 页面显示 <a> </a>
2,添加节点 appendChild()

let ul = document.getElementById('ul');
let li = document.creatElement('li');
ul.appdenChild(li);

一般用于对页面添加文本列表项啥的。
3,删除节点 removeChild()

var ul = document.getElementById("myList"); //获得ul
var lis = ul.getElementsByTagName("li") //获取ul中所有li的集合
ul.removeChild(lis[0]);       //移除第一个li,与上面不同,要考虑浏览器之间的差异

4,查找节点(常用)

document.getElementById('box1');//查询Id为box1的元素
document.getElementByClass('box2');//查询class(类名)为box2的元素

5,复制节点 cloneNode()

1 var ul = document.getElementById("myList"); //获得ul
2 var deepList = ul.cloneNode(true); //深复制
3 var shallowList = ul.cloneNode(false); //浅复制

十一,事件模型的三个阶段

一个事件的处理过程主要有三个阶段:捕获,目标,冒泡;

(1)捕获: 当我们在 DOM 树的某个节点发生了一些操作(例如单击、鼠标移动上去),就会有一个事件发射过去。这个事件从 Window 发出,不断经过下级节点直到触发的目标节点。在到达目标节点之前的过程,就是捕获阶段(Capture Phase)。( 所有经过的节点,都会触发这个事件。捕获阶段的任务就是建立这个事件传递路线,以便后面冒泡阶段顺着这条路线返回 Window。 )
(2)目标阶段:当事件不断的传递直到目标节点的时候 ,最终在目标节点上触发这个事件,就是目标阶段。
(3) 冒泡阶段: 事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),然后逐级传播到较为不具体的节点(我们平时用的事件绑定就是利用的事件冒泡的原理)

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件

这里得提到阻止事件冒泡
方法一:event.stopPropagation( )

//为所有button元素绑定click事件
$(":button").click( function(event){
    alert("button-click");
    // 阻止事件冒泡到DOM树上
    event.stopPropagation(); // 只执行button的click,如果注释掉该行,将执行button、p和div的click (同类型的事件)  
} );

方法二:event.target

$(document).ready(function(){
 $('#switcher').click(function(event){
  if(event.target==this){//判断是否是当前绑定事件的元素元素触发的该事件
  $('#switcher .button').toggleClass('hidden');
  }
  })
 })

还得提到js的事件绑定
这个就是非常基础的东西
1,原生函数

<input onclick="alert('谢谢支持')" type="button" value="点击我,弹出警告框" />

2,自定义函数

<input onclick="myAlert()" type="button" value="点击我,弹出警告框" />
<script type="text/javascript">
function myAlert(){
alert("谢谢支持");
}
</script>

3,js代码绑定

<input id="demo" type="button" value="点击我,显示 type 属性" />
<script type="text/javascript">
document.getElementById("demo").onclick=function(){
alert(this.getAttribute("type")); // this 指当前发生事件的HTML元素,这里是<div>标签
}
</script>

4,事件监听(用的不多)
绑定事件的另一种方法是用 addEventListener() 或 attachEvent() 来绑定事件监听函数。

十二,css盒子模型

标准的盒子模型 元素宽度 = width(内容宽)+ padding(内边距)+border(边框)+margin(外边距)

低版本ie 元素宽度 = width(内容+内边距+边框)+margin(外边距)

十三,js继承

实现继承首先需要一个父类,在js中实际上是没有类的概念,在es6中class虽然很像类,但实际上只是es5上语法糖而已
1,原型链继承(常用,如引用工具类函数)

function Woman(){ 
}
Woman.prototype= new People();
Woman.prototype.name = 'haixia';
let womanObj = new Woman();

优点:

简单易于实现,父类的新增的实例与属性子类都能访问

缺点:

可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面

无法实现多继承

创建子类实例时,不能向父类构造函数中传参数

2,借用构造函数继承(伪造对象、经典继承)

复制父类的实例属性给子类

function Woman(name){
 //继承了People
  People.call(this); //People.call(this,'wangxiaoxia'); 
  this.name = name || 'renbo'
}
let womanObj = new Woman();

优点:

解决了子类构造函数向父类构造函数中传递参数

可以实现多继承(call或者apply多个父类)

缺点:

方法都在构造函数中定义,无法复用

不能继承原型属性/方法,只能继承父类的实例属性和方法
3,实例继承(原型式继承)
4,组合式继承

function People(name,age){
  this.name = name || 'wangxiao'
  this.age = age || 27
}
People.prototype.eat = function(){
  return this.name + this.age + 'eat sleep'
}

function Woman(name,age){
  People.call(this,name,age)
}
Woman.prototype = new People();
Woman.prototype.constructor = Woman;
let wonmanObj = new Woman(ren,27);
wonmanObj.eat(); 

5,寄生组合继承

/父类
function People(name,age){
  this.name = name || 'wangxiao'
  this.age = age || 27
}
//父类方法
People.prototype.eat = function(){
  return this.name + this.age + 'eat sleep'
}
//子类
function Woman(name,age){
  //继承父类属性
  People.call(this,name,age)
}
//继承父类方法
(function(){
  // 创建空类
  let Super = function(){};
  Super.prototype = People.prototype;
  //父类的实例作为子类的原型
  Woman.prototype = new Super();
})();
//修复构造函数指向问题
Woman.prototype.constructor = Woman;
let womanObj = new Woman();

十四,浏览器访问页面发生什么

1、DNS查询
2、TCP链接
3、发送HTTP请求
4、Server处理HTTP请求并返回HTTP报文
5、浏览器解析并render页面
6、HTTP连接断开

十五,清除浮动

清除浮动是由于float:left;或float:right;引起的问题。实际运用过程中是不用的或少用,原因是浮动布局造成的影响较多,处理繁琐。更建议使用灵活布局即 display:flex;相关操作可以在网上搜索,不过多赘述。

浮动让元素脱离文档流,按照指定的方向进行运动,遇到相邻的浮动元素或者父元素的边沿时停下,左浮动left;右浮动right
清除浮动的方法
1,父级div定义 height
原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题。
优点:简单、代码少、容易掌握
缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题
建议:不推荐使用,只建议高度固定的布局时使用
2,结尾处加空div标签 clear:both
原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
优点:简单、代码少、浏览器支持好、不容易出现怪问题
缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不好
建议:不推荐使用,但此方法是以前主要使用的一种清除浮动方法
3,父级div定义 overflow:hidden
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
优点:简单、代码少、浏览器支持好
缺点:不能和position配合使用,因为超出的尺寸的会被隐藏。
建议:只推荐没有使用position或对overflow:hidden理解比较深的朋友使用。

知道3个就行,实际运用很少,应付面试即可

十六,数组去重

1,利用Array.from和Set成员的唯一性

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

let arr = [1, 2, 3, 2, 1];

function unique(arr){
    return Array.from(new Set(arr));
}
console.log(unique(arr))   // [1, 2, 3]

2,双重for循环进行去除(es5最多使用)

var arr = [1, 5, 6, 0, 7, 3, 0, 5, 9, 5, 5]
function unique(arr) {
  for (var i = 0, iLen = arr.length; i < iLen; i++) {
    for (var j = i + 1, jLen = arr.length; j < jLen; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1)
        j-- // 每删除一个数j的值就减1
        jLen-- // j值减小时len也要相应减1(减少循环次数,节省性能)
        // console.log(j,jLen)
      }
    }
  }
  return arr
}
console.log(unique(arr)) //  1, 5, 6, 0, 7, 3, 9

数组去重是必须掌握的一个方法,实际运用中可能后端都给你处理好了,但是也有可能需要你处理的,第一种方法多用,在笔试题部分可以节省大量时间

十七,promise是什么,可以解决什么问题

ES6中新技术,解决异步回调地域问题。
(1)promise对象表示一个异步操作的最终完成或失败,及其结果值,是一个代理值。
(2)语法上:Promise是一个构造函数,用来生成Promise的实例对象。
(3)功能上:Promise对象用来包裹一个异步操作,并获取成功、失败结果值。

实例

function f1() {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(111), 1000);
    }).then(data => console.log(data));
  }
function f2() {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(222), 2000);
    }).then(data => console.log(data));;
  }
 function f3() {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(333), 3000);
    }).then(data => console.log(data));;
  }

f1().then(f2).then(f3)

实际情况下,我可能不会使用promise,更加倾向使用.then(),在then里调用函数
例如

a().then(()=>{
	b().then(()=>{
		c();
	})
})

十八,如何查找当前页面中所有z-index,并找到其中最大值

1,找到所有元素转化维数组

Array.from(document.querySelectorAll('body *'))

2,找到所有元素中的z-index

如果zindex为null则覆盖为0

// 正常写法
Number(window.getComputedStyle(__DOM__).zIndex) || 0

// 简写写法
+window.getComputedStyle(__DOM__).zIndex || 0

3,数组中寻找最大值

Math.max(...arr)

综合起来

var arr = Array.from(document.querySelectorAll('body *')).map(e => Number(window.getComputedStyle(__DOM__).zIndex) || 0)
return arr.length ? Math.max(...arr) : 0

十九,接收服务端消息推送

可以用websocket,主要的就是这样
socket=newWebSocket(url);
//打开websokcet
socket.open=()=>{console.log(“已打开”)};
//接收信息
socket.onmessage=(data)=>{console.log(收到的信息:${data})};
//关闭
socket.onclose=()=>{console.log(“关闭”)};
//出错
socket.οnerrοr=()=>{console.log(“出错”)};

二十,数组与类数组区别

类数组

  1. 拥有length属性
  2. length属性的类型是Number

二十一,前端浏览器多个标签页通讯?

1,通过localstorage进行存储与读取
2,通过cookie+setInterval。隔段时间读取

二十二,js去除所有空格?

去除字符串内所有的空格:str = str.replace(/\s*/g,"");

二十二,vue单页项目优缺点

优点
良好的交互体验

单页面应用的内容改变不需要重新加载整个页面,数据获取也是通过ajax异步获取的,没有页面之间的切换,就不会出现白屏现象,也不会出现假死并有闪烁现象,页面显示流畅,web更具有响应性

良好的前后端分离工作模式,后端不再负责渲染模板,后端API通用化,即同一套后端程序代码,不用修改就可以用于web界面,手机,平板等多种客户端

减轻服务器压力,服务器只用出数据就可以,不用展示逻辑和页面合成,吞吐能力会提高几倍

缺点
首屏加载慢

如果不对路由进行处理,在加载首页的时候,就会将所有组件全部加载,并向服务器请求数据,拖慢加载速度
通过查看Network,发现整个网站记载时间长达十几秒,加载最长的就是js,css,和媒体文件
解决方案

Vue-router懒加载

vue-router懒加载就是按需加载组件,只有当路由被访问的时候才会加载对应的组件,而不是在加载首页的时候就加载,而不是在加载时候也的时候就加载,项目越大,对首屏加载的速度就提升的越明显

使用CDN加速

项目中用到的库,采用CDN加载可以加快速度

异步加载组件

服务端渲染

服务端渲染还能对SEO优化起到作用,有利于搜索引擎抓取更多的有用信息(如果页面纯前端渲染,搜索引擎抓取到的就只有空白页面

不利于SEO

SEO的本质就是一个服务器向另一个服务器发起请求,解析请求内容,但一般来说搜索引擎不会去执行请求到的js。也就是说,搜索引擎的基础爬虫原理就是抓取url,然后获取html源代码并解析,如果是一个单页面应用,html在服务端还没有渲染部分数据,在浏览器才渲染出部分数据,搜索引擎请求到的html是模型页面并不是最终数据的渲染页面

解决方案

服务端渲染, 服务端合成完整的html文件再输出浏览器

页面预渲染

路由采用h5 history模式

不适合开发大型项目
大型项目可能会涉及到大量的DOM操作,复杂的动画效果,也就不适合用vue,react框架进行开发

Logo

前往低代码交流专区

更多推荐