前端面试题

原型

每个对象都有一个属性__proto__指向构造函数的原型对象,对象可以继承原型对象上的属性和方法,原型对象又有原型,可以继承原型对象上的属性和方法,这样一层一层,以此类推,这种关系称为原型链
每个函数都有一个属性prototype指向原型对象,创建一个函数的时候就创建了这个属性
new 构造函数创建的实例,内部的__proto__属性指向构造函数的原型对象,普通对象的__proto__属性指向Object.prototype,函数对象的__proto__指向Function.prototype,每个对象都有__proto__属性,除了Object,create(null)创建的对象没有原型
在这里插入图片描述
原型对象上有一个constructor的属性指向构造函数,因为实例对象继承了原型对象的方法,所以实例对象也可以通过constructor属性找到构造函数

new一个对象
  1. 创建一个新的对象
  2. 将this指向这个对象
  3. 执行构造函数中的代码,添加属性和方法
  4. 返回这个新对象
闭包

有权访问函数内部变量的函数叫做闭包,创建的方式就是一个函数内部创建一个函数
闭包的两个用处:

  1. 可以访问函数内部变量,可以设计私有变量和方法
  2. 可以将变量始终保存在内存中

好处:实现封装和缓存,减少全局变量的污染
缺点:闭包会引用函数的作用域,增加内存用量,容易造成内存泄漏
解决方法:在退出函数之前,将不用的局部变量删除,将变量设为Null
作用域链的理解:
确保执行环境中对有权访问的变量和函数是有序的,只能向上访问,访问到window为止,不能向下访问
创建函数会创建一个作用域链(包含全局变量以及包裹他的函数活动对象),作用域链保存在内部的[[scope]]属性中

JS继承
  1. 构造函数继承:在子构造函数中加上Super.apply(this) 继承实例属性
  2. 原型链继承:Sub.prototype= Object.create(Super.prototype) 继承原型方法
  3. 组合继承 上面两个都应用
对this的理解

this 执行上下文对象,在函数调用时确定this的指向

  1. 默认绑定:直接使用函数引用调用的,指向window,严格模式是undefined
  2. 隐式绑定:对象.方法 对象调用函数指向对象
  3. 显式绑定:bind call apply 绑定this
  4. new创建的新对象 this指向新对象
陈述输入URL回车后的过程
  1. 解析URL
  2. DNS解析得到IP地址
  3. 与服务器进行TCP连接
  4. 发送http请求,传输数据
  5. 客户端得到服务器端响应的html文件
解析HTML页面
  1. 根据HTML解析出DOM树
  2. 根据css解析生成css规则树
  3. 结合DOM树和css规则树生成 渲染树
  4. 根据渲染树计算每个节点的信息
  5. 根据计算好的信息绘制页面
    DOM树中包含所有的标签包括dispaly:none的元素
    render树中只包含所有可见的元素以及visible:hidden
回流和重绘

回流(Reflow):渲染树中的元素尺寸、形状、为止改变时,影响了周围元素或内部元素时,浏览器会重新渲染部分或全部文档
操作:

  1. 页面首次渲染
  2. 添加或删除可见元素
  3. 元素尺寸内容位置字号图片大小改变
  4. 浏览器窗口resize
  5. 激活css伪类(:hover)

重绘(Repaint):改变颜色以及visible
性能影响:回流的代价更高
浏览器优化回流,将所有引起回流重绘的操作放入队列中,如果任务数量或时间间隔达到某一个阈值,浏览器会清空队列,进行一次批处理
但是某些方法或属性,会立即处理:
clientWidth/offsetWidth/scrollWidth/width/height/getComputedStyle(elem,null).getPropertyValue(‘height’)
优化:引起少量回流或少量元素回流

  1. 避免使用table布局,因为table在变成渲染树时会经过多次计算
  2. 将动画效果应用在position为absolute或fixed元素上,,使其脱离文档流,否则会引起父元素以及后续元素的回流
  3. 避免使用css表达式(会增大计算量)

javascript中避免回流的方法

  1. 避免频繁操作样式 style一次重写,用class2
  2. . documentFragment 文档片段 不会回流
  3. 必须用到的属性 offsetHeight 缓存
  4. 先display:none;操作之后再display:block;
  5. 对动画使用绝对定位
defer和async

defer: 延迟执行引用的JS(执行之后,执行DOMContentLoaded)
载入JS文件不会影响HTML的解析,执行阶段会放到HTML解析完成之后
async: 异步引入的js
如果已经加载好,就开始执行(此时可能是HTML解析阶段,可能是在DOMContentLoaded之后);一定在load之前触发;执行会阻塞HTML解析,如果是在HTML解析阶段

src和href的区别

src: 是下载src指向的资源应用到当前文档中,会暂停其他资源的下载和解析
href是指向网络资源所在位置,并行下载资源,不会停止对当前文档的处理

BFC块级格式化上下文

常规流(标准流):
块盒一行一行竖着排列;行内盒横着排列;float为none;position为static和relative在常规流中排列
position为relative相对定位,位置偏移,但是原有位置会在常规流中保留
BFC的效果:

  1. 创建一个独立的空间
  2. 内部有个标准流
  3. 处于同一个bfc的元素,可能会发生margin合并
  4. 计算BFC高度是,考虑BFC的所有子元素,包括浮动元素

BFC的创建

  1. 根元素
  2. float不为none,position为fixed和absolute
  3. 行内块(display:inline-block)
  4. 表格单元格(display:table-cell)
  5. 弹性盒(display:flex/inline-flex)
  6. overflow不为 visible

外边距合并: 处于同一个BFC中的块盒垂直方向上会发生margin合并
解决:给其中一个盒子加上overflow:hidden;让其不在同一个BFC中

事件代理(委托)

把需要绑定的事件委托给父元素,让父元素监听事件
原理:事件冒泡 冒泡的事件可以委托 不冒泡的事件不可以委托
好处:提高性能,节约内存占用,减少事件注册
event.target是触发的对象
event.currentTarget 是绑定事件的对象

事件模型

事件3个阶段:捕获(父到子)目标 冒泡(子到父)
默认触发事件的阶段是冒泡阶段
如果把addEventListener的第三个参数改为true 就是在捕获阶段触发
阻止冒泡:stopPropagation IE是 cancelBubble= true
取消默认事件: e.preventDefault IE是 e.returnValue= false

说说对promise 的了解
  1. Promise是异步抽象处理对象,处理异步请求返回的响应数据的使用
  2. 常见异步编程方案:
    链接: https://blog.csdn.net/qq_32442973/article/details/89322763.
    (1)回调
    (2)事件监听
    (3)发布订阅
    (4)Promise
    (5)async await
  3. 一共有三种状态 pending resolved rejected
    pending 变为resloved
    pending 变为rejected
    只有这两种变化,并且一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般为value,失败的结果数据一般为reason
  4. then 注册成功或失败的回调 一定返回新的promise对象,返回的promise的结果是执行回调函数(onResolved、onRejected)的结果
async 和 await
  1. await必须放在async函数里面
  2. await后面是一个promise对象,如果不是就转为一个立即resolve的promise对象
  3. 只要await后面的promise变成reject,那么整个async函数会被中断执行,如果不希望中断后续请求 使用try …catch
  4. async 函数返回一个promise对象,函数中的返回值就是这个promise对象resolve中的参数,如果出错了throw new Error(‘出错了’)或者 await Promise.reject(‘出错了’),就是reject中的参数
commonJS
  1. node.js是commonJS的主要实践者
  2. 一个文件一个模块,每个模块都有独立的作用域,在一个模块内定义的变量在其他模块中无法读取,除非是global的属性和方法
  3. 模块只有一个出口,module.exports是一个对象,将想要暴露的方法或者属性放到该对象上;用require(url)加载一个模块

特点:同步加载模块,服务端,模块文件都在本地磁盘上,读取起来很快,所以没问题,但浏览器上限于网络原因,更合理应使用异步加载

AMD和require.js
  1. 用require.js实现AMD的模块化
  2. require.config() 指定引用路径
  3. define() 定义模块
  4. require()加载模块

特点:异步加载模块,模块的加载不影响后面语句的执行。所有依赖这个模块的语句都被定义在一个回调中,等待加载完成执行
requireJS主要解决的问题:
(1)多个JS可能存在依赖关系,被依赖的文件要早于依赖他的文件加载
(2)JS加载,浏览器暂停页面渲染,加载文件越多,页面失去响应的时间越长

CMD通用模块定义

一个模块一个文件
define(function(require, exports,module){
var $= require(‘jquery.js’)
$(‘div’).addClass(‘active’)
})
在文件中引入加载模块,使用时加载

AMD与CMD的区别

AMD:依赖前置,定义模块时就下载并执行依赖模块,所有模块执行完了,才开始执行回调中的主逻辑
CMD:就近依赖,定义模块时需要把模块变成字符串遍历一遍,知道依赖了哪些模块,然后下载但不执行,只有主逻辑遇到require了才去执行依赖
AMD中的依赖放在数组中,依赖执行没有先后顺序
CMD中遇到require才去执行,执行顺序与页面书写的顺序一致
下载都是异步下载,AMD体验好,因为没有延迟,依赖模块提前执行;CMD性能好,只有用户用到才去执行

ES6模块

ES6 的模块不是对象,import命令会被JavaScript引擎静态分析,在编译时就引入模块代码,而不是运行时,因此不能实现条件加载

CommonJS与ES6的区别
  1. commonJS模块输出值的拷贝(浅拷贝)
    ES6输出值的引用,js引擎对脚本静态分析时,遇到import命令会生成一个只读引用,当代码真正执行时,根据这个引用到被加载的模块中取值;因此ES6是动态绑定,不会缓存值,import的变量绑定其所在模块
    export default math
    import math form ‘./math’
    math中存放的是指向math.js 中对象的指针
  2. CommonJS是运行时加载,ES6是编译时输出接口
    CommonJS运行时加载整个模块,生成一个对象,在对象上调用方法
    ES6模块不是对象,而是通过export命令显示指定输出的代码,import时采用静态命令形式,即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载成为编译时加载
    export let bar= 1
    setTimeout(()=> { bar= 2; }, 500)
    import { bar } from ‘utils.js’
    console.log(bar) // 1
    setTimeout(() => { console.log(bar) }, 500) //
vue和react的区别
  1. react是函数式的思想,并且是单向数据流;vue是响应式的,视图的改变基于数据,并且对于表单属性来说,vue是双向绑定的,当视图变化,data中的数据也会变化
  2. react通过JS来生成HTML,所以设计了jsx;vue是把html,css,js组合到一起,用各自的处理方式,vue有单文件组件,可以吧html/css/js写到一个文件中,HTML提供了模板引擎来处理
  3. react是类的写法;vue是声明式的写法
  4. react可以通过高阶组件来扩展,而vue通过mixins来扩展
对于MVVM的理解

MVVM是model-view-viewmodel的缩写
model代表数据层 ,view代表是视图层,
viewmodel监听数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步view和model的对象,连接model和view
在MVVM架构中,view和model之间没有直接的联系,而是通过viewmodel进行交互,model和viewmodel之间的交互式双向的,因此view数据的变化会同步到model中,而model数据的变化也会立即反映到view上

vue响应式系统
  1. 每个Vue组件都有一个watcher实例与之对应
  2. 每个属性都有一个与之对应的dep实例
  3. vue的data属性都被observer数据劫持添加上setter和getter
  4. 当组件render执行,会访问属性,触发属性的getter,此时vue的watcher会记录渲染视图依赖的属性,与属性对应的dep实例也会记录当前的watcher
  5. 当属性改变时,会触发属性的setter,dep就会通知所有依赖此属性的watcher,执行watcher的update方法,如果是渲染watcher就是重新渲染视图,如果是user、computed watcher就执行回调
vue组件通信
  1. 父->子: 传props
  2. 子->父:
    (1)父组件传值的时候 :title.sync=“doc.title” 子组件使用 this. e m i t ( " u p d a t e : t i t l e " , n e w T i t l e ) 触 发 事 件 更 新 父 组 件 的 值 ( 2 ) 方 法 名 作 为 属 性 名 父 组 件 : : g e t T i t l e = " g e t T i t l e " 子 组 件 : t h i s . g e t T i t l e ( ) ( 3 ) 方 法 作 为 事 件 父 组 件 : @ g e t T i t l e = " g e t T i t l e " 子 组 件 : t h i s . emit("update:title", newTitle) 触发事件更新父组件的值 (2)方法名作为属性名 父组件::getTitle="getTitle" 子组件:this.getTitle() (3)方法作为事件 父组件:@getTitle="getTitle" 子组件:this. emit("update:title",newTitle)2:getTitle="getTitle"this.getTitle()3@getTitle="getTitle"this.emit(‘getTitle’)
  3. eventBus事件总线
  4. vuex全局数据管理
    state mutation 更改store中状态的唯一方式 提交mutation(mutation必须是同步函数) action提交的是mutation 不直接更改状态 可以是异步函数
  5. provide/inject 允许一个祖先组件向其子孙后代注入一个依赖
vue路由的钩子函数

beforeRouteEnter进入路由之前
beforeRouteUpdate路由改变 但该组件被复用
beforeRouteLeave 离开路由之前
afterEach 进入每个路由之后
beforeEach 进入每个路由之后

vue的diff算法

相同类型的节点:

  1. key相同(如果没有 就是undefined == undefined)
  2. tag 标签名相同且isComment(是否为注释节点)且data是否都存在且是否都为input或不为input
  3. 是异步组件 工厂函数asyncFactory相同

vue的diff算法

  1. 对比新旧开始结束节点是否为相同类型的节点,是的话就原地复用,新旧开始指针向后挪一个
  2. 对比新旧开始与结束或结束与开始节点是否为相同节点;是的话就用insertBefore移动节点
  3. 如果新有旧没有,添加节点
    这样简单的移动添加得到快速处理,待处理节点减少,缩小处理范围,性能得到提升
vue中key值的作用

就是在上面提到的判断节点是否为相同类型节点时,如果key相同的话就会就地复用,key的作用主要是为了高效的更新虚拟DOM

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值