前端面试题
1.响应式布局如何实现
响应式布局可以让网站同时适配不同分辨率和不同的手机端,让客户有更好的体验。
为什么要使用响应式布局:
在之前使用固定宽高有一定的局限:屏幕越来越宽时,因为定 得宽是固定的,这样会让页面不美观屏幕越来越小时,因为定宽的局限会让用户看不到完整的页面内容
在这种情况下,响应式布局就出现了
响应式布局的实现(有五种方法)
1.百分比布局:百分比布局是相对于父元素进行布局,百分比能够对width,height,padding,margin来进行布局,border,font-size不能;
局限: 因为百分比布局只能对大面积的地方进行布局,所以不够完美
2.css3媒体查询:媒体查询可以根据不同的分辨率来设置不同的css样式,通过这种方式来适配不同屏幕,相比于百分比布局,媒体查询可以对布
局进行更细致的调整
@media screen and(min-width:1200px) @media screen and(max-width:1200px) Screen就是客户端屏幕的信息
局限:媒体查询在设置的时候需要在每个分辨率和操作下设置不同的css样式
3.rem响应式布局:rem是一个单位,跟px,em类似,1rem就等于html的font-size值,有两种方法可以进行设置
1.通过媒体查询来设置,在不同的分辨率下给html的font-size赋值;比较麻烦
2.js进行动态计算给font-size设置值:封装一个函数:通过屏幕的宽度去处理某个数,得出来的值就是html的font-size值,当屏幕宽
度改变的时候就调用这个函数,这样在使用rem的时候就会根据html的font-size来进行等比缩放;
4.弹性盒子布局:通过display:flex;来布局,给父元素设置display:flex;在给子元素设置想要改变的属性;
5.vw响应式布局:vw是基于视口的布局方案,所以在使用的时候需要在meta标签的视口中声明;1vw等于视口宽度的1% 1vh等于视口高度的1%;
现在用的都是vw,因为高度是根据内容的多少而自适应的。
2.rem布局原理
原理:rem是指相对于根元素的字体大小的单位,是基于根元素的font-size值来进行计算,就是1rem就等于html的font-size值;
1rem等于多少px,就是font-size的值*
你设定的rem的值;
--------怎么使用rem来布局
使用Js来动态修改根元素的font-size值,当屏幕宽度发生改变的时候rem就会被动态计算出来,那你设置的rem就会自动转换为px单位;
JS代码:
function rem(){
document.documentElement.style.fontSize=document.documentElement.clientWidth/7.5+'px'
}
rem()
window.onresize=rem;
3.数据类型判断
一共有4中数据类型判断的方法
1.typeof()他可以检测一些普通数据类型,比较直观的数据,比如number,string这些能够具体的检测出来他们的类型,
判断引用数据类型无论引用的对象是什么类型都返回object; [],null,{} :object
2.instanceof 他可以检测引用数据类型,可以判断一个变量是否是某个类型和是否是某个实例,由构造类型判断数据类型,返回的是true或者false,
不可以判断null和undefined fn instanceof Fn
3.constructor 他是通过对象的construnctor直接来判断他是否和他的原型相同,但是一旦构造函数的原型被更改那么这个方法就不好用了
fn.constructor == Array
4.Object.prototype.toString.call() 他目前是一个最完美的解决方案,他只需要在括号里边写你想要判断的数据类型就行了,
他可以直接从原型里面找要判断的类型
4.原型和原型链
函数原型:每个函数都有一个prototype对象,这个对象就是函数的原型,每个函数原型中都有一个constructor属性,就是构造函数本身,
构造函数被实例化后,包含一个__proto__属性,这个属性就是函数的原型,new实例化后的对象没有prototype原型,有__proto__;
函数的原型有一个优点就是在原型中添加属性,所有的实例化对象都可以访问到
JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是自身的原型
JavaScript 的函数对象,除了原型 [proto] 之外,还有 prototype 属性,当函数对象作为构造函数创建实例时,
该 prototype 属性值将被作为实例对象的原型 [proto]
原型链:当一个对象调用自身不存在的属性/方法时,就会去自己 [proto] 关联的前辈 prototype 对象上去找,如果没找到
,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而形成了所谓的“原型链”。
代码实现:先定义一个函数,里面写一些属性;然后在这个函数的原型上设置一些属性;然后在new 实例化这个函数;
最后通过调用这个实例化出来的新函数来查找属性,就可以实现一个原型链;
5.闭包
要了解闭包,先得了解变量的作用域,分为全局作用域和局部作用域,JS中函数内部可以访问函数外部的变量,但函数外部却无法访问函数内部
的变量;
闭包就是能够访问其他函数内部的变量的函数,闭包的本质就是把函数内部和外部连接起来;
闭包有一个封闭性的特点:就是一旦形成闭包,那么外界就无法访问到闭包里面的数据定义:
当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数的内部变量,且返回的那个函数在外部被执行,就产生了闭包.
特性:
1:函数套函数
2:内部函数可以直接访问外部函数的内部变量或参数
3:变量或参数不会被垃圾回收机制回收
闭包的优缺点:
优点:
1:变量长期驻扎在内存中
2:避免全局变量的污染
3:私有成员的存在
缺点:
1.虽然说防止了全局变量污染,但是这样容易导致内存泄漏,会让使用过的变量无法回收,一直占着内存;
2、对捕获的变量是引用,不是复制
3、父函数每调用一次,会产生不同的闭包
应用场景:
1.SetTimeout:原生的setTimeout传递的函数不能带参数,通过闭包可以实现传参效果。
2.回调:定义一个行为,然后把它关联到某个用户事件上。代码通常会作为一个回调绑定到事件上;
3.选项卡
闭包案例
原生的setTimeout传递的第一个函数不能带参数
setTimeout(function(param){
alert(param)
},1000)
通过闭包可以实现传参效果
function func(param){
return function(){
alert(param)
}
}
var f1 = func(1);
setTimeout(f1,1000);
```
- 选项卡案例
```js
for(var i = 0; i< lis.length; i++){
(function(i){
lis[i].click = function(){
for(var m = 0; m< lis.length; m++){
lis[m].className = "";
}
lis[i].className = "active";
}
})(i)
}
作用:改变作用域
## 内存泄露的解决?
由于IE的js对象和DOM对象使用不同的垃圾收集方法,因此闭包在IE中会导致内存泄露问题,无法销毁驻留在内存中的元素 .在退出
> 函数之前,将不使用的局部变量全部删除。
> 2.通过添加另外一个闭包来避免JS对象和DOM对象之间的循环引用
# 6.js继承
BOM:浏览器对象模型;DOM:文档对象模型;
------1.构造函数继承:构造函数继承的中心思想就是把父函数的this指向改为子函数的this指向,从而实现继承; 优点:可以传递参数,借助call等改变this指向的方法; 改变this指向的方法:call 第二个参数与要改变指向中的方法的参数对应
apply 第二个参数是一个数组,数组中的元素与要改变的方法中的参数对应
bind方法使用后返回的是一个函数,所以第二个参数要在()里写,调用 缺点:他只能继承父函数本身的属性,父类原型的方法却不能使用;无法实现构造函数的复用。每个新实例都有父类构造函数的副本
#代码
function Fu(name) {
this.name = name;
}
function Zi() {
Fu.call(this,”aa”)
}
var obj = new Zi();
console.log(obj.name);
**
## 3. **bind,call,apply的区别**
**
- 都是用来改变this对象的指向
- 第一个参数都是this要指向的对象
- 都可以传递第二个参数
区别
//父函数
function Fu(name,gender,age){
this.name = name;
this.gender= gender;
this.age = age;
this.say = function(){
console.log(this.name + " , " + this.gender + " ,今年" + this.age);
}
}
function Zi(){
Fu