指令v-if v-show有什么不同?

v-if 和 v-show都是Vue中的指令而且都可以用来控制模板的渲染。

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS( display:none) 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

写出 normalizeProps 方法

在 Vue 中,我们在使用 props 的时候有两种写法,一种是使用字符串数组

1
2
3
const ChildComponent = {
props: ['some-data1''someData2']
}

另外一种是使用对象语法

1
2
3
4
5
6
7
8
9
const ChildComponent = {
props: {
some-data1: Number,
someData2: {
type: String,
default: ''
}
}
}

请写出规范化props的方法 normalizeProps (options, vm),将两种形式规范成同一种形式

1
2
3
4
5
6
7
8
9
10
11
const ChildComponent = {
props: {
someData1: {
type: Number
},
someData2: {
type: String,
default: ''
}
}
}

答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function camelize (str) {
return str.replace(/-(\w)/g, (_, c) => c ? c.toUpperCase() : '')
}
function isPlainObject (obj) {
return Object.prototype.toString.call(obj) === '[object Object]'
}
function toRawType (value) {
return Object.prototype.toString.call(value).slice(8, -1)
}
function normalizeProps (options, vm) {
const props = options.props
if (!props) return
const res = {}
let i, val, name
if (Array.isArray(props)) {
i = props.length
while (i--) {
val = props[i]
if (typeof val === 'string') {
name = camelize(val)
res[name] = { type: null }
} else if (process.env.NODE_ENV !== 'production') {
warn('props must be strings when using array syntax.')
}
}
} else if (isPlainObject(props)) {
for (const key in props) {
val = props[key]
name = camelize(key)
res[name] = isPlainObject(val)
? val
: { type: val }
}
} else if (process.env.NODE_ENV !== 'production') {
warn(
`Invalid value for option "props": expected an Array or an Object, ` +
`but got ${toRawType(props)}.`,
vm
)
}
options.props = res
}

为什么 data 需要写成一个函数?

通过函数返回数据对象,保证了每个组件实例都有一个唯一的数据副本,避免了组件间数据互相影响。

为什么我们能够使用 props 初始化 data 中的数据

因为 data 选项是在初始化的时候才求值的,而 props 的初始化先于 data 选项的初始化。

生命周期钩子是否可以写成数组形式?如果可以那么将以什么顺序执行?如果不可以为什么不可以?

可以,因为在合并生命周期钩子函数 mergeHook 中判断了子组件钩子函数为数组的情况。钩子函数将按顺序执行。

vm.$options.parent和 vm.$parent 有什么不同?

vm.$options.parent 指的是当前实例 components 下注册的子组件的父实例
vm.$parent指的是当前实例的非抽象父实例

vue源码中大量用到了 Object.create(null),Object.create(null) 和 new Object() 及对象直接量{}有什么不同?

Object.create() 方法的内部实现简单来说是这样的:

1
2
3
4
5
6
7
8
function create(o){
var t = typeof o;
if (t != "object" && t != "function")
throw TypeError();
function f(){};
f.prototype = o;
return new f();
}

这样一来 Object.create(null) 创建的新对象的原型对象就是null,也就是说它没有任何原型方法;
而直接使用{}创建新对象,其实是等同于new Object(),它是继承了Object的,是有原型方法的。

Vue 是通过什么方法来实现数据响应系统的?

Vue 数据响应系统的原理的核心是通过 Object.defineProperty 函数将数据对象的属性转换为访问器(getter/setter)属性,从而使得我们能够拦截到属性的读取和设置。

哪些数据变化情况无法被 Vue 的响应式系统观测到,应该如何处理?

  1. Vue 不能检测到以下变动的对象
    1. 当你添加或删除对象的属性时,例如:
1
2
3
4
5
6
7
8
9
10
var vm = new Vue({
data: {
a: 1,
items: ['a', 'b'. 'c']
}
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的
  1. Vue 不能检测到以下变动的数组
    1. 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
    2. 当你修改数组的长度时,例如:vm.items.length = newLength

可以使用全局方法 Vue.set(target, key, value) 方法向嵌套对象添加响应式属性/直接设置一个数组的值,或者使用实例方法 vm.$set(target, key, value)

可以使用全局方法 Vue.delete(target, key) 方法向嵌套对象删除响应式属性/删除数组元素,或者使用实例方法 vm.$delete(target, key)

修改数组的长度可以通过 vm.items.splice(newLength) 实现。

注意 Vue.set(target, key, value)Vue.delete(target, key) 并不能为根数据对象添加/删除属性也不能为 Vue 实例添加/删除属性。

vue不同组件之间如何通信?

可以通过使用一个空的Vue实例作为中间事件栈,然后使用 $emit $on 传递数据。