【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】

文章目录

    • html篇
      • 1.语义化标签有哪些?HTML5新特性有哪些?
      • 2.说一些浏览器实现页面渲染的整个过程
      • 3.行内标签有哪些?块级标签有哪些?
      • 4.简述一下src与href的区别?
    • CSS篇
      • 1.如何让一个div盒子实现垂直水平居中?有几种方法?
      • 2.清除浮动的方法有哪些?
      • 3.CSS3的新特性有哪些?
      • 4.讲下CSS的盒子模型是怎样的?
      • 5.px和em的区别?
    • JS篇
      • 1.深拷贝和浅拷贝的区别?
      • 2. == 和 === 的 区别
      • 3.什么是闭包?什么时候会用到?有什么优缺点?
      • 4.var 、let和const的区别是什么?
      • 5.如何改变this的指向,call和apply的区别是什么?
      • 6.什么是原型链?如何实现继承,在项目中有没有使用过?
      • 7.ES6的新语法有哪些?
      • 8.常见的操作数组的方法有哪些?
      • 9.js如何判断一个变量的类型,typeof和instanceof的区别是什么?
      • 10.简述同步和异步的区别
    • Jquery篇
      • 1.jquery如何实现链式编程?
    • Window对象篇
      • 1.事件捕获、事件冒泡和事件委托?
      • 2.localstorage、 sessionstorage、和cookie的区别是什么?
      • 3.常见的http状态码有哪些,分别代表什么?
      • 4.get和post的区别是什么?
      • 4.工作中如何处理跨域问题?
    • Vue篇
      • 1. 说一下 Vue 的双向绑定数据的原理?
      • 2. 解释单向数据流和双向数据绑定
      • 3.Vue 如何去除 URL 中的#?
      • 4.对 MVC、MVVM 的理解?
      • 5. Vue 生命周期的理解
      • 6.组件通信
      • 7.vue-router 路由?
      • 8.v-if 和 v-show 区别?
      • 9.$route 和 $router 的区别?
      • 10.NextTick 是做什么的?
      • 11.Vue 组件 data 为什么必须是函数?
      • 12.对比 jQuery ,Vue 有什么不同?
      • 13.Vue 中怎么自定义指令?
      • 14.Vue 中怎么自定义过滤器?
      • 15.对 keep-alive 的了解?
      • 16.Vue 中 key 的作用?
      • 17.Vue 等单页面应用的优缺点?
    • 开发及性能篇
      • 1.如何优化前端的性能?
      • 2.什么叫优雅降级和渐进增强?
      • 3.如何规避JavaScript多人开发函数重名的问题?
      • 4.请说出三种减低页面加载时间的方法?
      • 5.你所了解到的Web攻击技术?
      • 6.前端开发中,如何优化图像?图像格式的区别?
      • 7.浏览器是如何渲染页面的?

html篇

1.语义化标签有哪些?HTML5新特性有哪些?

语义化标签:h1-h6(标题标签)、li(无序列表)、ol(有序列表)、strong/em(强调)等
HTM5新特性
1.语义化标签:header、footer、section、nav、aside、artical
2.增强型表单:input的多个type(email、number、color、time等)
3.新增表单元素:datalist、keygen、output(用于不同类型的输出,比如计算或脚本输出)
4.新增表单属性:placehoder、required、min和max
5.音频视频:audio、video
6.canvas(元素用于图形的绘制,通过脚本 -通常是JavaScript来完成.)
7.地理定位
8.拖拽
9.本地存储:localStorage-没有时间限制的数据存储;sessionStorage-针对一个session的数据存储,当用户关闭浏览器窗口后,数据会被删除
10.新事件:onresize、ondrage、onscroll、onmousewheel、onerror、onplay、onpause
11.WebSocket:单个TCP连接上进行全双工通讯的协议
支持html5新标签:
IE8/IE7/IE6支持通过document。createElement方法产生的标签
可以利用这一特性让这些浏览器支持html5的新标签
浏览器支持新标签后,还需添加标签的默认样式

2.说一些浏览器实现页面渲染的整个过程

1.在浏览器输入url
2.浏览器先查看浏览器缓存–系统缓存–路由器缓存,如果缓存中存在页面的内容,就会直接在屏幕当中显示
3.在发送http请求前,浏览器会开启一个线程来解析域名(DNS解析),获取相应的IP地址
4.浏览器向服务器发起TCP连接,与服务器通过TCP三次握手建立连接
5.握手成功后,浏览器再向服务器发起http/https请求,请求数据包
6.服务器处理受到的请求,将数据返回给浏览器
7.浏览器收到http响应
8.解析html,构建dom树
9.解析css,生成css规则树
10.合并dom树和css规则树,生成render树
11.布局render树
12.绘制render树,即绘制页面像素信息
13.GPU将各层合成,结果呈现在浏览器的窗口当中

(简单记忆:dns -- tcp --http请求--服务器响应--渲染
关于tcp握手不理解的话,可以看这位老哥的文章,写的简单易懂:
https://baijiahao.baidu.com/s?id=1614404084382122793&wfr=spider&for=pc

3.行内标签有哪些?块级标签有哪些?

行内标签:span、a、em(强调)、strong、u(下划线)、i(斜体)
行内块标签:img、input、textarea、
块级标签:div、h1-h6、ul、ol、li、hr、以及html5新增的 header、section、aside、footer

4.简述一下src与href的区别?

href是指向网络资源所在的位置,建立和当前元素(锚点)或当前文档(链接)之间的锚点,用于超链接。
src是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在的位置,在请求src资源的时候会将其指向的资源下载并应用到文档当中,例如js脚本,img图片,frame等元素。

当浏览器解析到钙元素的时候,会暂停其他资源的下载和处理,知道该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内,这也是为什么将js脚本放在底部而不是头部

CSS篇

1.如何让一个div盒子实现垂直水平居中?有几种方法?

<div class='parent'>
<div class='children'><div>
<div>
.parent{
	width:600px;
	height:600px;
	background:blue;
.children{
	width:300px;
	height:300px;
	background:pink;}
}

1.flex布局 (垂直和水平都居中)

.parent{
	display:flex;
	justify-content:center;
	align-item:center;
.children{}
}

2.定位

.parent{
	position:relative;
.children{
	position:absolute;
	top:50%;
	left:50%;
	margin-top:-150px;
	margin-left:-150px;}
}

3.magin:auto;

.parent{
	position:relative;
.children{
	position:absolute;
	magin:auto;
	top:0;
	left:0;
	right:0;
	bottom:0;
	}
}

2.清除浮动的方法有哪些?

  1. 给父级元素单独定义高(height)

  2. 给元素设置overflow:hidden(或者是除了visible其他的属性)

  3. 额外的标签法(有浮动的父级元素的末尾插入了一个没有内容的块级元素div 给其设置clear:both的样式)

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

.clearfix:after {
 visibility: hidden;
 clear: both;
 display: block;
 content: ".";
 height: 0;
}

.clearfix {
 *zoom: 1;
}

  1. 双伪元素清除法
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}

3.CSS3的新特性有哪些?

1.颜色:新增RGBA,HSLA模式
2.文字阴影(text-shadow)
3.边框:圆角(border-radius)、边框阴影(box-shadow)
4.盒子模型:box-sizing
5.背景:background-size 设置背景图片的尺寸 background-origin设置背景颜色的原点 background-clip设置背景图片的裁切区域 、以“,”分割可以设置多个背景,用于自适应的布局
6.渐变:linear-gradient、radial-gradient
7.过渡:transition ,可实现的动画
8.自定义动画
9.在css3中唯一引入的伪元素是::selection
10.媒体查询,多栏布局
11.border-image
12.2D转换:transfrom:translate(x,y)rotate(x,y)skew(x,y)scale(x,y)
13.3D转换

4.讲下CSS的盒子模型是怎样的?

一个盒子由外到内可以分成四个部分:margin(外边距)、border(边框)、padding(内边距)、content(内容)。而 margin、border、padding是css的属性,因此可以通过这三个属性来控制盒子的三个部分,而content则是html元素的内容。
而盒子模型也包括两种IE 盒子模型标准 W3C 盒子模型。标准 W3C 盒子模型的宽和高都包括了padding、和boder

5.px和em的区别?

相同点:px和em都是长度单位
异同点:px的值是固定的,指定是多少就是多少,计算比较容易,em的值就不是很固定,并且em会继承父级元素的字体大小

浏览器的默认字体高都是16px。所以未经调整的浏览器都符合:1em=16px.那么12px=0.75em,10px=0.625em

JS篇

1.深拷贝和浅拷贝的区别?

提示>>>>>从堆和栈的角度去解释。。
首先先说下他们的含义:假设B复制了A,当我们修改B的值的时候,假如这时A的值跟着一起改变了,那就是浅拷贝,假如A的值没有改变,那就是深拷贝。
那从堆和栈的角度要怎么去解释呢?
我们先解释下堆和栈是什么?
堆是堆内存(heep)的简称,栈是栈内存(stack)的简称。

  • 我们先要知道js总共有两种数据类型,一种是基本数据类型:number、string、null、undefined、boolean一种是引用类型的数据:如对象(Object)、数组(Array)、函数(Function)
  • js的基本类型都是存储在栈当中,每种类型的数据占用的内存空间的大小是确定的,并且由系统自动分配和自动释放,这样带来的好处是,内存可以及时得到回收,相对于堆来说,更加容易去管理内存空间。
  • js的引用数据类型的数据是存储于堆当中,准确来讲,应该是他们的数据地址存储于栈当中,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址,然后再通过地址找到堆当中我们所需要的数据。

栈中的基本数据类型
var a=“bbb”

【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第1张图片
然后我们再改变a的值
a=111
在这里插入图片描述
由此我们可以看到,基本数据类型数值的改变就是在原本的内存当中修改,而不会新开辟一个地址

那接下来,我们将a赋值给c
var c=a
【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第2张图片
而当我们进行赋值的时候,是会开辟一个新的地址,不信的话我们改变下 c的值试试
c=666
【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第3张图片
大家可以用代码试一试

var a = "bbb";
console.log(a);  //bbb
a = 111;
console.log(a);//111
var c = a;
console.log(c); //111
c = 666;
console.log(c);//666
console.log(a);//111


堆中的引用数据类型
1.如下示例
var obj = new Object();

由此可知 obj 引用数据对象类型,在栈内存中是等于一个地址,然后再从这个地址去堆内存里面找到相对应的值
2.键值对
obj.name=“theshy”
【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第4张图片
3.引用数据类型的赋值
var b=obj
【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第5张图片
看到这里不知道大家懂了没,其实引用数据类型的赋值,就只是单纯地把堆内存里面的地址赋值,所以说 obj和b的堆内存地址是一样的
假如我们修改了b里面的属性,那么obj对象里面的属性也会跟着改变,因为他们的内存地址是一样的。他们两个的命运相同。
不懂的可以敲以下代码找找感觉

var obj = new Object()
obj.name = 'theshy'
console.log(obj)//  {name: "theshy"} 
var b = obj
console.log(b)// {name: "theshy"} 
b.name = '我是666'
console.log(b)// {name: "我是666"} 
console.log(obj)// {name: "我是666"}


那究竟深拷贝和浅拷贝以及栈和堆有什么差别呢?
在深入理解的时候,我们先来一起看一段代码:

var obj = [4, 5, 6, { name: 'theshy', sex: '男' }];
  // 浅拷贝函数
  function copy(obj) {
    var copyObj = {};
    for (var key in obj) {
      copyObj[key] = obj[key];
    }
    return copyObj;
  }

  var obj1 = copy(obj);
  console.log(obj1);        // [4, 5, 6, { name: 'theshy', sex: '男' }]
  console.log(typeof obj1); // object

  // 改变_obj数组的第一项 , 发现对obj没有影响
  obj1[0] = 'change'
  console.log(obj);   // [4, 5, 6, { name: 'theshy', sex: '男' }]
  console.log(obj1);  // ['change', 5, 6, { name: 'theshy', sex: '男' }];


  // 改变_obj的name属性,obj的name也会改变
  obj1[3].name = 'mang';
  console.log(obj);   // [4, 5, 6, { name: 'theshy', sex: '男' }]
  console.log(obj1);  // ['change', 5, 6, { name: 'mang', sex: '男' }];

  // 只改变数组中的对象
  var test = obj[3]
  test.name = 'test'
  console.log(test)   // {name: "test", sex: "男"}
  console.log(obj)    // [4, 5, 6, { name: 'theshy', sex: '男' }]
  console.log(obj1)   // ['change', 5, 6, { name: 'mang', sex: '男' }];

所谓的浅拷贝,不过就是只复制第一层对象,但是当对象的属性是引用类型时,实质复制的是其引用地址,当引用值改变时,另一个也会跟着变化

来啦来啦,划重点啦~~
所谓的浅拷贝,不过就是只复制第一层对象,但是当对象的属性是引用类型时,实质复制的是其引用地址,当引用值改变时,另一个也会跟着变化(就是 他们的堆内存当中使用的是相同的地址)命运相同
但是深拷贝的话,就是赋值的时候,新的对象的数据存放是直接开辟了一个新的地址,这个时候,当新对象发生改变的时候,旧的对象就不会跟着发生改变了。两个独立的个体
深拷贝可以通过递归的方式。(这个我们要自己尝试写一下)

2. == 和 === 的 区别

  • 两个等于号:==它在作比较时会尝试去自动转换
  • 三个等于号:===它在作比较时不会进行自动的转换

3.什么是闭包?什么时候会用到?有什么优缺点?

闭包
1.函数里面包含着子函数,子函数可以访问父函数的局部变量
2.通过return将子函数暴露在全局作用域,子函数就形成闭包
3.通过闭包,父函数的局部变量没有被销毁,可以通过闭包去调用,但同时,这个局部变量也不会被全局变量污染。

function aaa() {
                var a = 0;
                return function () {
                    alert(a++);
                };
            }
            var fun = aaa();
            fun(); //1
//简单点就是return一个函数

闭包的应用场景
1.setTimeout(原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果)
2.回调函数
3.用闭包模拟私有方法
具体可以看这篇文章,更加详细

优点:避免全局变量的污染,同时,局部变量没有被销毁,驻留在内存中,还可以被访问
缺点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

4.var 、let和const的区别是什么?

简单介绍
let 的用法类似于 var ,但是 let 只在所在的代码块内有效,所以我们一般使用 let 替代 var 。而 const 用来声明常量。

让我们先看一看这张表:

声明方式 变量提升 暂时性死区 重复声明 初始值 作用域
var 允许 不存在 允许 不需要 除块级
let 不允许 存在 不允许 不需要 块级
const 不允许 存在 不允许 需要 块级

1.var令会在预解析的时候,会预解析,发生变量提升的现象,而为了预防变量提升时导致意料之外的行为,es6规定let和const命令不发生变量提升
2.在相同的作用域内,let和const命令声明的变量是不允许重复声明的,而var是允许重复定义的。
3.const声明是只读的常量,一旦声明了,就必须立刻初始化,声明之后值不能改变。

5.如何改变this的指向,call和apply的区别是什么?

可以通过bind、call和apply属性改变this的指向
call和apply的区别就是,传参的第二个参数不同。call的话可以无限制传入无限个参数,而apply的参数,需要变成一个数组的形式从而进行传递
JS中apply、call和bind的共同点和区别是什么?

6.什么是原型链?如何实现继承,在项目中有没有使用过?

原型链:任何对象都是有__proto__属性,指向他的原型对象,而原型对象也是对象,那么原型对象也有自己的__proto__属性指向他的原型对象,也就是原型对象的原型对象,这样子形成的链式结构就是原型链。
如何实现继承?
将子对象的 prototype 指向父对象的 prototype
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
在项目中有没有使用过?
封装一些处理问题的套路,复用方法

7.ES6的新语法有哪些?

1.let与const
2.字符串模板--反引号
3.箭头函数(箭头函数中的 this 指的不是window,是对象本身)
4.解构(可以直接返回一个新的数组,但也是浅拷贝)
5.Classes(增加了类的概念,其实ES5中已经可以实现类的功能了,只不过使用Class实现可以更加清晰,更像面向对象的写法)
6.Promises(ES6 对 Promise 有了原生的支持,一个 Promise 是一个等待被异步执行的对象,当它执行完成后,其状态会变成 resolved 或者 rejected)

8.常见的操作数组的方法有哪些?

sort():对数组进行排序
unshift():将参数添加到原数组开头,并返回数组的长度
shift() :把数组的第一个元素删除,并返回第一个元素的值
.splice() :向/从数组中添加/删除项目,然后返回被删除的项目
slice() :可从已有的数组中返回选定的元素。slice(开始截取位置,结束截取位置)
reverse():用于颠倒数组中元素的顺序。
push() :可向数组的末尾添加一个或多个元素,并返回新的长度,(用来改变数组长度)
pop():用于删除并返回数组的最后一个(删除元素)元素,如果数组为空则返回undefined ,把数组长度减 1
join():用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
concat() :用于连接两个或多个数组,并返回一个新数组,新数组是将参数添加到原数组中构成的

9.js如何判断一个变量的类型,typeof和instanceof的区别是什么?

  • 一般简单的使用 typeof 或 instanceof 检测(这两种检测的不完全准确)
  • 完全准确的使用 原生js中的 Object.prototype.toString.call 或 jquery中的 $.type 检测
  • typeof可以检测出数据类型,但是array、josn、null的检测不出,需要用instanceof来进行检测
  • instanceof用来判断该对象是谁的实例,会随着原型链一直找,其语法是object instanceof constructor,返回值为true或false。

10.简述同步和异步的区别

同步是阻塞模式,异步是非阻塞模式
同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,知道收到返回信息才继续执行下去;
异步就是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态,当有消息返回时,系统会通知进程进行处理,这样可以提高执行的效率。

Jquery篇

1.jquery如何实现链式编程?

Window对象篇

1.事件捕获、事件冒泡和事件委托?

https://www.cnblogs.com/Chen-XiaoJun/p/6210987.html

2.localstorage、 sessionstorage、和cookie的区别是什么?

【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第6张图片
Cookie

Cookie 是小甜饼的意思。顾名思义,cookie 确实非常小,它的大小限制为4KB左右。它的主要用途有保存登录信息,比如你登录某个网站市场可以看到“记住密码”,这通常就是通过在 Cookie 中存入一段辨别用户身份的数据来实现的。

localStorage

localStorage生命周期是永久的,除非被清除,否则永久保存,而sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除

  • localStorage 与 HTTP 没有任何关系,所以在HTTP请求时不会带上 localStorage 的值
  • 只有相同域名的页面才能互相读取 localStorage,同源策略与 cookie 一致
  • 不同的浏览器,对每个域名 localStorage 的最大存储量的规定不一样,超出存储量会被拒绝。最大存5M 超过5M的数据就会丢失。而
    Chrome 10MB 左右
  • 常用来记录一些不敏感的信息
  • localStorage 理论上永久有效,除非用户清理缓存

sessionStorage

sessionStorage 的有效期是页面会话持续,如果页面会话(session)结束(关闭窗口或标签页),sessionStorage 就会消失。而 localStorage 则会一直存在。

共同点:都是保存在浏览器端,且同源的。
区别cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
数据有效期不同 ,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。

3.常见的http状态码有哪些,分别代表什么?

200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误

4.get和post的区别是什么?

GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark(被收藏为书签),而POST不可以。
GET请求会被浏览器主动cache(保留在历史记录当中),而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。
https://blog.csdn.net/c_Janz/article/details/81275165

4.工作中如何处理跨域问题?

https://www.cnblogs.com/smallbean/p/4493237.html

一、cors跨域
服务端对于cors的支持,主要是通过设置Access-Control-Allow-Origin来进行的,如果浏览器检测到相应的设置,就可以允许ajax进行跨域的访问。

项目中有时会使用JWT配合cors跨域实现身份验证,登录后拿到服务端生成的令牌,用户发起的请求头中需携带令牌,这样就解决了请求跨域和多端身份验证问题。(但是token令牌也有一些缺点,如,可能会被xss攻击截获,无法主动控制让token过期等,技术选型方案后续讨论。)

在服务端设置Access-Control-Allow-Origin,标识允许哪个域的请求。

响应头具体配置:
//指定允许其他域名访问
'Access-Control-Allow-Origin:http://172.20.0.206'//一般用法(*,指定域,动态设置),3是因为*不允许携带认证头和cookies
//是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回
'Access-Control-Allow-Credentials:true'
//预检结果缓存时间
'Access-Control-Max-Age: 1800'
//允许的请求类型
'Access-Control-Allow-Methods:GET,POST,PUT,POST'
//允许的请求头字段
'Access-Control-Allow-Headers:x-requested-with,content-type'

哪些是简单请求:

请求方式是:head,get,post
请求头允许的字段:Accept,Accept-Language,Content-Language,Last-Event-ID
Content-Type:application/x-www-form-urlencoded、multipart/form-data、text/plain 三选一

二、修改document.domain来跨子域
通过修改document.domain来跨子域,将子域和主域的document.domain设为同一个主域,前提条件:这两个域名必须属于同一个基础域名,而且所用的协议、端口都要一直,否则无法利用document.domain进行跨域
主域相同的使用document.domain
三、jsonp
原理是:动态插入script标签,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数当中指定的函数,并且会把我们需要的json数据作为参数传入。(注意:需要服务端.支持JSONP请求)
由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出json数据,并且执行回调函数,从而解决了跨域的数据请求。
优点:兼容性好,简单易用,支持浏览器与服务器双向通信,
缺点是只支持get请求。
举个栗子:

<script type="text/javascript">
    function dosomething(jsondata){
        //处理获得的json数据
    }
</script>

四、window.name
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的, 每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面当中的。

使用HTML5新引进的window.postMessage方法来跨域传送数据
还有flash在服务器上设置代理页面等跨域方式。个人认为window.name的方法既不复杂,也能兼容到几乎所有的浏览器,这是一个极好的跨域方式。

Vue篇

1. 说一下 Vue 的双向绑定数据的原理?

vue实现双向数据绑定的原理是:采用数据劫持“发布者-订阅者”的模式,这种模式是通过Object.defineProperty()来劫持各个属性的setter、getter,然后在数据变动的时候发布给订阅者,触发相应的监听回调。

2. 解释单向数据流和双向数据绑定

单向数据流:顾名思义,数据流是单向的,数据的流动方向可以跟踪,流动单一,追查问题的时候可以更加快捷。缺点就是写起来不太方便。要使UI发生变更就必须创建各种action来维护相对应的state
双向数据绑定:数据之间是相同的,将数据变更的操作隐藏在框架的内部。优点是在表单交互较多的场景下,会简化大量与业务无关的代码,缺点就是无法追踪局部状态的变化,增加了出错时debug的难度。

3.Vue 如何去除 URL 中的#?

vue-router默认使用hash模式,所以在路由加载的时候,项目中的url会自带“#”。如果不想使用“#”,可以使用vue-router的另一种模式 history:

newRouter({
	mode:'history',
	routes:[]
})

需要注意的是,当我们启用history模式的时候,由于我们的项目是一个单页面的应用,所以在路由跳转的时候,就会出现访问不到静态资源出现“404”的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果url匹配不到任何静态资源,则应该返回同一个“index.html”页面。(由后端处理)

4.对 MVC、MVVM 的理解?

MVC:
【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第7张图片
特点:

  1. View传送指令到Controller
  2. Controller完成业务逻辑后,要求Model改变状态
  3. Model将新的数据发送到View,用户得到反馈
  4. 所有的通信都是单向的

MVVM:
【遇见】真实经历过的前端面试题汇集【这是个待续篇,也欢迎大家一起讨论】_第8张图片
特点:
1.各部分之间的通信,都是双向的
2.采用双向绑定:View的变动,自然都反应在ViewModel,反之也一样

5. Vue 生命周期的理解

共有八个,创建前,创建后,挂载前,挂载后,更新前,更新后,销毁前,销毁后。
beforeCreated():在实例创建之前执行,数据是未加载的状态
created():在实例创建,数据加载后,能初始化数据,在DOM渲染之前执行
beforeMounte():虚拟DOM已创建完成,在数据渲染前最后一次更新数据
mounted():页面、数据渲染完成,真实的DOM挂载完成
beforeUpdate():重新渲染之前触发
Updated():数据已经更改完成,DOM也重新render完成,更改数据会陷入一个死循环。
beforeDestory():销毁前执行(这时实例仍然可以使用)
destoryed():销毁后执行

6.组件通信

父组件向子组件通信
子组件通过props属性,绑定父组件的数据,完成双方的通信
子组件向父组件通信
将父组件的事件在子组件中通过$emit来触发
非父子组件、兄弟组件之间的传值

/*新建一个Vue实例作为中央事件总嫌*/
let event = new Vue();
/*监听事件*/
event.$on('eventName', (val) => {
//......do something
});
/*触发事件*/
vent.$emit('eventName', 'this is a message.')

7.vue-router 路由?

路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。

8.v-if 和 v-show 区别?

v-if:当他为false的时候,是已经不存在于html里面了
v-show:不管值为true或者false,html元素都会存在,只是css中的display显示或隐藏

9.$route 和 $router 的区别?

$router为VueRouter的实例,想要导航到不同的Url,则需要使用$router.push方法(相当于一个全局的路由对象,包括路由的跳转对象和钩子函数)
$route是当前router跳转对象里面的(是路由的信息对象),可以获取name,path,query,params

10.NextTick 是做什么的?

$nextTick是在下次dom更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调当中获取更新后的DOM。
举个栗子
比如需要在一个dom上面挂载或者监听一个内容时候,往往会出错。比如使用v-if来进行dom渲染,由于dom还未渲染,会直接导致挂载失败。这也是Vue不建议直接操作dom的原因。

或者是通过data里的数据来重新刷新一些插件的值,由于数据是异步刷新的,可能会导致传输到插件的值还是原值,导致插件刷新失败。

这里Vue提供一个Vue.nextTick(callback)的方法,这样可以在dom都渲染完毕后再执行我们相关的业务代码。
什么时候需要用Vue.nextTick():

  • 你在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。原因是什么呢,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
  • 在数据变化后要执行的某个操作,当你设置 vm.someData = ‘new
    value’,DOM并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新。如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题。。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。

11.Vue 组件 data 为什么必须是函数?

因为js本身的特性带来的,如果data是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性的时候,会影响到所有Vue实例的数据,如果将data作为一个函数返回一个对象,那么每一个实例的data属性都是独立的,不会相互影响了。

12.对比 jQuery ,Vue 有什么不同?

jQuery 专注于视图层,通过操作dom来实现页面的一些逻辑渲染,vue专注于数据层,通过数据的双向绑定,最终表现在dom层面,减少了dom操作。
vue使用了组件化的思想,使得项目子集职责清晰,提高了开发的效率,方便重复利用,便于协同开发。

13.Vue 中怎么自定义指令?

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
  inserted: function(el) {
// 聚焦元素
    el.focus()
  }
})
//下面是局部注册
directives: {
  focus: {
// 指令的定义
   inserted: function
 (el) {
 el.focus()
 }
 }
}

参考官方文档:自定义指令(https://cn.vuejs.org/v2/guide/custom-directive.html
)

14.Vue 中怎么自定义过滤器?

可以用全局方法 Vue.filter() 注册一个自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数。过滤器函数以值为参数,返回转换后的值。

Vue.filter('reverse', 
function(value) {
return
 value.split('').reverse().join('')
})

15.对 keep-alive 的了解?

keep-alive是vue内置的一个组件,主要用于保留组件状态或避免重新渲染。

<!-- 基本 -->
<keep-alive>
  <component :is="view"></component>
</keep-alive>

<!-- 多个条件判断的子组件 -->
<keep-alive>
  <comp-a v-if="a > 1"></comp-a>
  <comp-b v-else></comp-b>
</keep-alive>

<!--`` 一起使用 -->
<transition>
  <keep-alive>
    <component :is="view"></component>
  </keep-alive>
</transition>

具体参考官方文档API:https://cn.vuejs.org/v2/api/#keep-alive

16.Vue 中 key 的作用?

key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
可参考官方文档:https://cn.vuejs.org/v2/api/#key

简单来讲:
vue中的key作用是高效地更新虚拟的dom,就是管理可复用的元素。当vue.js用v-for遍历已渲染过的元素列表时,它默认用“就地复用的策略”,会复用已有的元素而不是从头开始渲染,这样会使vue变得非常快

17.Vue 等单页面应用的优缺点?

优点

  • 良好的交互体验
  • 良好的前后端工作分离模式
  • 减轻服务端的压力

缺点

  • seo难度较高
  • 前进、后退管理
  • 初次加载耗时多

开发及性能篇

1.如何优化前端的性能?

  1. 减少http请求(css雪碧图)
  2. css放在顶部、js放在底部
  3. 合并请求
  4. 使用组件防止代码冗余

2.什么叫优雅降级和渐进增强?

渐进增强 progressive enhancement
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验
优雅降级 graceful degradation
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容

区别:
a.优雅降级是从复杂现状开始,并试图减少用户体验的供给
b.渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断地扩充,以适应未来环境的需要
c.降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带

3.如何规避JavaScript多人开发函数重名的问题?

a.命名空间
b.封闭空间
c.js模块化mvc(数据层、表现层、控制层)
d.seajs
e.变量转换成对象的属性
f.对象化(面向对象编程)

具体可看这位老哥的介绍:https://www.cnblogs.com/luoge-Snippet/p/9271320.html

一般来说有经验的程序员会尽量少的使用全局变量,尽可能使用局部变量,这不仅会减少变量重名的几率,更会减少内存开销,因为局部变量一般都会在函数结束后自动销毁释放出内存,而全局变量会直到进程结束才会被销毁
掉。其次,当我们需要一个作用域来关住变量时一般会用一个匿名函数(也就是形成一个封闭的空间)来充当这个作用域。如:

1 (function(){
2     var gender = 'girl';
3 })();
4 console.log(gender);//结果是:gender is not defined

匿名函数充当作用域这种方法一般已经能够满足一部分程序员的需求了,但函数重名怎么解决?项目中必须要使用大量全局变量又该如何解决呢?

其实解决办法跟上面方法的思路一样,只是有一点技巧性,JS既然缺少作用域限制,那我们自己再给它人为加上一个作用域,并且保证每个作用域不重复,这样一来问题不就解决了吗。好了下来我们缺少的就是这么一个神奇的作用域替代品,令人开心的是,这个东西本身JS就有,那就是对象

 1 // A同学负责的工作人员信息
 2 var A = {} //定义一个空对象
 3 A.name = 'tom';
 4 A.gender = 'male';
 5 A.age = 30;
 6 A.showName = function() {
 7     alert(this.name);
 8 }
 9 A.showAge = function() {
10     alert(this.age);
11 }
12 
13 // B同学负责的老师信息
14 var B = {}
15 B.name = 'Jack';
16 B.gender = 'male';
17 B.age = 28;
18 B.showName = function() {
19     alert(this.name);
20 }
21 B.showAge = function() {
22     alert(this.age);
23 }

25 // 正常使用,不会冲突
26 console.log(A.name);//结果:tom
27 console.log(B.name);//结果:Jack
28 A.showAge();//结果:30
29 B.showAge();//结果:28

4.请说出三种减低页面加载时间的方法?

1.压缩css、js文件
2.合并js、css文件,减少http请求
3.外部js、css文件放最底下
4.减少dom的操作,尽可能用变量减少对不必要的dom的操作

//以下是更详细的解答:
内容方面

  • 减少http请求
  • 减少dom元素的数量
  • 使得ajax可以缓存

针对css

  • 把css放到代码也的上端
  • 从页面中剥离js与css
  • 精简js与css
  • 避免css表达式

针对js

  • 脚本放在hrml代码页的底部
  • 从页面中剥离js和css
  • 精简js与css
  • 移除重复的脚本

面向图片

  • 优化图片
  • 不要再html上面使用缩放图片
  • 使用恰当的图片格式
  • 使用css Sprites技巧对图片进行优化

5.你所了解到的Web攻击技术?

(1)XSS(Cross-Site Scripting,跨站脚本攻击):指通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或者JavaScript进行的一种攻击。
(2)SQL注入攻击
(3)CSRF(Cross-Site Request Forgeries,跨站点请求伪造):指攻击者通过设置好的陷阱,强制对已完成的认证用户进行非预期的个人信息或设定信息等某些状态更新。

6.前端开发中,如何优化图像?图像格式的区别?

优化图像:
1)不用图片,尽量用css3代替。 比如说要实现修饰效果,如半透明、边框、圆角、阴影、渐变等,在当前主流浏览器中都可以用CSS达成。
2)使用矢量图SVG替代位图。对于绝大多数图案、图标等,矢量图更小,且可缩放而无需生成多套图。现在主流浏览器都支持SVG了,所以可放心使用!
3)使用恰当的图片格式。我们常见的图片格式有JPEG、GIF、PNG。
基本上,内容图片多为照片之类的,适用于JPEG
修饰图片通常更适合用无损压缩的PNG
GIF基本上除了GIF动画外不要使用。且动画的话,也更建议用video元素和视频格式,或用SVG动画取代
4)按照HTTP协议设置合理的缓存。
5)使用字体图标webfont、CSS Sprites(雪碧图,精灵图)等。
6)用CSS或JavaScript实现预加载。
7)WebP图片格式能给前端带来的优化。WebP支持无损、有损压缩,动态、静态图片,压缩比率优于GIF、JPEG、JPEG2000、PG等格式,非常适合用于网络等图片传输。
图像格式的区别:
矢量图:图标字体,如 font-awesome;svg
位图:gif,jpg(jpeg),png
区别:
1)gif:是一种无损,8位图片格式。具有支持动画,索引透明,压缩等特性。适用于做色彩简单(色调少)的图片,如logo,各种小图标icons等。
2)JPEG格式:是一种大小与质量相平衡的压缩图片格式。适用于允许轻微失真的色彩丰富的照片,不适合做色彩简单(色调少)的图片,如logo、各种小图标icons等。
3)png:PNG可以细分为三种格式:PNG8,PNG24,PNG32。后面的数字代表这种PNG格式最多可以索引和存储的颜色值。
关于透明:PNG8支持索引透明和alpha透明;PNG24不支持透明;而PNG32在24位的PNG基础上增加了8位(256阶)的alpha通道透明。
优缺点
1)能在保证最不失真的情况下尽可能压缩图像文件的大小。
2)对于需要高保真的较复杂的图像,PNG虽然能无损压缩,但图片文件较大,不适合应用在Web页面上。

7.浏览器是如何渲染页面的?

渲染的流程如下:
1)解析HTML文件,创建DOM树;
自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。
2)解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式 3)将CSS与DOM合并,构建渲染树(Render Tree);
4)布局和绘制,重绘(repaint)和重排(reflow)。

你可能感兴趣的:(前端面试)