vue
https://baijiahao.baidu.com/s?id=1630858302456359651&wfr=spider&for=pc(40面试题)
https://www.cnblogs.com/theblogs/p/10575845.html(ES6)
https://segmentfault.com/a/1190000016344599(vue经典面试题)
1、data() 为何一定是函数
为了每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响
类别引用数据类型
Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了;
JavaScript只有函数构成作用域(注意理解作用域,只有函数{}构成作用域,对象的{}以及if(){}都不构成作用域),data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。
2、watch和computed的区别
computed支持缓存,依赖数据发生改变,重新计算,不支持异步
watch不支持缓存,数据变,直接触发,支持异步
- computed
支持缓存,只有依赖数据发生改变,才会重新进行计算
不支持异步,当computed内有异步操作时无效,无法监听数据的变化
watch
不支持缓存,数据变,直接会触发相应的操作;
支持异步
3、深度监听
watch监听时设置deep:true
// 监听一个对象
watch:{
obj:{ //监听的对象
deep:true, //深度监听设置为 true
handler:function(newV,oldV){
console.log('watch中:',newV)
}
}
}
// 监听一个对象的某个属性
watch:{
'obj.name':{
deep:true,
handler:function(newV,oldV){
console.log('watch中:',newV)
}
}
}
// 利用computed监听一个对象的某个属性
computed:{
name(){
return this.obj.name;
}
},
watch:{
name(newV){
console.log('watch中name为:',newV)
}
}
4、vue生命周期的应用场景:
beforeCreate 可以在此时加一些loading效果,在created时进行移除
created 需要异步请求数据的方法可以在此时执行,完成数据的初始化
mounted 当需要操作dom的时候执行,可以配合$.nextTick 使用进行单一事件对数据的更新后更新dom
updated 当数据更新需要做统一业务处理的时候使用
5、nextTick
- 理解
延迟函数,在dom更新完再执行,源码是Promise 或setTimeout(fn, 0) - 应用
1)在created生命周期中进行dom操作,例如created中通过$refs获取子组件的属性或方法。(相当于mounted里操作)
2)在某个数据改变引起的dom更新后 再进行的操作
补充
调用 setTimeout 函数会在一个时间段过去后在队列中添加一个消息。这个时间段作为函数的第二个参数被传入。如果队列中没有其它消息,消息会被马上处理。但是,如果有其它消息,setTimeout 消息必须等待其它消息处理完。因此第二个参数仅仅表示最少的时间,而非确切的时间。
零延迟 (Zero delay) 并不是意味着回调会立即执行。在零延迟调用 setTimeout 时,其并不是过了给定的时间间隔后就马上执行回调函数。其等待的时间基于队列里正在等待的消息数量。也就是说,setTimeout()只是将事件插入了任务队列,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证回调函数一定会在setTimeout()指定的时间执行。
6、父子交互
// 父组件访问子组件(有dom之后)
<child-com ref="child"></child-com>
this.$refs.child.属性/方法
// 子组件访问父组件
this.$parent.属性/方法
// 父传子:
props // 单向数据流
// 子传父:
子
this.$emit('emitfun','传过去的值')
父
<parent @emitfun="ffun"/> // 用一个自身的fun来监听子组件暴露出来的fun
methods: {
ffun(val) {
console.log(val);
}
}
7、vuex
- 创建store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
name:'missssssss',
},
mutations: {
M_NAME: (state, name) => {
state.name = name
},
},
actions: {
A_M_NAME({ commit },name){
commit('M_NAME', name)
}
},
getters:{
}
})
export default store
- 使用
<script>
import { mapState, mapActions, mapGetters } from "vuex";
export default {
name: "user",
data() {
return {};
},
computed: {
...mapState({
name: state => state.name
})
},
methods: {
...mapActions(["A_M_NAME"]),
gai1() {
this.A_M_NAME("gogoging");
}
}
};
</script>
————————————————
参考链接:https://blog.youkuaiyun.com/m0_37805167/article/details/79655346
js
原型链的理解
实例对象和原型之间组成的链,就是用来实现共享属性和继承的
继承
我们平常一般用的是通过new一个对象出来,实现了继承。
so 理解继承之前先要理解new做了什么。
new做的工作分为三步:
1、创建类的实例。这步是把一个空的对象的 proto 属性设置为 F.prototype 。
2、初始化实例。函数 F 被传入参数并调用,关键字 this 被设定为该实例。
3、返回实例。
用JS代码实现一下new
function New (f) {
var n = { '__proto__': f.prototype }; /*第一步*/
return function () {
f.apply(n, arguments); /*第二步*/
return n; /*第三步*/
};
}
例子检测
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
print: function () { console.log(this.x, this.y); }
};
var p1 = new Point(10, 20);
p1.print(); // 10 20
console.log(p1 instanceof Point); // true
var p2 = New (Point)(10, 20);
p2.print(); // 10 20
console.log(p2 instanceof Point); // true
继承的进化
// 父类:
function funpar(){
this.a = 'aa'
this.fun1 =function(){
console.log('fun1')
}
}
//父类原型链:
funpar.prototype.hello ='hello'
funpar.prototype.sayhello=function(){
console.log(this.hello)
}
par = new funpar() //父类的某个对象
console.log('par:',par)
//继承要在创建子对象时进行
// 方法一:对象冒充
var funchi = function(){
this.c = 'cc'
this.cfun = function(){
console.log('cfun')
}
this.mm=funpar; //继承是 创建函数 的继承
this.mm();
delete this.mm;
}
chi = new funchi()
console.log('chi:',chi)
// 方法二:call(),apply()
var funchi2 = function(){
this.c2 = 'c2'
this.c2fun = function(){
console.log(this.c2)
}
funpar.call(this,'aa')
// funpar.apply(this,['aa'])
}
var chi2 = new funchi2()
console.log('chi2',chi2)
//方法三:原型链继承:
var funchi3 = function(){
funchi3.prototype = new funpar()
// funchi3.prototype = funpar.prototype ?有何区别?
}
var chi3 = new funchi3()
console.log('chi3',chi3)
// 方法四:混合继承
//继承实例
var funchi4 =function(){
funpar.call(this)
}
//继承原型链
funchi4.prototype = new funpar()
var chi4 = new funchi4()
console.log('chi4',chi4)
// 方法五:寄生组合继承(要会手写)
//一样先继承实例
function funchi5(){
funpar.call(this)
this.cc5 = 'cc5'
}
//寄生的方法继承原型链
(function(){
var ls = function(){} //创建一个空函数
ls.prototype = funpar.prototype; //将父原型寄生给空函数
funchi5.prototype = new ls() //子函数通过继承空函数达到继承父函数的目的
})()
var chi5 = new funchi5()
console.log('chi5:',chi5)
推荐使用寄生组合继承,因为它解决了前面几种继承方式的:只能继承实例,只能继承原型,不能多继承,要创建出两份实例 等缺点。
闭包的理解和应用
有权访问另一函数作用域参数的函数
局部变量会常驻在内存中;可以避免使用全局变量,防止全局变量污染;
会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
es6的理解和使用
- Promise
是异步编程的一种解决方案,比传统的解决方案——回调函数和事件监听——更合理和更强大。
持续更新中。。。