1. 什么是闭包
函数嵌套函数 当内部函数访问外部函数变量时 就产生了闭包
2.特性
函数嵌套函数
内部函数可以直接访问外部函数的内部变量或参数
变量或参数不会被垃圾回收机制回收
3. 闭包应用场景
4.闭包优点
避免全局变量污染
私有成员的存在
变量长期驻扎在内存中
5.闭包的缺点
常驻内存
增大内存的使用量
使用不当 会造成内存泄漏
变量作用域就是一个变量可以使用的范围
1.作用域种类:
js中首先有一个最外层的作用域,全局作用域
js中可以通过函数来创建一个独立作用域称为函数作用域
,函数可以嵌套,所以作用域也可以嵌套;
es6新增了块级作用域{}
比如if{} for{}
es6作用域,只适用于const,let
2.自由变量:当前作用域没有定义的变量
一个变量在当前作用域没有定义,但被使用了
向上级作用域,一层一层依次寻找,直达找到为止
如果全局作用域都没找到,则报错 xx is not defined
3.作用域链: 自由变量向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,这就是作用域链
变量提升(预解析)
var声明的变量,function声明的函数存在变量提升 let const 不会变量提升
1.原型的概念
JavaScript的所有对象都包含一个proto属性,这个属性对应的就是自身的原型
JavaScript的函数对象,除了原型proto属性之外还有prototype属性,当函数对象作为构造函数创建实例时,该prototype属性值将被作为实例对象原型proto
2.原型链
获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__
上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有__proto__属性值为null。
1. 使用继承的好处
2.ES5中的继承
3.ES6继承
4.ES6中class继承
5.ES6中的6种继承方式
1. 原型链继承
2. 构造函数继承
call()
调用父类方法,将父类this的指向修改为子类的this,相当于把实列属性复制一份给子类3. 组合继承
call()
方法,再把父类的实例作为子类的原型const add = { //定义的一个对象
name: "名字",
age: 9,
sex: {
sex: "男"
},
arr: ["a", "b", "c"]
}
//递归函数
function deepClone(obj) {
//obj 是 null ,或者不是对象和数组,直接返回
if (typeof obj !== "object" || obj == null) {
return obj;
}
let result //初始化变量
//判断是不是一个数组
if (obj instanceof Array) {
result = []
} else {
result = {}
}
//循环obj
for (let key in obj) {
//判断 key 不是一个原型属性
if (obj.hasOwnProperty(key)) {
//调用递归函数
result[key] = deepClone(obj[key])
}
}
//返回数据
return result
}
//将add拷贝到obj1中
const obj1 = deepClone(add)
console.log(obj1.arr) //打印结果 ["a","b","c"]
//给数据arr的第一个值重新赋值
obj1.arr[0] = "d"
console.log(obj1.arr) //打印结果 ["d","b","c"]
console.log(add.arr) //打印结果 ["a","b","c"]
2.Promise有哪些API
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
}
//延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
}
Promise.race([requestImg(), timeout()]).then(function(results){
console.log(results);
}).catch(function(reason){
console.log(reason);
});
//上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。
//如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
//如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。
优点:
特点:
使用场景
dep
)里面添加自己update
()方法dep.notice()
通知时,能调用自身的update()方法
,并触发Compile中绑定的回调
,则功成身退。MVVM
作为数据绑定的入口,整合Observer、Compile和Watcher三者,
通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。1.兄弟组件通信
Bus.$emit(“事件名”,"参数")
来派发事件,数据是以$emit()的参数形式来传递2.父传子
3.子传父
将虚拟节点渲染到视图上,如果直接使用虚拟节点覆盖旧节点的话会有很多不必要的操作,为了避免不必要的dom操作,虚拟dom在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的的旧虚拟节点做对比,找出真正需要更新的节点来进行dom操作,从而避免其他无需改动的dom。
虚拟dom是利用js描述元素与元素的关系
好处:可以快速的渲染高效的更新元素,提高浏览器性能
diff算法
优点:最终表现在DOM上的修改只是部分的变更,可以保证高效的渲染,提高网页的性能
缺点:首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHtml慢一点
如何获取dom
在vue中可以通过给标签加ref属性,就可以在js中利用ref去引用它,从而操作该dom元素
1. vuex是一个专门为vue.js应用程序开发的状态管理模式。采用集中式存储和管理程序的所有组件数据
2. 好处
在大型程序中如果多个组件中用到的数据我们可以存储到vuex,如果小型项目我们可以适当使用vuex
3. 运行机制
在组件中通过dispatch来调用actions中的方法在actions中通过commit来调用mutations中的方法,在mutations中可以直接操作state中的数据,state的数据只要一发生改变立马响应到组件中
4. 异步修改数据
通过dispatch调用actions中的方法,再通过commit提交调用mutations中的方法,修改state数据达到修改数据目的
5. vuex核心概念及作用(五大属性)
6.vue持久化
概念: keep-alive是Vue的内置组件,能在组件切换过程中将状态保留在内存中,取消组件的销毁函数,防止重复渲染DOM
我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。
组件使用keep-alive以后会新增两个生命周期 actived() deactived()
1. 全局保存在App.vue中 把routerView保存起来
2. 部分缓存
1、router.js中设置要缓存的页面
{
path: '/child1',
name: 'Child1',
component: Child1,
meta:{
keepAlive:true
}
}
},
2、用v-if来显示router-view是否在keep-alive中出现
3、使用keep-alive的标签属性, include() exclude()
//include 包含标签名字被缓存 exclude 包含的标签不被缓存
//缓存名字组件中有个name属性进行定义即可
面试常问题
1. 你封装过组件吗?
2. 说一下组件封装?
3. 你在项目中如何封装组件?
我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
除了核心功能默认内置的指令 (如v-model 和 v-show等),Vue 也允许注册自定义指令。有的情况下,对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
1.自定义指令分为全局自定义指令和局部自定义指令
Vue.directive('focus',{bind(el,binding){},inserted(){}})
进行全局自定义指令bind(){} 只调用一次,指令第一次绑定到元素时调用
inserted(){}被绑定元素插入父节点时调用
update(){}被绑定元素所在的模板更新时调用,而不论绑定值是否变化
componentUpdated(){}被绑定元素所在模板完成一次更新周期时调用
unbind(){}只调用一次, 指令与元素解绑时调用
2.指令钩子函数会被传入以下参数
3.实际应用
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
路由钩子函数有三种分别为 全局守卫 单个路由守卫 组件内部守卫
全局守卫钩子 beforeEach
单个路由守卫 beforeEnter
组件内部守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
router.beforeEach((to, from, next) => { console.log(to) => // 到哪个页面去? console.log(from) => // 从哪个页面来? next() => // 一个回调函数 } router.afterEach(to,from) = {} next():回调函数参数配置
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址
next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项
2. 组件路由守卫
// 跟 methods: {}等同级别书写,组件路由守卫是写在每个单独的 vue 文件里面的路由守卫
beforeRouteEnter (to, from, next) {
// 注意,在路由进入之前,组件实例还未渲染,所以无法获取 this 实例,只能通过 vm 来访问组件实例
next(vm => {}) } beforeRouteUpdate (to, from, next) { // 同一页面,刷新不同数据时调用, } beforeRouteLeave (to, from, next) { // 离开当前路由页面时调用 }
3. 路由独享守卫
路由独享守卫是在路由配置页面单独给路由配置的一个守卫
export default new VueRouter({ routes: [ { path: '/', name: 'home', component: 'Home', beforeEnter: (to, from, next) => { // ... } } ] })
跨域是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javaScript实施的安全限制。
跨域解决方案,最少说出三种
Jsonp, CORS, 代理,反向代理,哈希处理跨域,a链接处理跨域,nginx代理跨域,nodejs中间件代理跨域
jsonp的原理
script的src属性不受同源策略的限制
将不同源的服务器端请求地址写在 script 标签的 src 属性中
什么是同源策略
同源策略 是由NetScape提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能
答1: 所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源
答2: 所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
jsonp解决跨域
JSONP是服务器与客户端跨域通信的常用方法。最大特点就是简单适用,兼容性好。缺点是只支持get请求,不支持post请求。
核心思想:
网页通过添加一个 script 元素,向服务器请求JSON数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
服务器不在返回JSON格式的数据,而是返回回调函数包裹数据,在src中进行调用,实现了跨域。
1.分类
100-199 提示信息 – 表示请求正在处理
200-299 成功 – 表示请求正常处理完毕
300-399 重定向 – 要完成请求必须进行更进一步的处理
400-499 客户端错误 – 请求有语法错误或请求无法实现
500-599 服务器端错误 – 服务器处理请求出错
浏览器的地址栏输入URL并按下回车。
浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
DNS解析URL对应的IP。
根据IP建立TCP连接(三次握手)。
HTTP发起请求。
服务器处理请求,浏览器接收HTTP响应。
渲染页面,构建DOM树。
关闭TCP连接(四次挥手)。