常见面试题
1. 如何实现ajax请求
- 通过实例化一个XMLHttpRequest对象得到一个实例
- 调用实例的open方法为这次 ajax请求设定相应的http方法、相应的地址和以及是否异步,当然大多数情况下我们都是选异步
- 以异步为例,之后调用send方法ajax请求,这个方法可以设定需要发送的报文主体
- 然后通过 监听readystatechange事件,通过这个实例的readyState属性来判断这个ajax请求的状态,其中分为0,1,2,3,4这四种 状态,当状态为4的时候也就是接收数据完成的时候,这时候可以通过实例的status属性判断这个请求是否成功
1
2
3
4
5
6
7
8
9
10var xhr = new XMLHttpRequest();
xhr.open('get', 'aabb.php', true);
xhr.send(null);
xhr.onreadystatechange = function() {
if(xhr.readyState==4) {
if(xhr.status==200) {
console.log(xhr.responseText);
}
}
}
javascript有哪几种数据类型
六种基本数据类型
- undefined
- null
- string
- boolean
- number
- symbol(ES6)
一种引用数据类型
- 函数本身作用域。
- 闭包定义时的作用域。
- 全局作用域。
闭包常见用途:
- 创建特权方法用于访问控制
- 事件处理程序及回调
JavaScript有哪几种方法定义函数
- 函数声明
- 函数表达式
- ES6箭头函数
客户端存储localStorage和SessionStorage
- localStorage有效期为永久,sessionStorage有效期为顶层窗口关闭前
- 同源文档可以读取并修改localStorage数据,sessionStorage只允许同一个窗口下的文档访问,如通过iframe引入的同源文档。
- Storage对象通常被当做普通javascript对象使用:通过设置属性来存取字符串值,Storage对象的API:setItem(key, value)设置,getItem(key)读取,removeItem(key)删除,clear()删除所有数据,length表示已存储的数据项数目,key(index)返回对应索引的key
1
2
3
4
5// 枚举所有存储的键值对
for (var i = 0, len = localStorage.length; i < len; ++i ) {
var name = localStorage.key(i);
var value = localStorage.getItem(name);
}
cookie及其操作
- cookie是web浏览器存储的少量数据,最早设计为服务器端使用,作为HTTP协议的扩展出现。cookie数据会自动在浏览器和服务器之间传输。
- 通过读写cookie检测是否支持
- document.cookie setItem参数有key,value,max-age,path,domain
link与@import的区别
- link是HTML方式, @import是CSS方式
- link最大限度支持并行下载,@import过多嵌套导致串行下载,出现FOUC
- link可以通过rel=”alternate stylesheet”指定候选样式
- 浏览器对link支持早于@import,可以使用@import对老浏览器隐藏样式
- @import必须在样式规则之前,可以在css文件中引用其他文件
- 总体来说:link优于@import
MVVM
mvvm由以下三个内容组成
- View:界面
- Model:数据模型
- ViewModel:作为桥梁负责沟通View和Model
在jQuery时期,如果需要刷新UI时,需要先取到对应的DOM再更新UI,这样数据和业务的逻辑就和页面有强耦合。
在MVVM中,UI是通过数据驱动的,数据一旦改变就会相应的刷新对应的UI,UI如果改变,也会改变对应的数据。这种方式就可以在业务处理中只关心数据的流转,而无需直接和页面打交道。ViewModel只关心数据和业务的处理,不关心View如何处理数据,这种情况下,View和Model都可以独立出来,任何一方改变了也不一定需要改变另一方,并且可以将一些可复用的逻辑放在一个ViewModel中,让多个View复用这个ViewModel。
在MVVM中,最核心的也就是数据双向绑定,例如Angluar的脏数据检测,Vue中的数据劫持。
脏数据检测
数据劫持
Vue内部使用了Object.definpropty() 中的get和set方法监听数据。
在解析模板代码时,会实例化属性的watcher对象,并且把它挂在到Dep.target属性上。
通过触发属性的get取值函数把相关的watcher实例添加到dep的subs属性中。
当数据发生变化时,触发属性的set存值函数,调用dep对象的notify方法,主要内容是遍历相关的watcher实例,调用其对应的update方法,更新视图。
面向过程和面向对象的区别?
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
箭头函数表达式和普通函数的区别
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或 new.target。
更短的函数、不绑定this、通过 call 或 apply 调用第一个参数忽略、不绑定arguments、箭头函数不能用作构造器,和 new一起用会抛出错误、箭头函数没有prototype属性、箭头函数不能用作生成器
vdom是什么?为何会存在vdom?
不用vdom遇到的问题:
- DOM操作是“昂贵”的,js运行效率高
- 尽量减少DOM操作,而不是“推到重来”
- 项目越复杂,影响就越严重
- vdom即可解决这个问题
问题解答: - virtual dom,虚拟DOM
- 用JS模拟DOM结构
- DOM操作非常“昂贵”
- 将DOM对比操作放在JS层,提高效率
vdom如何应用,核心API是什么?
- h(‘<标签名>’, {…属性…}, […子元素…])
- h(‘<标签名>’, {…属性…}, ‘…’)
- patch(container, vnode)
- patch(vnode, newVnode)
问题解答: - 如何使用?可用snabbdom的用法来举例
- 核心API:h函数返回vnode、patch函数打补丁
介绍一下diff算法?
问题解答: - 知道什么是diff算法,是linux的基础命令
- vdom中应用diff算法是为了找出要更新的节点
- diff实现,patch(container, vnode) patch(vnode, newVnode)
- 核心逻辑,createElement和updateChildren
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23function createElement(vnode) {
var tag = vnode.tag
var attrs = vnode.attrs || {}
var children = vnode.children || []
if (!tag) {
return null;
}
// 创建元素
var elem = document.createElement(tag)
// 属性
var attrName
for (attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
elem.setAttribute(attrName, attrs[attrName])
}
}
// 子元素
children.forEach(function(childVnode) {
// 递归调用createElement创建子元素
elem.appendChild(createElement(childVnode))
})
return elem;
}