前端常见面试题之vue2

文章目录

  • 一、vue2中父子组件嵌套时的生命周期执行顺序是怎样的
    • 1. 挂载阶段
    • 2. 更新阶段
    • 3. 销毁阶段
  • 二、vue组件通讯方式有哪些
    • 1. 父子组件通讯方式
      • (1). Props 和 Events:父组件通过props向子组件传递数据,子组件通过事件向父组件传递数据。
      • (2). `$parent` 和 `$children`:通过访问父组件的`$children`属性或子组件的`$parent`属性来实现通讯。
      • (3). `$refs`:使用ref属性获取子组件的实例,从而实现父组件和子组件之间的通讯。
    • 2. 兄弟组件通讯方式
      • 事件总线event bus:利用Vue实例作为事件总线,通过`$on`和`$emit`方法进行事件的监听和触发,实现兄弟组件之间的通讯。示例代码如下所示:
    • 3. 祖孙组件通讯
      • 依赖注入provide / inject
    • 4. vuex
  • 三、自定义v-model
  • 四、$nextTick
  • 五、插槽
  • 六、动态、异步组件
    • 1. 动态组件
    • 2. 异步组件
  • 七、keep-alive
  • 八、mixin
    • 1. 基本使用
    • 2. 存在问题
  • 九、谈谈你对MVVM的理解
  • 十、vue是如何实现响应式的
  • 十一、 vue2在使用Object.defineProperty实现数据响应式的时候有哪些缺点
  • 十二、谈谈你对虚拟dom的理解
  • 十三、使用虚拟dom描述一个dom树

一、vue2中父子组件嵌套时的生命周期执行顺序是怎样的

在Vue2中,组件的生命周期钩子函数包括:

  1. beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用
  2. created:实例已经创建完成之后被调用
  3. beforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用
  4. mounted:el 被新创建的 vm.$el 替换,并挂载到实例上后调用该钩子函数
  5. beforeUpdate:数据更新时调用,在数据更新之前和重新渲染之前被调用
  6. updated:由于数据改变导致的虚拟 DOM 重新渲染和打补丁时调用
  7. beforeDestroy:在实例被销毁之前调用。此时实例仍然完全可用
  8. destroyed:Vue 实例被销毁后调用

生命周期函数执行的顺序如下:

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted
  5. beforeUpdate
  6. updated
  7. beforeDestroy
  8. destroyed

举例说明:

new Vue({el: '#app',data: {message: 'Hello, Vue!'},beforeCreate: function() {console.log('beforeCreate');},created: function() {console.log('created');},beforeMount: function() {console.log('beforeMount');},mounted: function() {console.log('mounted');},beforeUpdate: function() {console.log('beforeUpdate');},updated: function() {console.log('updated');},beforeDestroy: function() {console.log('beforeDestroy');},destroyed: function() {console.log('destroyed');}
});

以上代码创建了一个Vue实例,当页面加载时会依次输出如下内容:

beforeCreate
created
beforeMount
mounted

1. 挂载阶段

父子组件的生命周期执行顺序是先执行父组件的生命周期钩子函数,然后再执行子组件的生命周期钩子函数

只看created和mounted钩子,执行顺序是

父组件created
子组件created
子组件mounted
父组件mounted

前四个生命周期的执行顺序是:

  1. 父组件beforeCreate
  2. 父组件created
  3. 父组件beforeMount
  4. 子组件beforeCreate
  5. 子组件created
  6. 子组件beforeMount
  7. 子组件mounted
  8. 父组件mounted

举例说明:

//父组件
<template><div><child-component></child-component></div>
</template><script>
import ChildComponent from './ChildComponent';export default {components: {ChildComponent},beforeCreate() {console.log('父组件beforeCreate');},created() {console.log('父组件created');},beforeMount() {console.log('父组件beforeMount');},mounted() {console.log('父组件mounted');}
}
</script>//子组件
<template><div>Child Component</div>
</template><script>
export default {beforeCreate() {console.log('子组件beforeCreate');},created() {console.log('子组件created');},beforeMount() {console.log('子组件beforeMount');},mounted() {console.log('子组件mounted');}
}
</script>

当上述代码中的父组件和子组件被渲染到页面时,控制台输出的日志顺序将是:

父组件beforeCreate
父组件created
父组件beforeMount
子组件beforeCreate
子组件created
子组件beforeMount
子组件mounted
父组件mounted

2. 更新阶段

在Vue2中,父组件和子组件的生命周期钩子在更新阶段执行的顺序是:

  1. 父组件beforeUpdate钩子
  2. 子组件beforeUpdate钩子
  3. 子组件updated钩子
  4. 父组件updated钩子

举例说明:

假设有一个父组件Parent和一个子组件Child,在Parent组件中包含了Child组件。当父组件的数据发生变化时,更新触发事件会导致更新阶段的生命周期钩子执行顺序如下:

<template><div><Child :msg="message"></Child><button @click="updateMessage">更新消息</button></div>
</template><script>
import Child from './Child.vue';export default {components: {Child},data() {return {message: 'Hello'};},methods: {updateMessage() {this.message = 'World';}},beforeUpdate() {console.log('父组件beforeUpdate');},updated() {console.log('父组件updated');}
};
</script>

Child组件的代码如下:

<template><div><p>{{ msg }}</p></div>
</template><script>
export default {props: ['msg'],beforeUpdate() {console.log('子组件beforeUpdate');},updated() {console.log('子组件updated');}
};
</script>

当点击按钮更新消息时,控制台输出的结果为:

父组件beforeUpdate
子组件beforeUpdate
子组件updated
父组件updated

可以看到,在更新阶段,父组件的beforeUpdate钩子会在子组件的beforeUpdate钩子之前执行,而子组件的updated钩子会在父组件的updated钩子之前执行。这是因为Vue在更新过程中是从父组件开始,然后递归更新子组件。

3. 销毁阶段

在Vue2中,父子组件的生命周期钩子函数在销毁前和销毁阶段执行顺序如下:

  1. Parent beforeDestroy
  2. Child beforeDestroy
  3. Child destroyed
  4. Parent destroyed

例如,假设有一个父组件Parent和一个子组件Child,它们的生命周期钩子函数如下:

Parent组件:

export default {// 父组件的生命周期钩子函数beforeDestroy() {console.log('Parent beforeDestroy');},destroyed() {console.log('Parent destroyed');}
}

Child组件:

export default {// 子组件的生命周期钩子函数beforeDestroy() {console.log('Child beforeDestroy');},destroyed() {console.log('Child destroyed');}
}

当父组件Parent销毁时,执行顺序如下:

  1. Parent beforeDestroy
  2. Child beforeDestroy
  3. Child destroyed
  4. Parent destroyed

可以看到,在父组件销毁前,会先执行子组件的beforeDestroy钩子函数,然后再执行子组件的destroyed钩子函数。最后再执行父组件的destroyed钩子函数。

二、vue组件通讯方式有哪些

1. 父子组件通讯方式

在Vue2中,父子组件之间的通讯方式有以下几种:

(1). Props 和 Events:父组件通过props向子组件传递数据,子组件通过事件向父组件传递数据。

示例:
父组件:

<template><child-component :message="parentMessage" @notify="handleNotify"></child-component>
</template><script>
export default {data() {return {parentMessage: 'Hello from parent'}},methods: {handleNotify(message) {console.log(message)}}
}
</script>

子组件:

<template><div @click="sendMessage">{{message}}</div>
</template><script>
export default {props: ['message'],methods: {sendMessage() {this.$emit('notify', 'Message from child')}}
}
</script>

(2). $parent$children:通过访问父组件的$children属性或子组件的$parent属性来实现通讯。

示例:
父组件:

<template><child-component></child-component>
</template><script>
export default {methods: {sendMessage() {this.$children[0].$emit('notify', 'Message from parent')}}
}
</script>

子组件:

<template><div @click="sendMessage">{{message}}</div>
</template><script>
export default {data() {return {message: 'Hello from child'}},methods: {sendMessage() {this.$parent.$emit('notify', 'Message from child')}}
}
</script>

(3). $refs:使用ref属性获取子组件的实例,从而实现父组件和子组件之间的通讯。

示例:
父组件:

<template><child-component ref="child"></child-component>
</template><script>
export default {methods: {sendMessage() {this.$refs.child.sendMessage('Message from parent')}}
}
</script>

子组件:

<template><div @click="sendMessage">{{message}}</div>
</template><script>
export default {data() {return {message: 'Hello from child'}},methods: {sendMessage(message) {console.log(message)}}
}
</script>

2. 兄弟组件通讯方式

事件总线event bus:利用Vue实例作为事件总线,通过$on$emit方法进行事件的监听和触发,实现兄弟组件之间的通讯。示例代码如下所示:

// eventBus.js
import Vue from 'vue';
export const EventBus = new Vue();// ComponentA.vue
<script>
import { EventBus } from './eventBus';export default {methods: {sendMessage() {EventBus.$emit('message', 'Hello from Component A');}}
};
</script>// ComponentB.vue
<script>
import { EventBus } from './eventBus';export default {data() {return {message: ''};},mounted() {EventBus.$on('message', (message) => {this.message = message;});}
};
</script>

这里,ComponentA发送一个名为message的事件,并传递一个消息。ComponentB监听这个事件,然后更新自身的message属性。

3. 祖孙组件通讯

依赖注入provide / inject

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。

可以使用provide和inject选项来实现依赖注入。provide选项用于向子组件提供依赖项,inject选项用于在子组件中注入依赖项。

例如,以下是一个简单的示例,在父组件中使用provide提供一个变量,然后在子组件中使用inject注入该变量:

// ParentComponent.vue
export default {provide: {message: 'Hello from parent'}
}
// ChildComponent.vue
export default {inject: ['message'],created() {console.log(this.message); // 输出 'Hello from parent'}
}

在这个示例中,父组件使用provide选项提供了一个名为message的变量,而子组件通过inject选项注入了这个变量,并在created钩子函数中打印了该变量的值。

需要注意的是,provide和inject选项不会对子组件进行响应式处理,也不支持嵌套对象的属性访问。因此,在使用依赖注入时,建议将数据存在在原始数据中,而不是在嵌套对象中。

4. vuex

Vuex是一个专门为Vue.js应用程序开发的状态管理模式,它集中存储管理应用的所有组件的状态,并以功能强大和易于维护的方式进行统一管理和更新。

vuex的五大核心概念

  1. State:状态存储在Vuex的中央存储中,用于存储组件之间共享的数据。

  2. Getter:用于从state中获取数据,类似于计算属性,可以对数据进行进一步的处理。

  3. Mutation:用于修改state中的数据,必须是同步函数。

  4. Action:用于处理异步操作,可以包含任意异步操作,并且可以通过commit来调用mutation来修改state中的数据。

  5. Module:用于将store分割成模块,每个模块拥有自己的state、getters、mutations、actions。Vuex允许将store分割成模块,更好地管理代码结构。

一些Vuex的主要功能和用途包括

  1. 状态存储:Vuex可以让你在一个集中的地方管理所有组件的状态。通过store对象,可以存储所有需要共享和管理的状态,确保应用中的每个组件都可以访问和更新这些状态。

  2. 状态共享:Vuex使得在不同组件之间共享状态变得更加容易。通过store对象中存储的状态,可以在需要的时候在任何组件中获取和修改状态,而不需要通过props或事件来传递状态。

  3. 状态响应:Vuex提供了一种响应式的状态管理机制,它能够追踪状态的变化并实时更新应用的视图。当状态发生变化时,依赖于该状态的组件会自动重新渲染,从而保持状态和视图的同步。

状态共享,举例

要使用Vuex实现在组件之间通信,首先需要在Vue应用中安装并配置Vuex。然后在store中定义state、mutations、actions和getters等属性,以及要共享的数据。

举例说明如下:

假设有两个组件ComponentA和ComponentB,它们之间需要共享一个变量count。首先在store中定义一个state并初始化count的值:

// store.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const store = new Vuex.Store({state: {count: 0},mutations: {increment(state) {state.count++;}},actions: {increment({ commit }) {commit('increment');}},getters: {getCount(state) {return state.count;}
});export default store;

然后在ComponentA和ComponentB中分别使用mapState和mapActions来获得state和actions,并进行相应的操作:

// ComponentA.vue
<template><div><p>ComponentA Count: {{ count }}</p><button @click="increment">Increment Count</button></div>
</template><script>
import { mapState, mapActions } from 'vuex';export default {computed: {...mapState(['count'])},methods: {...mapActions(['increment'])}
}
</script>
// ComponentB.vue
<template><div><p>ComponentB Count: {{ count }}</p><button @click="increment">Increment Count</button></div>
</template><script>
import { mapState, mapActions } from 'vuex';export default {computed: {...mapState(['count'])},methods: {...mapActions(['increment'])}
}
</script>

这样就实现了在ComponentA和ComponentB之间共享count变量,并通过点击按钮来增加count的功能。当一个组件中修改了count值,另一个组件中的count值也会同步更新。

三、自定义v-model

在Vue2中,自定义组件的v-model用于实现父子组件之间的双向绑定。通过使用v-model,可以简化在父组件中传递数据和监听子组件事件的操作。

在自定义组件中,可以使用配置项model来自定义v-model的属性名称和事件名称。下面是一个简单的示例:

// MyComponent.vue<template><input :value="value" @input="$emit('update:value', $event.target.value)">
</template><script>
export default {props: ['value'],model: {prop: 'value',event: 'update:value'}
}
</script>

在上面的示例中,配置项model中prop指定了v-model绑定的属性名称为value,event指定了v-model绑定的事件名称为update:value。这样在使用MyComponent组件时,可以直接使用v-model来实现双向绑定:

// ParentComponent.vue<template><MyComponent v-model="message"></MyComponent>
</template><script>
import MyComponent from './MyComponent.vue'export default {data() {return {message: 'Hello, Vue!'}},components: {MyComponent}
}
</script>

在上面的示例中,父组件ParentComponent中使用了MyComponent组件,并通过v-model绑定了message变量,实现了父子组件之间的双向绑定。当在子组件中输入内容时,父组件中的message变量会自动更新。

四、$nextTick

$nextTick是Vue实例的一个方法,用于在DOM更新之后执行代码,确保代码在DOM更新之后执行。

在Vue.js中,如果需要在更新DOM之后操作DOM元素,可以使用$nextTick方法来执行相应的代码。这样可以确保操作是在DOM更新完成之后进行的,避免出现DOM操作不及时导致的bug。

举个例子,假设有一个Vue组件中有一个按钮,点击按钮后改变按钮的背景颜色。但是由于Vue的更新并不是立即的,而是异步的,所以直接在按钮点击事件中修改样式可能无法生效。此时可以使用$nextTick方法来确保按钮背景颜色的修改在DOM更新之后执行:

methods: {changeColor() {this.buttonColor = 'blue';this.$nextTick(() => {document.getElementById('myButton').style.backgroundColor = 'blue';});}
}

五、插槽

插槽是一种特殊的语法,使父组件可以向子组件传递内容。插槽具有以下几个重要的知识点:

  1. 默认插槽:父组件可以在子组件中通过 <slot> 标签传递内容,而这些内容会被插槽内部的默认内容所替换。
    示例:
// Parent.vue
<template><child><p>内容会插入到默认插槽中</p></child>
</template>// Child.vue
<template><div><slot></slot></div>
</template>
  1. 具名插槽:父组件可以在子组件中使用具名插槽,以便给插槽传递多个不同的内容。
    示例:
// Parent.vue
<template><child><!--  简写 #header   --><template v-slot:header> <h2>头部内容</h2></template><template v-slot:footer><p>底部内容</p></template></child>
</template>// Child.vue
<template><div><slot name="header"></slot><slot name="footer"></slot></div>
</template>
  1. 作用域插槽:父组件可以在插槽内部传递数据给子组件,子组件可以获取这些数据并渲染到插槽中。
    示例:
<!-- ParentComponent.vue -->
<template><ChildComponent><template  v-slot:default="props"><p>{{ props.message }}</p></template></ChildComponent>
</template><script>
import ChildComponent from './ChildComponent.vue';export default {components: {ChildComponent},data() {return {message: 'Hello from ParentComponent'}}
}
</script>
<!-- ChildComponent.vue -->
<template><div><slot :message="message"></slot></div>
</template><script>
export default {props: {message: String}
}
</script>

在上面的例子中,ParentComponent通过在ChildComponent中使用作用域插槽传递了message数据。ChildComponent接收到message数据后,在插槽中使用slot-scope接收props对象,然后可以在插槽中使用props对象的message属性。

六、动态、异步组件

1. 动态组件

动态组件在Vue2中用于根据不同的条件或状态动态地渲染不同的组件。这样可以根据需要动态加载不同的组件,提高了代码的灵活性和可维护性。

举例来说,假设我们有一个网页,其中有一个切换按钮,根据用户的点击来动态地展示不同的组件内容。我们可以使用动态组件来实现这个功能。具体的代码示例如下:

<template><div><button @click="currentComponent = 'ComponentA'">显示组件A</button><button @click="currentComponent = 'ComponentB'">显示组件B</button><component :is="currentComponent"></component></div>
</template><script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';export default {data() {return {currentComponent: 'ComponentA'}},components: {ComponentA,ComponentB}
}
</script>

在上面的代码中,我们定义了两个按钮,分别用来显示组件A和组件B。当用户点击按钮时,currentComponent 的值会发生变化,从而动态加载不同的组件。这样可以根据用户的交互动态地展示不同的内容。

2. 异步组件

在Vue中,异步组件是一种特殊的组件,其内容是在组件被渲染时才进行加载。这意味着当页面加载时,异步组件的代码不会立即被加载,而是在需要的时候再进行加载,从而提高页面加载速度和性能。

异步组件的使用可以通过Vue的import()函数或者Webpack的import语法来实现。当需要使用异步组件时,可以将组件定义为一个方法,在需要时进行加载。

举例来说,下面是一个简单的异步组件的示例:

// 异步组件定义
const AsyncComponent = () => ({component: import('./AsyncComponent.vue')
});// 在组件中使用异步组件
new Vue({el: '#app',components: {'async-component': AsyncComponent},template: `<div><async-component></async-component></div>`
});

在这个示例中,AsyncComponent是一个异步组件,其内容在需要显示时才会被加载。通过使用异步组件,可以有效地提高页面加载速度,特别是在页面含有大量组件的情况下。

七、keep-alive

在Vue中,keep-alive是一个抽象组件,用于缓存不活动的组件实例,以便在组件切换时保留其状态或避免重新渲染。这在使用动态组件或路由时特别有用,能提升应用的性能和用户体验。

keep-alive组件接收两个属性includeexclude,用于指定哪些组件需要被缓存或排除缓存。当被包裹的组件切换时,keep-alive会检查其属性,并根据条件来保留或丢弃缓存实例。

下面是一个示例,演示如何在Vue中使用keep-alive组件:

<template><div><keep-alive><router-view :key="$route.fullPath"></router-view></keep-alive></div>
</template><script>
export default {name: 'App',
}
</script>

在上面的示例中,keep-alive组件包裹了router-view,通过设置<router-view :key="$route.fullPath"></router-view>key属性为动态的路由路径,实现每个路由页面的缓存和切换。这样在路由之间切换时,之前访问过的路由页面会被保留在缓存中,避免重复渲染和重新加载。

总之,keep-alive是一个非常有用的组件,在需要保留组件状态或避免重新渲染时,可以用来提升应用的性能和用户体验。

当一个组件被包裹后,组件将会缓存并保留其状态,避免在组件销毁后重新渲染。这意味着,即使组件被切换隐藏,组件的生命周期钩子函数也不会再执行,只有第一次加载时才执行。下面通过一个例子来说明组件被包裹后的生命周期。

假设我们有一个名为ComponentA的组件,它被包裹。当该组件首次加载时,会依次执行以下生命周期钩子函数:

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted

当我们切换到其他组件,ComponentA会被缓存并保留其状态。这时,再次回到ComponentA时,只有以下生命周期钩子函数会执行:

  1. activated
  2. deactivated

如果ComponentA被销毁,再次切换回来时,会重新执行以下生命周期钩子函数:

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted

通过包裹可以避免频繁的渲染和数据请求,提高页面性能和用户体验。

八、mixin

1. 基本使用

在Vue中,mixin是一种可重用的代码片段,允许在多个组件中共享相同的逻辑。使用mixin可以将组件中通用的属性、方法、生命周期钩子等提取出来,减少重复代码,提高代码的可维护性和重用性。

举例说明,假设我们有一个名为loadingMixin的mixin,用来处理组件的加载状态:

const loadingMixin = {data() {return {isLoading: false}},methods: {showLoading() {this.isLoading = true},hideLoading() {this.isLoading = false}}
}

然后我们可以在多个组件中使用这个mixin:

Vue.component('component1', {mixins: [loadingMixin],methods: {fetchData() {this.showLoading()// fetch datathis.hideLoading()}}
})Vue.component('component2', {mixins: [loadingMixin],methods: {fetchData() {this.showLoading()// fetch datathis.hideLoading()}}
})

通过使用mixin,我们可以避免在每个组件中重复编写加载状态的代码,提高了代码的复用性和可维护性。

2. 存在问题

Vue中的mixin存在一些问题,其中包括:

  1. 命名冲突:当两个mixin中有相同的选项时,会发生命名冲突,导致无法准确地确定最终结果。

  2. 不可预期的属性覆盖:当不同的mixin中定义了同名的属性或方法时,可能会覆盖掉原组件中的同名属性或方法,导致意外的行为。

  3. 难以追踪问题:由于mixin可以在多个组件中被引用,当出现问题时,可能需要逐一检查各个组件和mixin,增加了调试的复杂性。

举例说明:

假设有一个用户信息的mixin和一个订单信息的mixin,在不同的组件中都引用了这两个mixin。如果用户信息的mixin中定义了一个名为userInfo的属性,而订单信息的mixin中也定义了一个同名的属性,那么在组件中使用时可能会遇到属性覆盖的问题,导致无法获取到正确的用户信息或订单信息。这种情况下就会出现不可预期的行为,增加了调试和维护的难度。因此,在使用mixin时需要格外小心,避免出现命名冲突和属性覆盖的问题。

九、谈谈你对MVVM的理解

大家可以看看这篇谈谈你对mvc和mvvm的理解

十、vue是如何实现响应式的

可以看看这篇vue响应式原理

十一、 vue2在使用Object.defineProperty实现数据响应式的时候有哪些缺点

使用Object.defineProperty实现数据响应式在某些方面会有一些缺点,主要包括:

  1. 对象只能监听已经存在的属性,无法监听新增属性。
  2. 对象监听的属性是针对对象的指定属性,无法监听整个对象的变化。
  3. 需要在初始化属性时就进行数据响应式的处理,不能动态添加响应式属性。
  4. 对象的嵌套属性需要单独进行监听处理,如果对象嵌套层级较深会比较麻烦。
  5. 不支持数组的监听,需要额外处理数组的操作。
  6. 性能较差,每个属性都需要添加getter和setter,会影响整体性能。

因此,虽然Object.defineProperty可以实现简单的数据响应式,但在实际开发中可能会遇到一些限制和性能问题。Vue3采用Proxy来实现数据响应式,解决了Object.defineProperty的一些缺点。

十二、谈谈你对虚拟dom的理解

可以看看这篇虚拟dom笔记

优化时间diff算法的时间复杂度到O(n)

  1. 只比较同一层级,不跨级比较
  2. tag不相同,则直接删掉重建,不再深度比较
  3. tag和key,两者都相同,则认为是相同节点,不再深度比较

十三、使用虚拟dom描述一个dom树

假设我们有以下的DOM树结构:

<div id="app"><h1>Hello, Virtual DOM!</h1><ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>
</div>

对应的虚拟DOM树结构可以描述为:

{type: 'div',props: {id: 'app',children: [{type: 'h1',props: {children: 'Hello, Virtual DOM!'}},{type: 'ul',props: {children: [{type: 'li',props: {children: 'Item 1'}},{type: 'li',props: {children: 'Item 2'}},{type: 'li',props: {children: 'Item 3'}}]}}]}
}

在这个虚拟DOM树中,每个节点都有type字段表示节点类型,props字段存储节点的属性和子节点信息。可以看到整个DOM树的结构被用对象表示出来,便于在页面渲染时快速进行比对和更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/692717.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[word] word定时自动保存功能的作用是什么 #知识分享#学习方法#媒体

word定时自动保存功能的作用是什么 word定时自动保存功能的作用是什么 这是word提供的一个保护用户文档的功能&#xff0c;一般情况下是为了预防在未知原因的情况下&#xff0c;用户电脑关闭&#xff0c;或者不小关掉Word&#xff0c;导致正在使用的文档丢失&#xff0c;给用户…

nginx的功能以及运用

nginx与apache的对比 nginx优点 nginx使用场景 编译安装nginx过程 1.先清空opt文件夹 2.关闭防火墙&#xff0c;关闭防护 3 安装依赖包&#xff0c;可以通过本地yum去安装 首先就是挂载&#xff0c;随后切换到配置文件中修改 4本地配置文件配置内容 5 随后安装环境包 yum -y …

洛谷 P1241 括号序列 (Java)

洛谷 P1241 括号序列 (Java) 传送门&#xff1a;P1241 括号序列 题目&#xff1a; 括号序列 题目描述 定义如下规则&#xff1a; 空串是「平衡括号序列」若字符串 S S S 是「平衡括号序列」&#xff0c;那么 [ S ] \texttt{[}S\texttt] [S] 和 ( S ) \texttt{(}S\textt…

uniapp运动课程健身打卡系统微信小程序

考虑到实际生活中在我来运动管理方面的需要以及对该系统认真的分析,将系统分为小程序端模块和后台管理员模块&#xff0c;权限按管理员和用户这两类涉及用户划分。 (a) 管理员&#xff1b;管理员使用本系统涉到的功能主要有&#xff1a;首页、个人中心、用户管理、课程类别管理…

Python爬虫之图形验证码的识别

爬虫专栏&#xff1a;http://t.csdnimg.cn/WfCSx 前言 目前&#xff0c;许多网站采取各种各样的措施来反爬虫&#xff0c;其中一个措施便是使用验证码。随着技术的发展&#xff0c;验证码的花样越来越多。验证码最初是几个数字组合的简单的图形验证码&#xff0c;后来加入了英…

Java学习25--自定义异常

自定义异常class 自定义异常通常要配合 override “toString”命令&#xff0c;其实质是一个会报错的method,像一个交通违章通报LED&#xff0c;但何时被触发&#xff0c;如何算是违反交通&#xff0c;并不会在此class定义。 自定义异常class的步骤&#xff1a; 自建个异常类…

机械臂目标抓捕学习笔记【1】

基于概率量度的机械臂视觉伺服目标捕获运动规划方法 目录 基于概率量度的机械臂视觉伺服目标捕获运动规划方法期望轨迹序列状态转移函数系统测量值模型线性化卡尔曼滤波状态估计代价函数-闭环反馈轨迹误差方差误差几何化表示到达概率计算 参考文献&#xff1a;《[1]祁若龙,邵健…

直接查看电脑几核芯几线程的方法

之前查看电脑几核芯几线程时都是点击 此电脑->属性->设备管理器->处理器 但是这样并不能判断是否有多线程 譬如这里&#xff0c;是2核芯2线程还是4核芯&#xff1f; 实际上&#xff0c;打开任务管理器后点击性能查看核芯线程数即可 所以示例这台电脑是4核芯而不是2…

鸿蒙实战:ArkTs 开发一个鸿蒙应用

学习过的 ArkTs 知识点&#xff0c;一步一步开发一个小的鸿蒙应用示例&#xff0c;涉及到 ArkTs 语法、注解 Entry 、 Component、state、路由、生命周期、Prop、 Link 、常用组件的使用等等知识点。 要开发一个鸿蒙应用&#xff0c;首先我们需要知道 系统是如何找到页面的启…

仪表板展示|DataEase看中国:历年研究生报考数据分析

背景介绍 在信息时代的浪潮中&#xff0c;研究生教育作为培养高层次专业人才的重要通道&#xff0c;不断吸引着广大毕业生和在职人士的关注。今天我们结合2018年&#xff5e;2024年的研究生报考数据&#xff0c;以数字为镜&#xff0c;深入了解近年来研究生培养态势。 本文将…

YOLOv8改进 | 进阶实战篇 | 利用辅助超推理算法SAHI推理让小目标无所谓遁形(支持视频和图片)

欢迎大家订阅我的专栏一起学习YOLO! 一、本文介绍 本文给大家带来的是进阶实战篇,利用辅助超推理算法SAHI进行推理,同时官方提供的版本中支持视频,我将其进行改造后不仅支持视频同时支持图片的推理方式,SAHI主要的推理场景是针对于小目标检测(检测物体较大的不适用,…

IP详细地理位置查询:技术原理与应用实践

IP地址是互联网上设备的唯一标识&#xff0c;在网络安全、个性化服务等领域具有重要意义。通过IP详细地理位置查询&#xff0c;可以获取到IP地址所在地的具体信息&#xff0c;为网络管理、定位服务等提供支持。IP数据云将深入探讨IP详细地理位置查询的技术原理、应用实践以及相…

Linux——进程替换

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、进程程序替换1、替换原理2、替换函数3、函数解释4、命名理解 二、用例测试1、execl测试2、…

Hive中几种常见的表

Hive的表类型主要有&#xff1a;内部表&#xff08;受控表/管理表&#xff09;、外部表、临时表、分区表、分桶表。 1. 内部表&#xff08;管理表&#xff09; 默认创建的表都是管理表/内部表&#xff0c;表数据默认存储在warehouse目录中&#xff0c;在加载数据的过程中&…

GB 23864-2023 防火封堵材料检测

防火封堵材料是指具有防火&#xff0c;防烟功能&#xff0c;用于密封或填塞建筑物、构筑物以及各类设施中的贯穿孔洞、环形缝隙及建筑缝隙&#xff0c;便于更换且符合有关性能要求的材料。 GB 23864-2023 柔性有机堵料等防火封堵料的理化性能&#xff1a; 测试项目 测试方法 …

【PX4-AutoPilot教程-TIPS】Gazebo仿真环境昏暗的解决办法即Ubuntu系统安装NVIDIA显卡驱动方法

Gazebo仿真环境昏暗的解决办法即Ubuntu系统安装NVIDIA显卡驱动方法 分析原因手动安装方法&#xff08;推荐&#xff09;自动安装方法检查是否安装成功Gazebo仿真环境前后对比 分析原因 具体原因为&#xff1a;大多数情况是因为显卡性能不足&#xff0c;Gazebo自动关闭了灯光和…

说一下JVM创建对象的流程?

一、类加载检查。 在实例化一个对象的时候&#xff0c;JVM 首先会去检查目标对象是否已经被加载并初始化了。如果没有&#xff0c;JVM 需要立刻去加载目标类&#xff0c;然后调用目标类的构造器完成初始化。然后初始化的过程&#xff0c;主要是对目标类里面的静态变量、成员变…

【CANoe示例分析】EthernetTC8Test

1、工程路径 C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 15.3.89\Ethernet\Test\EthernetTC8Test 在CANoe软件上也可以打开此工程:File|Help|Sample Configurations|Ethernet Testing|TC8Test(Ethernet) 2、示例目的 TC8示例是作者本人使用最多的CANo…

三、滑动窗口问题

3、无重复字符的最长子串&#xff08;中等&#xff09; 题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输…

代码随想录day26--贪心基础

什么是贪心 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优 举个例子&#xff1a; 有一堆钞票&#xff0c;可以拿走十张&#xff0c;如果想要达到最大的金额&#xff0c;应该怎么拿&#xff1f; 指定每次拿最大的&#xff0c;最终结果就是拿走最大数额的…