前端面试题及答案(一)

## 前端

**一.对闭包的理解,以及哪些地方用过闭包,以及闭包的缺点**

```javascript
<button id="add">加1</button>
<span id="span">10</span>
(function(){
var a = 10;
add.onclick = function (){
a++;
span.innerHTML = a;
}
})()
```

**二.对跨域了解吗,jsonp 的限制**

Q:为什么要跨域
A:跨域,通常情况下是说在两个不通过的域名下面无法进行正常的通信,或者说是无法获取其他域名下面的数据,这个主要的原因是,浏览器出于安全问题的考虑,采用了同源策略,通过浏览器对JS的限制,防止恶意用户获取非法的数据。

Q:同源策略
A:限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。

Q:“同源”
A:协议相同、域名相同、端口相同

Q:同源政策的目的
A:是为了保证用户信息的安全,防止恶意的网站窃取数据。

Q:同源的限制范围
A:Cookie、LocalStorage 和 IndexDB 无法读取;DOM 无法获得;AJAX 请求不能发送

**解决办法**
JSONP
1.只支持GET请求而不支持POST等其它类型的HTTP请求(虽然采用post+动态生成iframe是可以达到post 跨域的目的,但这样做是一个比较极端的方式,不建议采用)。明确说明:jquery使用POST请求jsonp可以成功是由于jquery自动把POST转化成GET,实际还是GET请求
2. 一般get请求能完成所有功能。如:如果需要给其他域服务器传送参数可以在请求后挂参数(注意不要挂隐私数据),即 <script src="http://xxx/getPerson.php?name=Hello&age=18"></script>
3. JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。
4.在受信任的双方传递数据,JSONP是非常合适的选择。
5.可以看出来JSONP跨域一般用于获取其他域的数据。
6.一般能够用JSONP实现跨域就用JSONP实现,这也是前端用的最多的跨域方法。

window.name
1、必须与iframe配合使用
2、window.name 传输技术,原本是 Thomas Frank 用于解决 cookie 的一些劣势(每个域名 4 x 20 Kb的限制、数据只能是字符串、设置和获取 cookie 语法的复杂等等)而发明的。后来 Kris Zyp 在此方法的基础上强化了 window.name 传输 ,用来解决跨域数据传输问题。
3.window.name 的美妙之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
特征:
1.浏览器窗口有 window.name 属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。
2.即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

基本原理:
1.当在浏览器中打开一个页面,或者在页面中添加一个iframe时,即会创建一个对应的window对象,当页面加载另一个新的页面时,window的name属性是不会变的。
2.这样就可以利用在页面动态添加一个iframe然后src加载数据页面,在数据页面将需要的数据赋值给window.name。
3.然而此时承载iframe的index页面(也就是请求数据的页面)还是不能直接访问,不在同一域下iframe的name属性,这时只需要将iframe再加载一个与承载页面同域的空白页面,即可对window.name进行数据读取

document.domain 跨域
这个的实现思路跟cookie跨域相似,都是在两个关联域名中设置document.domain值,然后让这两个值相等,这样就可以实现跨域操作

cookie跨域

postMessage跨域


**三..浏览器哪些地方用到了异步**

首先确定JS是一门脚本语言,他的执行顺序是从上到下逐行执行的,浏览器只有一个javascript引擎,所以浏览器同事只能执行一个任务,那么异步操作的实现原理是什么呢?
浏览器的javascript引擎确实是单线程的,但是浏览器本身是多线程的,浏览器包含
***javascript引擎线程、界面渲染线程、浏览器事件触发线程、Http请求线程***
所以出发异步操作的时候,会有单独的线程去做操作,javascript引擎线程不会受到阻塞,依然继续解析js代码。


**四、CSS 弹性布局,哪些地方用到过**

flex布局


**五、如何实现不定宽高水平和垂直居中**
1.最简单的flex布局
display: flex;
justify-content: center;
align-items: center;
2.利用table-cell
外层容器
display:table-cell;
text-align:center;
vertical-align:middle;
内部元素
vertical-align:middle;
display:inline-block;
3.使用CSS3 transform
外层容器
display:relative
内部元素
transform: translate(-50%,-50%);
position: absolute;
top: 50%;
left: 50%;

**六、const 和 let 区别,可以改变 const 定义的某个对象的属性吗**

let与const都是只在声明所在的块级作用域内有效。
let:无变量提升(未到let声明时,是无法访问该变量的)
const:无变量提升,声明一个基本类型的时候为常量,不可修改;声明对象可以修改
const arr = {name:'小可爱', age:'21'}
arr.name = '萱萱'
console.log(arr)
因为对象是引用类型的,arr中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会 改变
对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。


**七、ES6 用到过吗,新增了哪些东西,你用到过什么**
定义变量加入了 let const
箭头函数
Array.from() 将类数组对象与可遍历对象转换为数组
类class

**八、箭头函数,箭头函数的特点, this 的指向**
箭头函数是匿名函数,不绑定自己的this,arguments,super,new.target
箭头函数会捕获其所在上下文的this值,作为自己的this值,在使用call/apply绑定时,相当于只是传入了参 数,对this没有影响

**九、数组去重**
ES6:Array.from(new Set(arr));
```javascript
<script type="text/javascript">
let arr = ['1',2,1,3,5,6,5]
let arrString = arr.toString()
console.log(arrString)
arrSplit = arr1.split(',') // 把一个字符串分割成字符串数组。
//join() 把数组中的所有元素放入一个字符串。
console.log(arrSplit)
let set = new Set(arrSplit)
console.log(set)
let newArr = Array.from(set)
console.log(newArr)
</script>
```

**十、哪些方法会改变原数组**

shift:将第一个元素删除并且返回删除元素,空即为undefined
unshift:向数组开头添加元素,并返回新的长度
pop:删除最后一个并返回删除的元素
push:向数组末尾添加元素,并返回新的长度
reverse:颠倒数组顺序
sort:对数组排序
splice:splice(start,length,item)删,增,替换数组元素,返回被删除数组,无删除则不返回


**十一、深拷贝和浅拷贝**
浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

深拷贝的要求程度
*我们在使用深拷贝的时候,一定要弄清楚我们对深拷贝的要求程度:是仅“深”拷贝第一层级的对象属性或数组元素,还是递归拷贝所有层级的对象属性和数组元素?*

***深拷贝数组(只拷贝第一级数组元素)***
1.直接遍历
2. slice()
slice() 方法返回一个从已有的数组中截取一部分元素片段组成的新数组(不改变原来的数组!)
用法:array.slice(start,end) start表示是起始元素的下标, end表示的是终止元素的下标
当slice()不带任何参数的时候,默认返回一个长度和原数组相同的新数组

```javascript
var array = [1, 2, 3, 4];
var copyArray = array.slice();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
```
3. concat()
```javascript
var array = [1, 2, 3, 4];
var copyArray = array.concat();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
```
***深拷贝对象***
1.直接遍历
2.ES6的Object.assign

```javascript
var obj = {
name: '醉霜林',
job: '前端开发'
}
var copyObj = Object.assign({}, obj);
copyObj.name = '醉霜林2号';
console.log(obj); // {name: "醉霜林", job: "前端开发"}
console.log(copyObj); // {name: "醉霜林2号", job: "前端开发"}
```
Object.assign:用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target),并返回合并后的target
用法: Object.assign(target, source1, source2); 所以 copyObj = Object.assign({}, obj); 这段代码将会把obj中的一级属性都拷贝到 {}中,然后将其返回赋给copyObj
3.ES6扩展运算符:
扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
**对多层嵌套对象,很遗憾,上面三种方法,都会失败:**

```javascript
var obj = {
name: {
firstName: '醉',
lastName: '霜林'
},
job: '前端开发'
}

var copyObj = Object.assign({}, obj)
copyObj.name.lastName = '霜林醉';
console.log(obj.name.lastName); // 霜林醉
console.log(copyObj.name.lastName); // 霜林醉
```
***拷贝所有层级***

1.不仅拷贝第一层级,还能够拷贝数组或对象所有层级的各项值
2. 不是单独针对数组或对象,而是能够通用于数组,对象和其他复杂的JSON形式的对象
下面这一招可谓是“一招鲜,吃遍天”

(1).JSON.parse(JSON.stringify(XXXX))
```javascript
var array = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
var copyArray = JSON.parse(JSON.stringify(array))
copyArray[0].number = 100;
console.log(array); // [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]
```
2.手动写递归

```javascript
var array = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
function copy (obj) {
var newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
}
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ?
copy(obj[i]) : obj[i];
}
return newobj
}
var copyArray = copy(array)
copyArray[0].number = 100;
console.log(array); // [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

```
***存在大量深拷贝需求的代码——immutable提供的解决方案***

实际上,即使我们知道了如何在各种情况下进行深拷贝,我们也仍然面临一些问题: 深拷贝实际上是很消耗性能的。(我们可能只是希望改变新数组里的其中一个元素的时候不影响原数组,但却被迫要把整个原数组都拷贝一遍,这不是一种浪费吗?)所以,当你的项目里有大量深拷贝需求的时候,性能就可能形成了一个制约的瓶颈了。

immutable的作用:

通过immutable引入的一套API,实现:

1.在改变新的数组(对象)的时候,不改变原数组(对象)

2.在大量深拷贝操作中显著地减少性能消耗

```javascript
const { Map } = require('immutable')
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50
```

十二、call() 和 apply() 的区别和作用?

区别:apply()与call()作用没有区别,用法与call()方法稍有区别,就是call()的第二个参数(调用函数使用的参数),是一个一个传入的;而apply()的第二个参数的值是使用数组的形式传入的
作用:在Javascript中,每个函数都包含两个非继承而来的方法,call和apply。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。

apply方法接收两个参数,第一个参数是在其中运行函数的作用域,第二个是一个参数数组或者arguments对象。
call方法与apply方法作用相同,第一个参数也相同,区别在于,其余的参数需要逐个列出。

apply(thisArg, argArray);
call(thisArg[,arg1,arg2…]);

是使用call还是apply要看具体的情况。如果你知道所有参数或者参数的数量不多,可以使用call;
如果参数的数量不确定,或者数量很大,或者你收到的是一个数组或者是个arguments对象,则需要使用apply。
十三、localStorage sessionStorage Cookie
共同点:都是保存在浏览器端,且同源的。
不同点:
webstorage是本地存储,存储在客户端,包括localStorage和sessionStorage。

**localStorage**:localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除 localStorage信息,否则这些信息将永远存在。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。

**sessionStorage**:sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。源生接口可以接受,亦可再次封装来对Object和Array有更好的支持。

***localStorage和sessionStorage使用时使用相同的API:***

localStorage.setItem("key","value");//以“key”为名称存储一个值“value”
localStorage.getItem("key");//获取名称为“key”的值
localStorage.removeItem("key");//删除名称为“key”的信息。
localStorage.clear();​//清空localStorage中所有信息

作用域不同:
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标 签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。

**Cookie**
生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。 存放数据大小为4K左右 。有个数限制(各浏览器不同)。与服务器端通信:每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题。但Cookie需要程序员自己封装,源生的Cookie接口不友好。


```javascript
//Cookie方法
<script src="../js/cookie.js"></script>//Cookie函数自己封装引入
function haxi(){
if(getCookie("isClose")){
$(".header").hide();
}else{
$(".header").show();
}

$(".close").click(function(){
$(".header").fadeOut(1000);

setCookie("isClose", "1","s10");
})
}
haxi();
```
cookie的优点:具有极高的扩展性和可用性
1.通过良好的编程,控制保存在cookie中的session对象的大小。
2.通过加密和安全传输技术,减少cookie被破解的可能性。
3.只有在cookie中存放不敏感的数据,即使被盗取也不会有很大的损失。
4.控制cookie的生命期,使之不会永远有效。这样的话偷盗者很可能拿到的就 是一个过期的cookie。

cookie的缺点:
1.cookie的长度和数量的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB。否则会被截掉。
2.安全性问题。如果cookie被人拦掉了,那个人就可以获取到所有session信息。加密的话也不起什么作用。
3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务端保存一个计数器。若吧计数器保存在客户端,则起不到什么作用。

**浏览器允许每个域名所包含的cookie数**:
*Microsoft指出InternetExplorer8增加cookie限制为每个域名50个,但IE7似乎也允许每个域名50个cookie。
Firefox每个域名cookie限制为50个。
Opera每个域名cookie限制为30个。
Safari/WebKit貌似没有cookie限制。但是如果cookie很多,则会使header大小超过服务器的处理的限制,会导致错误发生。
注:“每个域名cookie限制为20个”将不再正确!*

**当很多的cookie被设置,浏览器如何去响应。**
除Safari(可以设置全部cookie,不管数量多少),有两个方法:
  最少最近使用(leastrecentlyused(LRU))的方法:当Cookie已达到限额,自动踢除最老的Cookie,以使给最新的Cookie一些空间。Internet Explorer和Opera使用此方法。

  Firefox很独特:虽然最后的设置的Cookie始终保留,但似乎随机决定哪些cookie被保留。似乎没有任何计划(建议:在Firefox中不要超过Cookie限制)。


**不同浏览器间cookie总大小也不同:**
 Firefox和Safari允许cookie多达4097个字节,包括名(name)、值(value)和等号。
 Opera允许cookie多达4096个字节,包括:名(name)、值(value)和等号。
 Internet Explorer允许cookie多达4095个字节,包括:名(name)、值(value)和等号。
注:多字节字符计算为两个字节。在所有浏览器中,任何cookie大小超过限制都被忽略,且永远不会被设置。

**十三、事件机制**(太多 百度)

**十四、setTimeout机制(推荐:https://www.jianshu.com/p/3e482748369d?from=groupmessage)**

**十五、遇到过兼容性问题吗,怎么处理的**
1、内外边距(初始化样式或normalize css)
2、图片默认有间距(display:block/float)
3、标签最低高度设置min-height不兼容(min-height:200px; height:auto !important; height:200px; overflow:visible;)
4、chrome中文界面下默认会将小于12px的文本强制按照12px显示 (添加css属性-webkit-text-size-adjust:none;)
5、一些移动端设备不支持vedio和audio的自动播放(
document.addEventListener('touchstart',function() {
document.getElementsByTagName('audio')[0].play();
document.getElementsByTagName('audio')[0].pause();
});)
6、IE5-IE8不支持opacity(
Opacity:0.8;
Filter:alpha(opacity=80);
-ms-filter:”progid:DXImageTransform.Microsoft.Alpha(opacity=80)”;)

7、Firefox点击链接出现的虚线框(a{outline:none;} a:focus{outline:none;})

8、css3种hack


参考部分面试题目或答案,如有遗漏,请私信补充。
https://blog.csdn.net/zhang6223284/article/details/81273180
https://blog.csdn.net/weixin_34116110/article/details/88624479
https://blog.csdn.net/qq_39207948/article/details/81067482

猜你喜欢

转载自www.cnblogs.com/daizhong/p/11896312.html