前端 题

本文深入解析Vue.js的关键特性,包括data函数的作用、watch与computed的区别、深度监听的实现方式、生命周期的应用场景、nextTick的原理与使用、组件间通信方法及Vuex的状态管理。同时,探讨了JavaScript原型链、继承机制、闭包应用、ES6的Promise等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
    是异步编程的一种解决方案,比传统的解决方案——回调函数和事件监听——更合理和更强大。

持续更新中。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值