# 面试题(一)

  • Vue的组件传值的方式(8种)
    • 父传子:数组/对象形式,单向数据流(在子组件中改变prop会出现警告)
    • 子传父:联系发布订阅模式($emit,$on)讲一下,怎么实现一个发布订阅模式
  • 打包工具webpack,rollup,parcel分别适用于什么场景?
  • 如何理解 vue 响应式原理(2.0/3.0)?
  • computed和watcher的原理,有什么区别及应用场景?(Watcher,惰性)
  • 为什么 Vue3.0 采用了 proxy,有什么优势?
  • 说一下模块化的方案,CommonJs,AMD,CMD,ES Modules
  • 介绍一下 Vue 的 Virtual DOM 与 Diff 算法
  • 说一下 $nextTick 的原理
  • Vue 组件 data 为什么必须是函数 ?
  • webpack插件主要是做什么的,常用的有哪些,自己写过webpack插件吗
  • webpack 热更新原理
  • js执行会阻塞DOM树的解析和渲染,那么css加载会阻塞DOM树的解析和渲染吗?css会阻塞js吗

# Vue的组件传值的方式(8种)

# props的写法

  • props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

    你可以基于对象的语法使用以下选项:

    • type:可以是下列原生构造函数中的一种:StringNumberBooleanArrayObjectDateFunctionSymbol、任何自定义构造函数、或上述内容组成的数组。会检查一个 prop 是否是给定的类型,否则抛出警告。
    • defaultany 为该 prop 指定一个默认值。如果该 prop 没有被传入,则换做用这个值。对象或数组的默认值必须从一个工厂函数返回。
    • requiredBoolean 定义该 prop 是否是必填项。在非生产环境中,如果这个值为 truthy 且该 prop 没有被传入的,则一个控制台警告将会被抛出。
    • validatorFunction 自定义验证函数会将该 prop 的值作为唯一的参数代入。在非生产环境下,如果该函数返回一个 false 的值 (也就是验证失败),一个控制台警告将会被抛出。你可以在这里 (opens new window)查阅更多 prop 验证的相关信息。
props: {
        detail: {
            type: Object,
            default: () => {},
            required: true
        },
        age: {
          type: Number,
          default: 0,
          required: true,
          validator: function (value) {
            return value >= 0
          }
        }
}

// 子组件向父组件传值时,一个事件可以传递多个参数

// 子组件点击事件
click(params1, params2) {
    this.$emit('selectDay', params1, params2)
}

// 父组件获取值
// <child  @selectDay="fun"></child>
fun (params1, params2) {
   console.log(params1, params2) 
}

# 打包工具webpack,rollup,parcel分别适用于什么场景?

webpack:一般用于大型复杂应用

rollup:一般用于开发第三方类库,例如 vue 源码就是用 rollup 打包的

parcel:轻量快捷,一般用于自己写一些小的 demo

# 如何理解 vue 响应式原理?

# computed和watcher的原理,有什么区别及应用场景?(Watcher,惰性)

一、 计算属性(computed)

computed 是计算属性,它会根据你所依赖的数据动态显示新的计算结果

通过计算出来的属性不需要调用直接可以在 DOM 里使用

<div id='app'>
  <p>我是原始值: {{ message }}</p>
  <p>我是计算属性的值: {{ computedMessage }}</p> 
</div>

    <script>
        let app = new Vue({
            el:'#app',
            data: {
                message: 'hello'
            },
            computed: {
                computedMessage: function () {
                    return this.message.split('').reverse().join('')
                }
            }      
        })
    </script>

计算属性的set操作

// set 操作
computedMessage: {
  get() {
		return
  }
  set() {
		return
  }
}

二、methods同样可实现 (没有缓存,会计算多次)

<div id="app">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage() }}"</p>
  <p>Computed reversed message: "{{ reversedMessage() }}"</p>
  <p>Computed reversed message: "{{ reversedMessage() }}"</p>
  <p>Computed reversed message: "{{ reversedMessage() }}"</p>
  <p>Computed reversed message: "{{ reversedMessage() }}"</p>
</div>

<script>
const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  methods: {
    // 计算属性的 getter
    reversedMessage: function () {
      // this 指向 Vue 实例
      return this.message.split('').reverse().join('')
    }
  }
})
</script>script>

三、监听属性(watch)

侦听属性 watch 用来观察和响应数据的变动。

    <div id="demodiv">      
        <input type="text" v-model="text">
        {{text}}         
    </div>

    <script>
        new Vue({
            el:"#demodiv",
            data:{
                    text:"abcdefg"
            },
            watch:{
                text(newval,oldval){
                    console.log(newval+'========'+oldval)
                }
            }
        })
    </script>

(1)首先表明,computed 和 watch 都属于 watcher,在initState中初始化,一共有三种还有一种是渲染 Watcher 在 mount 中初始化,本质上都依赖于 Vue 的响应式原理。

(2)computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值,其内部通过dirty属性标记计算属性是否需要重新求值。而 watch 则是当数据发生变化便会调用执行函数。

(3)computed: 当某个数据需要随着(依赖于)另一个数据的变动而作出改变时,这时候你需要使用计算属性。 watch: 当某个数据发生变化时,需要对这个数据的变化进行反应(进行一系列操作),这时候你需要使用侦听属性。methods: 与计算属性不同的是,每次读取数据时,都是计算一遍,除非你不需要缓存,否则这样做需要大量的性能开销。

# watch的两个参数

  • immediate:代表立即执行,而不是等监听对象改变再执行
  • deep:深度监听,对象的属性改变也可以监听的到

可以参考这篇文章 (opens new window)

// 两种写法
watch: {
    'user.firstName': function (newValue, oldValue) {
        this.user.fullName = this.user.firstName + '' + this.user.lastName
    }
}

watch: {
    'user': {
        handler: function (newValue, oldValue) {
        	this.user.fullName = this.user.firstName + '' + this.user.lastName
    	  },
        deep: true,
        immediate: true
    }
}

# 三种类型的 Watcher 对象

  • 没有静态方法,因为 $watch 方法中要使用 Vue 的实例

  • Watcher 分三种:计算属性 Watcher、用户 Watcher (侦听器)、渲染 Watcher

    • 计算属性 Watcher 在 initComputd 中创建
    • 用户 Watcher (侦听器) 在 Vue.$watch 中创建
    • 渲染 Watcher 在 mountComponent 中创建
  • Watcher内部实现是一样的,src/core/observer/watcher.js中,并且每一个Watcher都有一个id

  • 创建顺序:计算属性 Watcher、用户 Watcher (侦听器)、渲染 Watcher

  • vm.$watch()

    • src\core\instance\state.js
Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): Function {
    // 获取 Vue 实例 this
    const vm: Component = this
    if (isPlainObject(cb)) {
      // 判断如果 cb 是对象执行 createWatcher
      return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {}
    options.user = true
    // 创建用户 watcher 对象
    const watcher = new Watcher(vm, expOrFn, cb, options)
    // 判断 immediate 如果为 true
    if (options.immediate) {
      // 立即执行一次 cb 回调,并且把当前值传入
      try {
        cb.call(vm, watcher.value)
      } catch (error) {
        handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
      }
    }
    // 返回取消监听的方法
    return function unwatchFn () {
      watcher.teardown()
    }
  }

# 为什么 Vue3.0 采用了 proxy,有什么优势?

# 说一下模块化的方案,CommonJs,AMD,CMD,ESModules

# 介绍一下 Vue 的 Virtual DOM 与 Diff 算法

# 说一下 $nextTick 的原理

# Vue 组件 data 为什么必须是函数 ?

vue中data 是可以直接写成一个对象的,但这是保证这个组件不会被复用的情况下

由于组价的复用,其实是创建多个vue实例,如果data中仍然是只是一个对象,那么其实创建出来的实例保持的都是对同一个对象的引用。

所以我们通过 一个 函数执行返回了一个新的全新的数据对象。

# webpack插件主要是做什么的,常用的有哪些,自己写过webpack插件吗

# webpack 热更新原理

# js执行会阻塞DOM树的解析和渲染,那么css加载会阻塞DOM树的解析和渲染吗?css会阻塞js吗

  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  • css加载会阻塞后面js语句的执行
最后更新时间: 11/2/2023, 2:16:23 PM