web前端面试题

1. 网页从输入网址到渲染完成经历了哪些过程?

输入网址;
发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
与web服务器建立TCP连接;
浏览器向web服务器发送http请求;
web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
浏览器下载web服务器返回的数据及解析html源文件;
生成DOM树,解析css和js,渲染页面,直至显示完成;

2. 闭包

闭包特性:
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收

优点:
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
③匿名自执行函数可以减少内存消耗

缺点:
①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

3. JS里垃圾回收机制是什么,常用的是哪种,怎么处理的?

JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,
垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。
JS中最常见的垃圾回收方式是标记清除。
	
工作原理:
是当变量进入环境时,将这个变量标记为“进入环境”。当变量离开环境时,则将其标记为“离开环境”。标记“离开环境”的就回收内存。
	
工作流程:
垃圾回收器,在运行的时候会给存储在内存中的所有变量都加上标记。
去掉环境中的变量以及被环境中的变量引用的变量的标记。
再被加上标记的会被视为准备删除的变量。
垃圾回收器完成内存清除工作,销毁那些带标记的值并回收他们所占用的内存空间。

4. == 和 ( === )的区别,什么情况下用相等==?

==:运算符称作相等,用来检测两个操作数是否相等,这里的相等定义的非常宽松,可以允许进行类型转换
===:用来检测两个操作数是否严格相等 
1、对于string,number等基础类型,==和===是有区别的 不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等。同类型比较,直接进行“值”比较,两者结果一样 
2、对于Array,Object等高级类型,==和===是没有区别的
3、基础类型与高级类型,==和===是有区别的 对于==,将高级转化为基础类型,进行“值”比较,因为类型不同,===结果为false

5. js中深浅拷贝的实现方式

前置知识:
栈内存(stack):会自动分配的内存空间,它由系统自动释放
堆内存(heap):动态分配的内存及大小,不一定会自动释放
基本数据类型:String, Number, Boolean, undefined, null, Symbol
引用数据类型:Object, Array, Function
在JS中,数据类型分为基本数据类型和引用数据类型两种,对于基本数据类型来说,它的值直接存储在栈内存中,
而对于引用类型来说,它在栈内存中仅仅存储了一个引用,而真正的数据存储在堆内存中
	
基本数据类型:对于基本数据类型的数据而言,当进行赋值时,系统会自动对变量在栈内存中开辟一块新的内存进行存储,变量与变量的值互不影响,相互独立
引用数据类型: 通过对于引用数据类型的实验,我们发现与基本数据类型不同的是,两个变量之间会相互干扰。为什么会出现这种现象呢?其实是因为引用数据类型存储在堆内存中,当进行赋值时,系统为变量a传入了变量b指向堆内存中地址的指针,实际上他们俩指向的是同一个对象,所以当第二个变量的值改变的时候,第一个变量的值也会改变。
/**
*浅拷贝
**/
function clone(obj) {
  var cloneObj = {};
  for(var key of Object.keys(obj)) {
      cloneObj[key] = obj[key];
  }
  return cloneObj;
}

var a = {
  a: 1,
  b: 'Trist',
  c: { d: 1 }
}
var b = clone(a)
console.log(b)  // {a: 1,b: "Trist",c: {d: 1}}

a.a = 2;
console.log(b.a) // 1

b.b = '张三',
console.log(a.b) // Trist

b.c.d = 2;
console.log(a.c.d) // 2
实现原理:创建一个拷贝的方法 clone(),通过遍历传入对象的键名及键值,然后赋值给一个空对象,这样就完成了对原对象的浅拷贝。
实验发现:当我们拿到a的浅拷贝后,我们发现,对于对象中的基本数据类型而言,他们之间是互不影响的,而对于引用数据而言,他们会相互干扰。
理解浅拷贝:浅拷贝只复制了原对象中最外层的属性,也就是拷贝了其基本类型的数据,而对于引用类型数据而言,它仅复制了其引用,指向的地址还是原对象的地址。
/**
*深拷贝
**/
function deepClone(obj, cloneObj) {
  var cloneObj = cloneObj || {};
  for(var i in obj) {
      // 通过遍历判断属性是否为引用类型,此处注意null因为历史遗留bug通过typeof输出为object
      if(typeof obj[i] === 'object' && typeof obj[i] !== null) {
          // 判断引用值是否为数据 obj[i] instanceof Array
          cloneObj[i] = (obj[i].constructor === Array) ? [] : {};
          // 进行递归
          deepClone(obj[i], cloneObj[i]);
      }else {
          cloneObj[i] = obj[i];
      }
  }
  return cloneObj;
}

var a = {
  a: 1,
  b: 'Trist',
  c: { d: 1 }
}
var b = deepClone(a)
console.log(b)  // {a: 1,b: "Trist",c: {d: 1}}

a.a = 2;
console.log(b.a) // 1

b.b = '张三',
console.log(a.b) // Trist

b.c.d = 2;
console.log(a.c.d) // 1
实现原理:首先进行遍历,判断原对象内的属性是否还有对象以及空值null,若有则判断对象是否为数组,有则赋值空数组,无则赋值空对象,然后进行递归。
实验发现:不管是原对象内的基本数据类型,还是对象,或者数组,我们在进行属性的修改添加修改时,发现他们都各自独立,互不影响。
理解深拷贝:深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突。

6.js造成内存泄漏的几种情况

1、介绍js的垃圾回收机制
js的垃圾回收机制就是为了防止内存泄漏的,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。所以这里又涉及到变量的生命周期,当一个变量的生命周期结束之后它所指向的内存就应该被释放。
JS有两种变量,全局变量和在函数中产生的局部变量。局部变量的生命周期在函数执行过后就结束了,此时便可将它引用的内存释放(即垃圾回收),但全局变量生命周期会持续到浏览器关闭页面。所以当我们过多的使用全局变量的时候也会导致内存泄漏的问题
2、主要存在内存泄漏的问题点
BOM / DOM对象泄漏
scipt中存在对BOM / DOM对象的引用
javaScript对象泄漏
闭包函数导致的泄漏
3、主要关注的代码点

DOM中的addEventLisner 函数及派生的事件监听, 比如Jquery 中的on 函数, vue 组件实例的 $on 函数,第三方库中的初始化函数
BOM对象的事件监听,比如webSocket的监听事件
避免不必要的函数引用
如果是要render函数,避免在html标签中DOM / BOM事件
4、在vue中如何处理内存泄漏的

如果在mounted/created 钩子中绑定了DOM/BOM 对象中的事件,需要在beforeDestroy 中做对应解绑处理
如果在mounted/created 钩子中使用了第三方库初始化,需要在beforeDestroy 中做对应销毁处理
如果组件中使用了定时器,需要在beforeDestroy 中做对应销毁处理
模板中不要使用表达式来绑定到特定的处理函数,这个逻辑应该放在处理函数中如果在mounted/created 钩子中使用了$on,需要在beforeDestroy 中做对应解绑($off)处理
某些组件在模板中使用 事件绑定可能会出现泄漏,使用$on 替换模板中的绑定

7.什么是函数柯里化?

是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
// 普通方法
var add = function(x, y) {
  return x + y;
}    
console.log(add(3, 4))       //7
// 柯里化 
var foo = function(x) {
  return function(y) {
      return x + y
  }
}    
console.log(foo(3)(4))       // 7 

8.事件委托以及优缺点?

优点:
1.减少事件注册,节省内存。比如,
2.在table上代理所有td的click事件。
3.在ul上代理所有li的click事件。
4.简化了dom节点更新时,相应事件的更新。比如
5.不用在新添加的li上绑定click事件。
6.当删除某个li时,不用移解绑上面的click事件。
缺点:
1.事件委托基于冒泡,对于不冒泡的事件不支持。
2.层级过多,冒泡过程中,可能会被某层阻止掉。
3.理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。
4.把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。

9.typeof和instanceof 区别?

在javascript中,判断一个变量的类型可以用typeof   
(1)数字类型、typeof返回的值是number。比如说:typeof(1),返回值是number   
(2)字符串类型,typeof返回的值是string。比如typeof(“123”返回值时string)   
(3)布尔类型,typeof返回的值是boolean。比如typeof(true)返回值时boolean   
(4)对象、数组、null返回的值是object。比如typeof(window),typeof(document),typeof(null)返回的值都是object
(5) 函数类型,返回的值是function。比如:typeof(eval),typeof(Date)返回的值都是function。
(6)不存在的变量、函数或者undefined,将返回undefined。比如:typeof(abc)、typeof(undefined)都返回undefined
在javascript中,instanceof用于判断某个对象是否被另一个函数构造。
使用typeof运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回”object”。ECMAScript引入了另一个Java运算符instanceof来解决这个问题。Instanceof运算符与typeof运算符相似,用于识别正在处理的对象的类型。与typeof方法不同的是,instanceof方法要求开发者明确地确认对象为某特定类型

10.广度优先遍历(BFS)和深度优先遍历(DFS)?

广度优先遍历 英文缩写为BFS即Breadth FirstSearch。其过程检验来说是对每一层节点依次访问,访问完一层进入下一层,而且每个节点只能访问一次。
深度优先遍历 英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

11.for in和for of的区别

1.推荐在循环对象属性的时候,使用for...in,在遍历数组的时候的时候使用for...of
2.for...in循环出的是key,for...of循环出的是value
3.注意,for...of是ES6新引入的特性。修复了ES5引入的for...in的不足
4.for...of不能循环普通的对象,需要通过和Object.keys()搭配使用

12.原型链

JavaScript
原型: 每个对象都会在其内部初始化一个属性,就是prototype(原型)。 
原型链:
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
特点:
JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

13.js事件循环 event loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)

详细介绍:http://www.ruanyifeng.com/blog/2014/10/event-loop.html

14.事件冒泡,它是如何工作的?如何阻止事件冒泡?

在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)
阻止事件冒泡的几种方法 
1, event.stopPropagation(); 
2, return false; 
3,event.preventDefault();

15.页面渲染html的过程

1.浏览器解析html源码,然后创建一个 DOM树。并行请求 css/image/js在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本也都会有一个对应的文本节点。DOM树的根节点就是 documentElement,对应的是html标签。
2.浏览器解析CSS代码,计算出最终的样式数据。构建CSSOM树。对CSS代码中非法的语法它会直接忽略掉。解析CSS的时候会按照如下顺序来定义优先级:浏览器默认设置 < 用户设置 < 外链样式 < 内联样式 < html中的style。
3.DOM Tree + CSSOM --> 渲染树(rendering tree)。渲染树和DOM树有点像,但是是有区别的。
DOM树完全和html标签一一对应,但是渲染树会忽略掉不需要渲染的元素,比如head、display:none的元素等。而且一大段文本中的每一个行在渲染树中都是独立的一个节点。渲染树中的每一个节点都存储有对应的css属性。
4.一旦渲染树创建好了,浏览器就可以根据渲染树直接把页面绘制到屏幕上。

以上四个步骤并不是一次性顺序完成的。如果DOM或者CSSOM被修改,以上过程会被重复执行。实际上,CSS和JavaScript往往会多次修改DOM或者CSSOM。

16.项目中如何处理安全问题

HTTPS请求
登陆的时候加图片验证 ,一般的登陆密码等 加 md5 加盐处理
重要数据的防爬虫的页面数据组合展示
所有的请求在 http header 里 带上 token

17.观察者模式

把自己注入到被观察的对象里, 对象改变某个数据的时候, 调用自己的update函数更新相应的状态, 强耦合的方式

18.中介者模式

中介对象主要是用来封装行为的,行为的参与者就是那些对象,但是通过中介者,这些对象不用相互知道(机场交通控制系统)
中介者模式与业务相关,订阅/发布模式与业务无关
虽然实现结构非常相像,但是很明显的是,中介者模式参与业务相关东西,所以内容是大相径庭的

19.观察者和订阅-发布的区别,各自用在哪里

两者的主要区别是调度的地方不同 订阅发布模式比观察者模式,中间多一个“调度中心”。因此更解耦,所以常见系统中,订阅发布模式能让业务更清晰
观察者模式是由具体目标调度的 而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会
可以把restful请求的通信方式,看做观察者模式的应用;而服务总线(MQ)的方式,则是订阅发布模式

20.整个前端性能提升大致分几类

构建功能及性能优化, 
图片优化, 
浏览器缓存, 
离线存储技术, 
服务端渲染, 
css性能方案, 
js性能方案, 
重绘回流, 
事件循环异步更新,
懒加载, 
事件节流与防抖

21.call、apply和bind方法的用法以及区别

call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。
当第一个参数为null、undefined的时候,默认指向window。

apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。
当第一个参数为null、undefined的时候,默认指向window。

事实上apply 和 call 的用法几乎相同, 唯一的差别在于:当函数需要传递多个变量时, 
apply 可以接受一个数组作为参数输入, call 则是接受一系列的单独变量。

bind和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。
区别在于bind方法返回值是函数以及bind接收的参数列表的使用。

bind返回对应函数, 便于稍后调用; apply, call则是立即调用。

22.三大框架对比

Angular
双向数据绑定
强大的、丰富的模板指令
模板能力非常强大
静态路由
代码自由度较低

Vue
轻量,简洁易用
双向数据绑定
模板能力较强
动态路由
插件化

React
自由度很高
一切都是javascript
可以与第三方类库很好的配合
单项数据流
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值