2022知识点

2 篇文章 0 订阅

2022知识点


主要参考:
https://blog.csdn.net/qq_44182284/article/details/111191455
https://es6.ruanyifeng.com/
https://blog.csdn.net/weixin_38351681/article/details/101052383

VUE

vue优点

轻量级; 简单易学;双向绑定;组件化;数据、视图、结构分离;虚拟DOM; 渐进式框架;运行速度更快

vue2.x双向绑定原理

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来给各个属性添加getter、setter并劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。
实现:

  1. 实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者。
  2. 实现一个指令解析器Compile,对每个元素节点的指令进行扫描解析,根据指令模板替换数据以及绑定相应的更新函数。
  3. 实现一个watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图。

vue2.x响应式原理

数据改变时,视图会重新渲染,匹配更新为最新的值。
Object.defineProperty()为对象的每个属性设置getter;setter,每个声明的属性都有一个专属的依赖收集器。
当页面使用某个属性时,触发getter,页面watcher就会被放到属性依赖收集器中,数据变化时,通知更新。
当数据变化时,触发setter,数据会遍历自己的依赖收集器,逐个通知watcher视图开始更新。

vue3.x响应式原理

用Proxy代替Object.defineProperty。
通过Proxy(代理):拦截对象中任意属性的变化,包括属性的读写,属性的添加,属性的删除等。
通过Reflect(反射):对源对象的属性进行操作。

Proxy与Object.defineProperty对比

  1. Proxy可以直接监听对象而非属性
  2. Proxy可以直接监听数组的变化,数组的某些方法(push、unshift和splice)Object.defineProperty监听不到。
  3. Proxy有13种拦截方法
  4. Proxy返回的是一个新对象,可直接操作新对象达到目的。Object.defineProperty只能遍历对象属性直接修改。
  5. 响应式是惰性的。Object.defineProperty递归遍历对象,Proxy不能监听内部深层次的属性变化,因此它的处理方式是在getter中去递归响应式,按需响应,减少性能消耗。
  6. Proxy作为新标准将受到浏览器厂商重点持续的性能优化,即新标准的性能红利。Object.defineProperty兼容性好(支持IE9)

vue中v-if和v-for

vue2.x:v-for优先级高于v-if
vue3.x:v-if优先级高于v-for
不要一起使用,性能消耗问题

vue异步渲染

vue是组件级更新,组件数据变化,组件就更新,一更新就重新渲染性能不高,因此采用异步渲染(核心:nextTick),即本轮数据更新后,再去异步更新视图。而不是每当有数据更新,就立即更新视图。
参考:https://blog.csdn.net/sunnnnh/article/details/117746160

  1. 数据变化时,通过notify通知watcher进行更新操作;
  2. 通过subs[i].update依次调用watcher的update(未更新视图);
  3. 将watcher放到队列中,在queueWatcher会根据watcher的id进行去重(多个属性依赖一个watcher),如果队列中没有该watcher就会将该watcher添加到队列中(未更新视图);
  4. 通过nextTick异步执行flushSchedulerQueue方法刷新watcher队列(更新视图);

vue单向数据流

参考:vue单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
注意:在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

vue初始化过程(new Vue(optinos))都做了什么

  1. 处理组件配置项
    - 初始化根组件时进行了选项合并操作,将全局配置合并到根组件的局部配置上
    - 初始化每个子组件时做了一些性能优化,将组件配置对象上的一些深层次属性放 到 vm.$options 选项中,以提高代码的执行效率

  2. 初始化组件实例的关系属性,比如 $parent、$children、$root、$refs 等

  3. 处理自定义事件

  4. 调用 beforeCreate 钩子函数

  5. 初始化组件的 inject 配置项,得到 ret[key] = val 形式的配置对象,然后对该配置对象进行响应式处理,并代理每个 key 到 vm 实例上

  6. 数据响应式,处理 props、methods、data、computed、watch 等选项

  7. 解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上

  8. 调用 created 钩子函数

  9. 如果发现配置项上有 el 选项,则自动调用 $mount 方法,也就是说有了 el 选项,就不需要再手动调用 $mount 方法,反之,没提供 el 选项则必须调用 $mount

  10. 接下来则进入挂载阶段

vue生命周期

vue2生命周期
注意:所有的生命周期钩子自动绑定 this 上下文到实例中,不能使用箭头函数来定义一个生命周期方法,因为箭头函数绑定了父上下文。
1.beforeCreate:在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
2.created:在实例创建完成后被立即调用。实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。挂载阶段还没开始,$el property 目前尚不可用。
3.beforeMount:在挂载开始之前被调用:相关的 render 函数首次被调用。(该钩子在服务器端渲染期间不被调用。)
4.mounted:实例被挂载后调用,这时 el 被新创建的 vm. $el 替换了。不保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm. $nextTick。(该钩子在服务器端渲染期间不被调用。)
5.beforeUpdate:数据更新时调用,发生在虚拟 DOM 打补丁之前。适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。(该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。)
6.updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。不会保证所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm. $nextTick。(该钩子在服务器端渲染期间不被调用。)
7.activated:被 keep-alive 缓存的组件激活时调用。(该钩子在服务器端渲染期间不被调用。)
8.deactivated:被 keep-alive 缓存的组件停用时调用。(该钩子在服务器端渲染期间不被调用。)
9.beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。(该钩子在服务器端渲染期间不被调用。)
10.destroyed:实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。(该钩子在服务器端渲染期间不被调用。)
11.errorCaptured:当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。你可以在此钩子中修改组件的状态,因此在捕获错误时,在模板或渲染函数中有一个条件判断来绕过其它内容就很重要;不然该组件可能会进入一个无限的渲染循环。

vue3选项式API生命周期
注意:组合式 API 中的 setup() 钩子会在所有选项式 API 钩子之前调用
1.beforeCreate:同vue2。会在实例初始化完成、props 解析之后、data() 和 computed 等选项处理之前立即调用。
2.created:同vue2
3.beforeMount:同vue2。组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。
4.mounted:同vue2。这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用,或是在服务端渲染应用中用于确保 DOM 相关代码仅在客户端被调用。组件在以下情况下被视为已挂载:所有同步子组件都已经被挂载。(不包含异步组件或 树内的组件);其自身的 DOM 树已经创建完成并插入了父容器中。注意仅当根容器在文档中时,才可以保证组件 DOM 树也在文档中。
5.beforeUpdate:同vue2。
6.updated:同vue2。
7.activated:同vue2。
8.deactivated:同vue2。
9.beforeUnmount:同vue2的beforeDestroy。
10.unmounted:同vue2的destroyed。可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。一个组件在以下情况下被视为已卸载:其所有子组件都已经被卸载;所有相关的响应式作用 (渲染作用以及 setup() 时创建的计算属性和侦听器) 都已经停止。11.errorCaptured:同vue2。错误可以从以下几个来源中捕获:组件渲染、事件处理器、生命周期钩子、setup() 函数、侦听器、自定义指令钩子、过渡钩子。
12.renderTracked(dev only):在一个响应式依赖被组件的渲染作用追踪后调用。(这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。)
13.renderTriggered(dev only):在一个响应式依赖被组件触发了重新渲染之后调用。(这个钩子仅在开发模式下可用,且在服务器端渲染期间不会被调用。)
14.serverPrefetch(SSR only):当组件实例在服务器上被渲染之前要完成的异步函数。如果这个钩子返回了一个 Promise,服务端渲染会在渲染该组件前等待该 Promise 完成。这个钩子仅会在服务端渲染中执行,可以用于执行一些仅在服务端才有的数据抓取过程。

vue3组合式API生命周期钩子
同vue3选项式API生命周期,不包含(beforeCreate、created),每个钩子由回调函数方式注册,例如onMounted()。这些 API 都应该在组件的 setup() 阶段被同步调用。

生命周期errorCaptured错误传播规则

errorCaptured错误传播规则
1.默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报。
2.如果一个组件的继承或父级从属链路中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。
3.如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的 config.errorHandler。
4.一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说“这个错误已经被搞定了且应该被忽略”。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler。

vue组件和vue实例中的data

vue组件其实就是一个vue实例。
JS中的实例是通过构造函数来创建的,每个构造函数都可以new出多个实例,每个实例上都会继承原型上的方法和属性。
vue的data数据是vue原型上的属性,数据存于内存。vue为保证每个实例的data的独立性,规定必须使用函数而不是对象。对象是内存地址引用,会造成组件间数据相互影响。定义为函数,函数中的this指向是当前实例本身。
new Vue的实例时不会被复用的,因此不存在对象引用问题。

vue中data属性可以和methods方法同名吗

可以。
methods方法名会被data属性覆盖,控制台也会报错,但不影响执行。
因为源码定义的initState函数内部执行顺序是:props -> methods -> data -> computed -> watch。

vue中computed和methods

同:作为模板的数据显示,都实现了响应的功能。
异:

  1. computed是响应式的,methods并非响应式。
  2. 调用方式不一样,computed定义的成员像属性一样访问,methods定义的成员必须以函数形式调用。
  3. computed是带缓存的,只有其引用的响应式属性发生改变时才会重新计算,而methods里的函数在每次调用时都要执行。
  4. computed中的成员可以只定义一个函数作为只读属性,也可以定义get/set变成可读写属性。

vue中watch

用来监听数据变化。

  1. 监听的数据后面可以写成对象的形式,包含handler方法、immediate和deep。
  2. immediate表示在watch中首次绑定时是否执行handler,true则执行。
  3. 为了发现对象内部值的变化,可以在选项参数中指定 deep: true,即深度监听。注意监听数组的变更不需要这么做。

vue注册全局方法

  1. vue.prototype
Vue.prototype.m_method = function (){ ... }
  1. mixin
const myMethod = {
 methods: { m_method () { ... } } 
} export defaullt myMethod
// main.js
import myMethod from './mymethod'
Vue.mixin(myMethod);
  1. plugin
exports.install = function (Vue, options) {
 Vue.prototype.m_method = function (){ ... }
};
// main.js
import myMethod from './mymethod'
Vue.use(myMethod);

虚拟DOM

参考:https://blog.csdn.net/weixin_44231864/article/details/115264217
虚拟DOM本质就是一个普通的JS对象,用于描述视图的界面结构。
在vue中,每个组件都有一个render函数,每个render函数都会返回一个虚拟DOM树,这也意味着每个组件都对应一颗虚拟DOM树。

为什么需要虚拟DOM

在vue中,渲染视图会调用render函数,这种渲染不仅发生在组件创建时,也发生在视图依赖的数据更新时。真实DOM的创建、更新、插入等操作会带来大量的性能消耗,从而极大的降低渲染效率。因此,vue在渲染时使用虚拟DOM来替代真实DOM,通过新/旧DOM树对比,只更新变化的真实DOM,从而达到提高渲染效率的目的。

虚拟DOM如何转换为真实DOM

当组件实例首次渲染时,先生成虚拟DOM树,然后根据虚拟DOM创建真实DOM,并把真实DOM挂载到页面上。此时,虚拟DOM便对应一个真实的DOM。
当组件受响应式数据变化的影响,需重新渲染时,会重新调用render函数,创建一个新的虚拟DOM树,新/旧树对比(diff算法),找到最小更新量,再更新必要的真实DOM节点(pach算法),以此保证对真实DOM的最小改动。

模板和虚拟DOM的关系

vue框架中有一个compile模块,主要负责将模板转换为render函数,而render函数调用后将得到虚拟DOM。
两步:1. 将模板字符串转换为AST(Abstract Syntax Tree抽象语法树);2. 将AST转换为render函数
若使用传统的引入方式,则编译发生在组件第一次加载时,即运行时编译。若在vue-cli的默认配置下,编译发生在打包时,即模板预编译。
编译是一个机器耗费性能的操作,预编译可有效提高运行时性能,且由于运行时不再需要编译,vue-cli打包时会排除vue中的compile模块,以减少打包体积。
模板的存在仅为开发方便,vue最终运行时需要的是render函数而不是模板,因此,模板中的各种语法,在虚拟DOM中都不存在,它们都会变成虚拟DOM的配置。

虚拟DOM中key的作用

key是虚拟DOM对象的标识,在更新显示时起重要作用。vue会根据新数据生成的虚拟DOM,再进行新/旧DOM树对比。
对比规则:1. 旧树找到与新树相同的key,若没变则用之前的真实DOM,若变了则生成新的真实DOM再替换页面中的真实DOM。2. 旧树中未找到与新树相同的key,创建新的真实DOM渲染到页面。

index作为key可能引发的问题

使用元素自身的ID属性去指定渲染元素的key值有利于单个元素的重新渲染,若用index作为key,数据变化时会触发所有元素重新渲染。

vue中v-if和v-show

v-if:条件渲染,先判断条件,符合再渲染。
v-show:条件隐藏,先渲染,符合就显示,不符合就display:none;不显示但元素还在。

性能:

  1. v-if有更高的切换开销,v-show有更高的初始渲染开销
  2. 多种条件v-if更好
  3. v-show不支持<template>语法
  4. v-if每切换一次就走一次生命周期。v-show除了初始化渲染,其他时候不再走相关生命周期。

vue中的混入(mixins)

vue事件修饰符

vue插槽

默认插槽,具名插槽,作用域插槽。

  1. 默认插槽和具名插槽:父组件决定内容,子组件决定位置
  2. 具名插槽比默认插槽多了个name属性
  3. 作用域插槽:子组件决定内容,父组件传递数据,被<template>标签包裹

vue指令

vue自定义指令

vue组件通信

  1. 父子:props和emit(父通过props传入,子通过$emit()提交给父)
  2. 父子:$children和$parent
  3. 父传子孙:provider和inject(父定义provider方法return要分享的属性,子孙用inject接收指定的属性)
  4. 多层嵌套传递:$attrs和$listeners
  5. 父子兄弟跨级:eventBus.js(通过一个空的Vue实例作为中央事件总线,用它来emit触发事件和on来监听事件)
  6. 通信插件:PubSub.js
  7. vuex:vue的状态管理
  8. web store:localStorage和sessionStorage

vue中keep-alive

vue中权限控制

来自:https://cloud.tencent.com/developer/article/1794300
触发方式:页面加载触发、页面按钮触发。
四个方面:接口权限、按钮权限、菜单权限、路由权限。

接口权限:登录token。

按钮权限:

  1. v-if获取路由配置用户权限;
  2. 自定义鉴权指令,根据路由权限配置比较。

菜单权限:

  1. 菜单路由分离,菜单由后台返回(缺点:1. 新功能前后端都要改;2. 全局路由守卫判断);
  2. 菜单路由都由后台返回(缺点:1. 前后端配合要求高;2. 全局路由守卫判断)。

路由权限:

  1. 初始化挂在全部路由,并标记路由权限,跳转前校验(缺点:1. 路由过多性能不好;2. 全局路由守卫判断;3. 更新需重新编译;4. 菜单与路由耦合);
  2. 初始化只挂在不需要权限的路由,登陆后动态添加相应权限的路由(缺点:1. 全局路由守卫判断;2. 更新需重新编译;3. 菜单与路由耦合)

vue跨域

vue.config.js中配置

module.exports = {
    devServer: {
        open: true,
        host: '0.0.0.0',
        port: 8080,
        https: false,
        //以上的ip和端口是我们本机的;下面为需要跨域的
        proxy: {//配置跨域
            '/api': {
                target: 'http://192.168.0.10:8025',//这里后台的地址模拟的;应该填写你们真实的后台接口
                ws: true,
                changOrigin: true,//允许跨域
                pathRewrite: {
                    '^/api': ''//请求的时候使用这个api就可以
                }
            }
        }
    }
}

vue首屏优化

  1. 使用CDN,减少打包体积;
  2. 路由懒加载;
  3. 三方组件按需导入;
  4. nginx开启gzip打包压缩。

vue性能优化

参考:https://blog.csdn.net/Kiruthika/article/details/116612149

编码优化:

  1. 尽量减少data数据,data中的数据都会增加getter和setter,会收集对应的 watcher,这样就会降低性能;
  2. 如果数据只是用来渲染可以使用Object.freeze,可以将数据冻结起来,这样就不会增加getter和setter;
  3. v-if和v-for不要一起使用;
  4. 合理使用v-if和v-show;
  5. vue在v-for时给每项元素绑定事件需要用事件代理,节约性能;
  6. key保证唯一性,不要使用索引 (vue中diff算法会采用就地复用策略);
  7. SPA采用keep-alive缓存组件;
  8. 合理使用路由懒加载、异步组件;
  9. 尽可能拆分组件,来提高复用性、增加代码的可维护性,减少不必要的渲染;
  10. 数据持久化的问题,使用防抖、节流进行优化,尽可能的少执行和不执行;
  11. 尽量采用runtime运行时版本。

加载优化:1. 第三方插件按需加载;2. 滚动到可视区域动态加载;3. 图片懒加载。

用户体验:1. app-skeleton 骨架屏;2. app-shell app壳;3. pwa 可以实现H5的离线缓存,使用servicewor。

SEO 优化:1. 预渲染插件 prerender-spa-plugin;2. 服务端渲染 ssr。

打包优化:1. 使用 cdn 的方式加载第三方模块;2. 多线程打包 happypack;3. 抽离公共文件 splitChunks;4. sourceMap 优化。

缓存和压缩:1. 客户端缓存、服务端缓存;2. 服务端 gzip 压缩。

vue图片懒加载和预加载

懒加载:先显示默认图,再显示图片。
预加载:进入页面前把图片加载完成,进入页面后不会空白或加载慢,但首屏时间长。
本地图片预加载,动态接口返回的懒加载。

参考:https://www.jb51.net/article/203302.htm
懒加载:

  1. 在main.js里面进行引用
import VueLazyload from "vue-lazyload";
Vue.use(VueLazyload);
或者自定义
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif',
attempt: 1
})
  1. 组件内使用
<img v-lazy="loadImg" class="img-css" />

vue事件代理

<div @click="clickEvent">
	<div v-for='(item, index)' of 100 :key='index' :data-index='index'>{{item}}</div>
</div>
export default {
	methods: {
		clickEvent(e) {
			console.log(e.target.dataset);
		}
	 }
}

vue转场动画

vue css scope

css中没有局部样式的概念,vue脚手架实现了,即style标签添加scoped
scoped原理:vue通过postcss给每个DOM元素添加一个以data-开头的随机自定义属性实现的。

vue第三方ui样式库穿透

/deep/

vue配置全局样式

style-resources-leader

const path = require('path');
module.exports = {
    pluginOptions: {
        'style-resources-loader': {
            preProcessor: 'less',
            patterns: [path.resolve(__dirname, "src/assets/css/common.less")]
        }
    }
}

vue手机/PC适配

  1. postcss-pxtorem + fontsize
const baseSize = 16;
function setRem() {
  const scale = document.documentElement.clientWidth / 1920;
  if (document.documentElement.clientWidth > 750) {
    document.documentElement.style.fontSize = (baseSize * scale) + 'px';
  }
}
setRem();
window.addEventListener('resize', () => {
  setRem();
});
  1. lib-flexible.js
    主要应用于移动端,>540px后字体就不变了。

vue组件封装

https://blog.csdn.net/weixin_45820444/article/details/108494676
可提升项目开发效率,能够把页面抽象成多个独立模块,解决了开发效率低、难维护、复用性差等问题。

vue3与vue2区别

Vue3的Composition Api 与 Vue2的Options Api区别

Options Api:包含一个描述组件选项(data、methods、props等)的对象 options;API开发复杂组件,同一个功能逻辑的代码被拆分到不同选项 ;使用mixin重用公用代码,也有问题:命名冲突,数据来源不清晰;

Composition Api:vue3 新增的一组 api,它是基于函数的 api,可以更灵活的组织组件的逻辑;解决options api在大型项目中,options api不好拆分和重用的问题。

VUEX

vuex是什么

参考:https://www.cnblogs.com/wannacc-xx/p/13656219.html
vuex是专门为vue.js应用程序设计的状态管理工具。采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生改变,集中于MVC模式中的model层,规定所有数据操作必须通过action-mutation-statechange的流程来进行,再结合vue数据视图双向绑定来实现页面的展示更新。

vuex属性

vuex五个属性

vuex单向数据流

组件触发action -> action提交mutation -> mutation修改state -> 组件根据state或getter渲染页面

vuex命名空间

Vue Router

Router和Route

router是VueRouter的实例,相当于全局路由器对象,包含很多属性和子对象。
route相当于正在跳转的路由对象。

导航守卫

路由跳转

标签导航:<router-link :to="...">
编程式导航:router.push(...)

vue router和location跳转

a页面 => b页面 => c页面
location.herf = "",会刷新页面,新增历史记录,回退 c => b => a;
location.replace = "",会刷新页面,替换历史记录,回退 c => a;
history.pushState(""),无刷新,静态跳转;
router.push(""),使用diff算法,按需加载,减少DOM损耗,与history.pushState类似,尤其在history模式下。

路由传参

params传参:path:‘details/:id’ => to=“{details, params:{id:1}}”
query传参:path:‘details/’ => to=“{details, query:{id:1}}”

vue中动态路由(增删查)

vue路由懒加载

  1. import
// 将
// import UserDetails from './views/UserDetails'
// 替换成
const UserDetails = () => import('./views/UserDetails')
  1. resolve/require
routes: [{ path: '/users/:id', component: resolve => require['./views/UserDetails'], resolve}]
  1. 按组分块
const UserDetails1 = () => import('./views/UserDetails1')
const UserDetails2 = () => import('./views/UserDetails2')

vue <router-link>和<a>

<router-link>:不会跳转到新页面,不会重新渲染,减少DOM性能损耗;
<a>:跳转到另一页面,页面会重新加载,相当于打开一个网页。

vue-router mode

hash(浏览器默认) | history | abstract(node默认)

hash:1. 后面hash值的变化,不会导致浏览器向服务器发出请求,不发请求便不会刷新,每次hash值变化会触发hashchange事件;2. URL上有#。

history:1. 依赖H5 history API和服务器配置,利用H5新增的pushState()和replaceState()这两个方法应用于浏览器历史记录栈,在当前已有的back、forward、go基础上,提供了对历史记录修改的功能。只是执行修改时,虽该改变了RUL,但浏览器不会立即向后端发出请求;2. URL上无#;3. 子目录刷新404,需后台配置,如ngnix重定向:location / { try_files $uri $uri/ /index.html }。

Axios

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

  1. 从浏览器中创建 XMLHttpRequests
  2. 从 node.js 创建 http 请求
  3. 支持 Promise API
  4. 拦截请求和响应
  5. 转换请求数据和响应数据
  6. 取消请求
  7. 自动转换 JSON 数据
  8. 客户端支持防御 XSRF

AJAX

Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。ajax 不是新的编程语言,而是一种使用现有标准的新方法。ajax 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

参考:https://www.jb51.net/article/232340.htm
优点:1. 无刷新更新数据;2. 异步与服务器通信;3. 前后端负载平衡;4. 基于标准被广泛支持;5. 界面与应用分离。

缺点:1. 不能使用back和history功能,即对浏览器机制的破坏;2. 安全问题,ajax暴露了与服务器交互的细节;3. 对搜索引擎支持较弱;4. 破坏程序的异常处理机制;5. 违背了URL和资源定位的初衷;6. 不能很好的支持移动设备;7. 太多客户端造成开发成本。

JS

JS数据类型

值类型(基本类型):字符串(string)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol(ES6引入,表示独一无二的值)
引用类型:对象(Object)、数组(Array)、函数(Function)
BigInt(ES2020)

js中Null和Undefined

参考:https://www.ujcms.com/knowledge/470.html
Undefined:代表未定义,也就是不存在的。
Null:有值,是存在的,但是为空值。在语言层面,null是object,是一种特殊的空对象。如果把一个变量赋予null,则该变量原先指向的对象可以被GC回收,释放内存空间。当然也可以认为null是Null类型,这不影响实际的意义。

js原型和原型链

js原型:JS规定,每个函数都有一个prototype对象属性,其指向另一个对象(原型链上)prototype上的所有属性和方法,都会被构造函数的实例继承。我们可以把不变的公用属性和方法直接定义在prototype对象属性上。

js原型链:实例对象与原型之间的连接即原型链。_proto_属性是每个对象以及函数都隐含的一个属性,其所指向的是创建它的构造函数的prototype,原型链就是通过这个属性构建的。

pro._proto_ === Pro.prototype; // true
function Animals(){};
function Cats(){};
var a1 = new Animals();
Cats.prototype = a1;
var b1 = new Cats();
b1._proto_ === a1; // true
b1._proto_._proto_ === Animals.prototype; // true
b1._proto_._proto_._proto_ === Object.prototype; // true

js作用域

js中apply、call、bind

第一个参数:都是this的指向对象;
其他参数:
1.call的参数用逗号分隔,立即执行;
2.apply所有参数必须放在一个数组里,立即执行;
3.bind返回函数,参数与call一样,且必须调用才会执行。

js中this指向

var name = 'win1'; // 其实是window.name = 'win1';如果此段代码在vue中,则不是win1,是当前组件的name
function test(){
	var A = {
		name: 'A',
		sayHello: function(){ console.log(this.name); },
		sayBye: () => { console.log(this.name); },
		sayHi: function(){
			var s = () => console.log(this.name);
			return s;
		},
		child: {
			name: 'A1',
			sayNihao: () => { console.log(this.name); }
		}
	}
	
	A.sayHello(); // 指向父级,A
	A.sayBye(); // 指向最外层,win1	
	var sayHi = A.sayHi();
	sayHi(); // A
	A.child.sayNihao(); // 指向最外层,win1
	var B = {name: 'B'};
	A.sayHello.call(B); // B
	A.sayHello.call(); // win1
	sayHi.call(B);// A
	sayHi.call(); // A
}

try…catch…finally

  1. try/catch中存在return也会执行finally;
  2. catch异常会覆盖try异常,finally异常会覆盖catch异常;
  3. catch中return会覆盖try中return,finally中return会覆盖catch中return;
  4. finally中修改了try或者catch中return的变量但没有return并不会影响结果,因为结果已经先行存入栈中。

js中相等和严格相等

1.严格相等

  • 类型不同,不严格相等
  • 同为Null或Undefined,严格相等
  • Null与Undefined不严格相等
  • NaN与任何值不严格相等,包括自身
  • 同一基本类型,比较值
  • 同一引用类型,比较地址

2.相等

  • Null与Undefined自身相等且互等
  • NaN与任何值不相等,包括自身
  • 同一基本类型,字符串和布尔值都会转换成数值,比较值
  • 同一引用类型,对象转化成原始类型的值,比较值

判断JS数据类型的四种方式

参考:https://blog.csdn.net/qq_40138556/article/details/103922078

  1. typeof:typeof('2') // “string”
  2. instanceof: arr instanceof Array // true
  3. constructor: arr.constructor // ƒ Array() { [native code] }
  4. prototype: Object.prototype.toString.call(1) // [object Number]

js判断数组

  1. instanceof: arr instanceof Array
  2. constructor: arr.constructor == Array
  3. prototype: Object.prototype.toString.call(arr) === '[object Array]'
  4. prototype: arr.__proto__ === Array.prototype
  5. isPrototypeOf: Array.prototype.isPrototypeOf(arr)
  6. getPrototypeOf: Object.getPrototypeOf(arr) === Array.prototype
  7. Array.isArray: Array.isArray(arr)

JS Array对象

方法描述结果
concat()连接两个或更多的数组返回新数组
copyWithin()从数组的指定位置拷贝元素到数组的另一个指定位置中改变原数组
entries()返回数组的可迭代对象返回可迭代对象
every()检测数值元素的每个元素是否都符合条件返回bool
fill()使用一个固定值来填充数组改变原数组
filter()检测数值元素,并返回符合条件所有元素的数组返回新数组
find()返回符合传入测试(函数)条件的第一个数组元素返回元素或undefined
findIndex()返回符合传入测试(函数)条件的数组元素索引返回索引或-1
forEach()数组每个元素都执行一次回调函数不改变原数组
from()通过给定的对象中创建一个数组返回一个新数组
includes()判断一个数组是否包含一个指定的值返回bool
indexOf()搜索数组中的元素,并返回它所在的位置返回索引或-1
isArray()判断对象是否为数组返回bool
join()把数组的所有元素放入一个字符串返回新字符串
keys()返回数组的可迭代对象,包含原始数组的键(key)返回可迭代对象
lastIndexOf()搜索数组中的元素,并返回它最后出现的位置返回索引或-1
map()通过指定函数处理数组的每个元素返回新数组
pop()删除数组的最后一个元素返回删除的元素,改变原数组
push()向数组的末尾添加一个或更多元素返回新的长度,改变原数组
reduce()将数组元素计算为一个值(从左到右)返回一个值
reduceRight()将数组元素计算为一个值(从右到左)返回一个值
reverse()反转数组的元素顺序改变原数组
shift()删除并返回数组的第一个元素返回第一个元素,改变原数组
slice()选取数组的一部分返回新数组
some()检测数组元素中是否有元素符合指定条件返回bool
sort()对数组的元素进行排序改变原数组
splice()从数组中添加或删除元素改变原数组
toString()把数组转换为字符串返回新字符串
unshift()向数组的开头添加一个或更多元素返回新的长度,改变原数组
valueOf()返回数组对象的原始值不改变原数组

数组排序

数组去重

  1. 双层循环,值相同则跳过,内循环一轮结束无相同则push()新数组;
  2. 双层循环,值相同则splice(),i–, j–;
  3. indexOf+splice:单层循环,indexOf(),不等于当前索引则splice();
  4. indexOf:单层循环,indexOf(),等于当前索引则push()到新数组;
  5. indexOf+newArr:单层循环,newArr.indexOf(arr[i]),不存在则push()到新数组;
  6. filter+indexOf:arr.filter(function(val, index, self){return self.indexOf(val) === index;});
  7. some+newArr:newArr.some(val=>arr[i] === val;),不存在则push()到新数组;
  8. set:var newArr = Array.from(new Set(arr));
  9. forEach+includes+newArr:newArr.includes(item),不存在则push()到新数组;
  10. forEach+map:var map = new Map(); map.has(item) ,不存在则set()到map并push()到新数组;
  11. forEach+object:obj[item],不存在则obj[item] = ture;并push()到新数组;
    indexOf不能判断NaN可以判断undefined,includes和map都可以判断

js创建类

function Animal(name){
	this.animalName = name; // 属性
	this.sleep = function(){ console.log(this.animalName + ' sleep...'); }
}
Animal.prototype.eat = function(food ){ console.log(this.animalName + ' eat ' + food);}
// ES6引入class定义类,可看作是语法糖
class Animal{
	constructor(name){ this.animalName = name; } // this代表实例对象
	sleep(){ console.log(this.animalName + ' sleep...'); }
}
Animal === Animal.prototype.constructor; // true,即类的数据类型就是函数,类本身指向构造函数,类的所有属性方法都定义在prototype属性上。
const cat = new Animal('cat');
// 类必须有constructor方法,未定义则默认添加空方法,该方法默认返回实例对象,也可指定返回其他对象。
  1. 类和模块内部默认是严格模式;
  2. 类不存在提升,需先声明后使用;
  3. name属性
class Animal(){}; 
console.log(Animal.name) // Animal
  1. 方法前加*就表示该方法为Generator函数;
  2. this默认指向类实例;
  3. static方法不会被实例继承,直接通过类调用,即静态方法;
  4. 静态属性
class Animal{...}
Animal.age = 1;

// ES7
class Animal{ ... static age = 1; }
  1. 私有属性和方法(#)
class Animal{... #color = 'red'; #changeColor(){}}

js类的getter 和 setter

类中我们可以使用 getter 和 setter 来获取和设置值,getter 和 setter 都需要在严格模式下执行,使用的是 get 和 set 关键字。

class Animal {
  constructor(name) {
    this._animalName = name;
  }
  get animalName() {
    return 'hello'; // 可以return任何值
  }
  set animalName(value) {
    this._animalName= value;
  }
}
let cat = new Animal('cat');
cat.animalName = 'fish';
console.log(cat.animalName); // hello;

注意:

  1. 即使 getter 是一个方法,当你想获取属性值时也不要使用括号;
  2. 虽然 set 是一个方法,但需要不带括号;
  3. getter/setter 方法的名称不能与属性的名称相同;
  4. 很多开发者在属性名称前使用下划线字符 _ 将 getter/setter 与实际属性分开。

js类继承

原型链继承、构造继承、原型式继承、寄生继承、组合继承、寄生组合继承、ES6 extends 关键字(实现原理寄生组合继承)。

  1. 原型链继承
function Cat(){
	Cat.prototype = new Animal();
	Cat.prototype.animalName = 'cat';
}
var cat = new Cat();

优点:1. 基于原型链,子实例既是父类实例,也是子类实例;2. 父类在原型上新增的方法和属性都能被子类继承。
缺点:1. 不能多继承;2. 传参不方便,只能在继承时传参;3. 原型上的属性/方法被所有实例共享。

  1. 构造继承
    使用父类构造函数来增强子类实例,等于复制父类的实例给子类,没用原型。
function Cat(){
	Animal.call(this);
	this.animalName = 'cat';
}
var cat = new Cat();

优点:1. 可多继承;2. 传参方便,可创建时传参。
缺点:只能实现继承父类的属性和方法,不能继承原型链上的属性和方法,无法实现函数复用。

  1. 原型式继承
    创建一个函数,传入要继承的对象,内部创建空的子函数,再在子类函数外部将父对象赋值给子类函数原型,最后返回子类函数的new执行结果。
function Cat(Animal()){
	function TempCat(){}
	TempCat.prototype = Animal;
	return new TempCat();
}

优点:不用实例化父类,只是用TempCat创建了一个副本。
缺点:不能改动自己的原型(因为返回new已经实例化了),所以也不能复用。

  1. 寄生继承
    函数内调用原型式继承,赋值给一个对象,然后可自定义增加它的一些属性和方法。
function Cat(Animal()){
	function TempCat(){}
	TempCat.prototype = Animal;
	return new TempCat();
}
function Cat2(animal){
	let tempCat2 = Cat(animal);
	tempCat2.animalName = 'cat';
	tempCat2.age = 1;
	tempCat2.getAge = function(){ console.log(this.age); }
	return tempCat2;	
}

优点:在原型式继承的基础上,增强了对象。
缺点:多包了一层,即多执行一次函数,不能复用。

  1. 组合继承
    相当于原型链继承和构造继承的结合。通过调用父类构造函数继承父类的属性并保留传参的优点,然后通过将父类实例作为子类的原型,实现函数复用。
function Cat(){
	Animal.call(this);
	this.animalName = animalName || 'cat';	
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;	
var cat = new Cat();

缺点:调用了两次父类构造函数,生成了两份实例。

  1. 寄生组合继承
    组合继承的优化。通过寄生的方式,去掉父类的实例属性,这样,在调用两次父类构造时,不会初始化两次实例。
function Cat(){
	Animal.call(this);
	this.animalName = animalName || 'cat';	
}
(function(){
	var tempCat = function(){};
	tempCat.prototype = Animal.prototype;
	Cat.prototype = new tempCat();
})();	
var cat = new Cat();

缺点:实现复杂。

  1. extends(寄生组合式继承语法糖)
class Cat extends Animal{};

js命名空间

参考:https://blog.csdn.net/qq_43444478/article/details/109111446

  1. 单一全局变量
    例如JQuery的$。
var myApp = (function(){ function(){ ... } return { ... }})();
  1. 命名空间前缀
    没有减少全局变量数量。
var myApp_propA = {};
var myApp_propB = {};
function myApp_method(){}
  1. 对象字面量表示法
    可认为是包含一组键值对的对象,键也可是新的命名空间。
    可读性、可维护性、可扩展性强。
var myApp = {
	getInfo: function(){},
	models: {},
	views: { page: {}}
}
  1. 嵌套命名空间
    可以说是对象字面量模式的升级版,易读且有组织性,相对安全,不易冲突。
    嵌套过多会增加浏览器查询工作量。
var myApp = myApp || {};
myApp.routers = myApp.routers || {};
myApp.routers.test = myApp.routes.test || {};
// 可声明新的嵌套命名空间或属性作为索引属性
myApp['routers'] = myApp['routers'] || {};
  1. 立即调用的函数模式
    立即调用函数(IIFE)即匿名函数。
(function(namespace, undefined){
	var foo = "foo"; // 私有
	namespace.foobar = "foobar"; // 公共
	namespace.sayHello = function(){ say("hello World:"); }; // 公共
	function say(str){ console.log($`You said: {str}`); } // 私有
})(window.namespace = window.namespace || {});
  1. 命名空间注入
    IIFE的变体,注入方法和属性,this做命名空间代理。
    优点:可将功能行为应用到多个对象或命名空间。
var myApp = myApp || {};
myApp.utils = {};
(function(){
	var value = 5;
	this.getValue = function(){ return value; }
	this.tools = {}; // 定义新的子命名空间	
}).apply(myApp.utils);
(function(){ this.diagnose = function(){ return "diagnose"; }}).apply(myApp.utils.tools);

js闭包

闭包就是能读取其他函数内部变量的函数。

var add = (function(){
	var count = 0;
	return function(){ return count += 1; }
})();
add(); // 1
add(); // 2

js异步编程

1.回调;2. 事件监听;3. 发布/订阅;4. Promise

js Promise

三种状态:pending、resolved、rejected。
状态一旦转换完成,不能再次转换。
异步编程的解决方案。
缺点:1. 一旦新建就会立即执行,无法取消;2. 若不设置回调,promise内部抛出的错误不会反应到外部。
如何停止一个promise链:在要停止的promise链位置添加一个方法,返回用不执行的resolve或reject的promise,那么这个promise永远pending,所以不会向下then或catch。

Promise.cancel = Promise.stop = function(){ return new Promise(function(){})}

promise.all():ES6,按顺序执行输出,有reject即reject,全resolve才resolve,且reject不会等待其他是否执行完成。
promise.race():ES6, 返回最先改变的 Promise 实例的返回值,且不会等待其他是否执行完成。
Promise.allSettled():ES2020,全部执行完成才会结束。
Promise.any ():ES2021,有resolve即resolve,全reject即reject, 且resolve不会等待其他是否执行完成。与promise.all()刚好相反。

export和export default

参考:https://blog.csdn.net/weixin_44447255/article/details/120447223
相同点:

  1. 都可以用于导出常量、函数、文件、模块等;
  2. 都可以用import导入。

不同点:

  1. 一个js文件中export可以有多个,export default只能有一个;
  2. 使用export 导出时,在导入时要加上{},export default则不需要;
  3. 使用export default为模块指定默认输出,导入时只需要知道文件名即可;
  4. 使用export必须知道导出的变量或者函数等,导入时的变量名要一致。

js宏任务和微任务

宏任务:setTimeout、setInterval、Ajax、Dom事件。
微任务:Promise、async/await。
微任务先于宏任务执行。

js Math

js 随机数

二叉树遍历

参考:https://blog.csdn.net/qq_44588981/article/details/122869029

    A
  /   \
 B     F
  \    \
   C     G
  / \   /
 D   E H

先序:左右,ABCDEFGH
中序:左右,BDCEAFHG
后序:左右,DECBHGFA

js数组与树结构互转

参考:https://blog.csdn.net/sinat_17775997/article/details/121426748

// 数组转树
data.forEach(item => {
	map[item.id] = item;
})
data.forEach(item => {
	let parent = map[item.parentId];
	if (parent) {
		(parent.children || (parent.children = [])).push(item);
	} else {
		result.push(item);
	}
})
// 树转数组
while (queue.length !== 0) {
	let item = queue.shift();
	data.push({
		id: item.id,
		parentId: item.parentId,
		name: item.name
	})
	let children = item.children;
	if (children) {
		for (let i = 0; i < children.length; i++) {
			queue.push(children[i]);
		}
	}
}

js递归

  1. 12345…*n
function fn(n){
	if(n == 1) return 1;
	return n * fn(n - 1);
}
  1. 斐波那契函数(1,1,2,3,5,8,13,21…)
function fn(n){
	if(n == 1 || n == 2) return 1;
	return f(n -1) + f(n - 2);
}

js循环

for > forEach > for of > map > for in

let data = [
  { id: 0, name: 'nihao' },
  { id: 1, name: 'hello' }
]
let data2 = { id: 0, name: 'nihao' };
  1. for循环遍历数组
for(let i = 0; i < data.length; i++){
	console.log(data[i].name); // nihao hello
}
  1. forEach遍历数组。不支持的 continue 与 break,使用 return 语句实现;
data.forEach(item => {
	console.log(item.name); // nihao hello
});
  1. for…of 遍历对象和数组
for(let item of data){
	console.log(item.name); // nihao hello
}
for(let item of Object.keys(data2)){
	console.log(item); // id name
}
for(let item of Object.values(data2)){
	console.log(item); // 0 nihao
}
  1. map遍历数组,返回一个新数组
data.map(item => {
	console.log(item.name); // nihao hello
});
  1. for…in遍历对象和数组,不应该用于关注索引顺序的数组。
for(let item in data){
	console.log(data[item].name); // nihao hello
}
for(let item in data2){
	console.log(item); // id name
	console.log(data2[item]); // 0 nihao
}

JS和TS

  1. TS是JS的超集;
  2. TS需要静态编译,提供了强类型与更多面向对象的内容;
  3. TS是强类型语言,面向对象语言,JS是弱类型语言;
  4. TS最终编译为弱类型JS文件,基于对象的原生JS,再运行;
  5. 由微软牵头主导,主要来自C#。

JS各版本特性

参考:https://blog.csdn.net/weixin_40466351/article/details/117922690

HTML

语义化标签

就是具有语义的表情,可清晰地向我们展示它的作用和用途。
优点:1. 具有可读性,使文档结构清晰;2. 浏览器便于读取,利于SEO优化;3. 展现在页面中时,用户体验好;4. 便于团队开发维护。
举例:1. 标题h;2. 段落p;3. 格式化文本(加粗strong、倾斜en、下划线ins、删除线del);4. h5新增(header、footer、hgroup、nav、aside、section、article)

html页面渲染

参考:https://www.jianshu.com/p/50fca328667b
解析HTML -> 构建DOM树 -> DOM树+css构建渲染(render)树 -> 布局 -> 绘制 -> 重排reflow -> 重绘repaint。
绘制:背景色 -> 背景图 -> 边框 -> 子render节点 -> 轮廓
重排:改变影响到文档内容或结构时,或元素位置改变。

  1. DOM操作(元素增、删、改、顺序改变);
  2. 内容变化(表单域内文本变化);
  3. css属性的计算或改变;
  4. 增删样式表;
  5. 更改“类”的属性;
  6. 浏览器窗口操作(缩放、滚动);
  7. 伪类激活(悬停)。
    重绘:改变不影响元素位置的样式时(背景色、边框色、可见性)。

重排一定重绘,重绘不一定重排
优化:1. 多次改样式属性操作合并为一次操作;2. 需多次重排的元素,position设置为absolute或fixed;3. display:none和overflow:hidden会重排;4. visibility:hidden会重绘。

px、em、rem区别

script异步加载

asyncdefer
https://blog.csdn.net/qq_34629352/article/details/106192746

H5新特性

  1. 新元素
  2. web存储:localStorage、sessionStorage;
  3. webWorker:开启异步线程,window.postmessage可跨域传数据;
  4. websocket:全双工通信;
  5. 拖拽:drag、drop。

H5 WebSocket

Web存储

更多:H5 Web存储Cookie

  1. cookie、session参与服务器通信,localStorage、sessionStorage不参数服务器通信;
  2. cookie保存为字符串,session保存对象;
  3. cookie保存在客户端,session保存在服务端;
  4. session不能区分路径,同一用户访问一个网站期间,所有session在任何地方都可访问。cookie若设置了路径参数,那么同一网站不同路径下cookie互相访问不到;
  5. cookie存在本地硬盘或内存,在发送HTTP请求时会被放入请求头参与通信,每个cookie最大4K,每个域名可拥有的cookie数量因浏览器不同。客户端设置失效时间,不设置则关闭时清除;
  6. session:创建时会生成一个sessionid,被存储在cookie中,用来访问session,服务端设置失效时间,最大5M左右,比cookie安全;
  7. localStorage:永久存储,window对象,最大5M左右;
  8. sessionStorage:临时存储,关闭页面或浏览器时清除。同源窗口,刷新或新进同源另一页面数据仍在。同时“独立”打开不同窗口,即使是同一页面也不同。

CSS

css3新特性

  1. 选择器
  2. 盒模型(flex);
  3. 背景和边框(background-image、background-size、background-origin、background-clip、border-radius、box-shadow、border-image);
  4. 文字特效(text-shadow、box-shadow、text-overflow、word-wrap、word-break);
  5. 2D/3D转换(transform);
  6. 动画(@keyframes);
  7. 多列布局(column-count、column-gap、column-rule-style、column-rule-width、column-rule-color、column-rule、column-span、column-width);
  8. 用户界面(resize、box-sizing、outline-offset)。

box-sizing

content-box:默认值,等于width;
border-box:混杂模式默认,等于width+padding+border;
inherit:从父继承。

居中

.parent {
    position: relative;
}
.child {
    position: absolute;
    top: 50%;
    left: 50%;
    transform:translate(-50%,-50%);    
}
.parent {
    position: relative;
}
.child {
    position: absolute;
	top: 0; left: 0; bottom: 0; right: 0; 
	margin: auto;     
}
.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}
.parent {
	display: flex;
    text-align: center;
}
.child {
    margin: auto;
}
.parent {
    text-align:center;
}
.child {
    vertical-align:middle;
    display:inline-block;
}
.parent:after{
    content:'';
    width:0;
    height:100%;
    display:inline-block;
    vertical-align:middle;
}
/*内部元素为行内元素垂直才有效*/
.parent {
    display: table-cell;
    vertical-align: middle;
    text-align: center;
}
.parent {
	display: -webkit-box;
    -webkit-box-pack:center;
    -webkit-box-align:center;
}

三面边框

border: 1px solid green;
border-top: 0;
border-left:1px solid green;
border-bottom:1px solid green;
border-right:1px solid green;
box-shadow:2px 2px 5px #333333, -2px 2px 5px #333333;

css清除浮动

父元素因子元素浮动引起的内部高度为0造成塌陷的问题。

  1. 定义父元素高度;
  2. 父元素overflow:hidden/auto,且必须定义width或zoom:1;
  3. clear: both;
  4. 伪元素:after;
  5. 双伪元素:after;:before。

BFC

css动画

transition渐变动画、transfrom转变动画、animation自定义动画

伪类和伪元素

伪类:用来定义元素特殊状态,hover、active、link、first-child。
伪元素:也叫伪对象,不存在于DOM文档中,是一个虚拟元素,before、after、placeholder。
区分:是否创建新元素。

LESS、SASS/SCSS

都是动态样式语言。
LESS:为css赋予了动态语言特性,如变量、继承、运算、函数,既可在客户端运行,也可在服务端运行。
SASS:缩排语法,依赖Ruby环境。
SCSS:SASS3就是SCSS,与源语法兼容,只是用{ }取代了缩进。

相同:1. 混入mixin;2. 参数混入(传参);3. 嵌套规则;4. 运算;5. 颜色功能(编辑);6. 命名空间;7. 作用域;8. JS赋值(表达式)。

不同:

  1. less在JS上运行,SASS在Ruby上;
  2. 变量,less用@,sass用$;
  3. 作用域,less会逐级向上查找,可先使用后定义;sass是局部变量;
  4. 都支持单行/多行注释,sass单行注释不编译,多行注释会编译;less不知道;
  5. less仅允许循环数值,只能递归循环;sass可遍历任何类型;
  6. less不支持条件语句,可用内置函数if、and、or、not模拟;sass支持条件语句@if、@else、@else if;
  7. sass引入的外部文件必须以_开头;less就用@

Node

简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台。
Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境,基于 Google 的 V8 引擎,V8 引擎执行 Javascript 的速度非常快,性能非常好。

使用场景:高并发、实时聊天、实时消息推送、客户端逻辑强大的SPA。

优势:

  1. 简单,用JS、JSON编码;
  2. 功能强大,非阻塞式I/O。在较慢网络中可分块传输,事件驱动,擅长高并发访问;
  3. 轻量级,本身既是代码又是服务器,前后端使用同一语言;
  4. 可扩展,轻松应对多实例、多服务器架构,海量三方组件。

全局对象

Electron

是一个使用JS、HTML和CSS构建桌面应用程序的框架,开发跨平台应用。

React Native

关联问题

MVC模式

Model View Controller是典型的平行关系,各司其职,最大的好处是将逻辑和页面分离。
优点:
1.通过把项目分成model view和controller,使得复杂项目更加容易维护;
2.没有使用view state和服务器表单控件,可以更方便的控制应用程序的行为;
3.应用程序通过controller来控制程序请求,可以提供丰富的url重写;
4.对单元测试的支持更加出色;
5.在团队开发模式下表现更出众。

不足:
1.对于简单的界面,增加了系统结构和实现的复杂性,并可能产生过多的更新操作,降低运行效率;
2.有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用;
3.视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

MVVM

Model-View-ViewModel本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。

  • model数据模型,各种业务逻辑处理和数据操作
  • view视图,即用户界面
  • viewmodel是一个同步view和model的对象,不需要手动操作DOM,不需要关注数据状态同步的问题

优点:低耦合;可重用性;独立开发;可测试

强类型和弱类型

强类型弱类型
编译时确定类型的数据,执行时类型不能更改执行时确定类型
更安全,效率更高更灵活,效率低,出错概率高
例如:C#例如:js

SPA和MPA

Signal Page Application仅在页面初始化时加载相应的HTML、JS、CSS。一旦页面加载完成,不会因为用户的操作而进行页面重新加载或跳转。页面变化是利用路由机制实现HTML内容的变换,避免页面重新加载。
优点:用户体验好;减轻了服务器压力;前后端分离;可以实现转场动画。
缺点:初次加载耗时多;不利于SEO。

MultiPage Application有多个独立的页面的应用,每个公共资源(HTML、JS、CSS)需选择性重新加载,多页面跳转刷新所有资源。
优点:有利于SEO。
缺点:页面跳转,用户体验差;没有转场动画。

SPA首屏加载慢

来自:https://blog.csdn.net/weixin_44475093/article/details/110675962
原因:1. 网络延时;2. 资源文件过大;3. 资源重复发送请求加载;4. 加载脚本时,渲染内容阻塞

解决:1. 减少入口文件体积;2. 静态资源本地缓存;3. UI框架按需加载;4. 图片压缩;5. 组件重复打包;6. 开启GZIP压缩;7. 使用SSR

渲染技术

客户端渲染(CSR)

客户端渲染(Client-side rendering)是由浏览器加载、解析来渲染HTML。
优点:1. 首次加载完后页面响应速度快;2 可实现局部刷新,无需每次都请求完整的页面。
缺点:1. 首屏加载慢;2. 不利于SEO。

服务端渲染(SSR)

服务器端渲染(Server-Side Rendering)是指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程。
优点:1. 有利于SEO;2. 更快的到达时间(即首屏渲染)
缺点:1. 服务端压力较大;2. 开发条件受限;3. 学习成本相对较高

预渲染

预渲染(Prerendering)是在构建阶段生成匹配预渲染路径的html文件(每个预渲染的路由都有一个对应的html文件),构建出来的html已有部分内容。
优点:1. 有利于SEO;2. 首屏渲染快。
缺点:降低构建的速度。
vue中使用prerender-spa-plugin和vue-meta-info实现预渲染。

防抖和节流

参考:https://www.jianshu.com/p/47c37af00fa4

防抖:单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零 clearTimeout。触发高频事件,n秒内事件只会执行一次,如果n秒内再次触发,则会重新计算时间。(登录发短信按钮,resize,文本编辑器实时保存,联想输入)

节流:控制事件发生的频率。代码实现重在开锁关锁 timer=timeout; timer=null。(scroll 事件,浏览器播放进度更新,联想输入)

网络传输模型

TCP/IP四层模型:数据链路层、网络层(IP…)、传输层(TCP、UDP…)、应用层(FTP、HTTP、DNS、SMTP)。

OSI七层模型:物理层、数据链路层、网络层、传输层、会话层(DNS、SMTP)、表示层、应用层(FTP、HTTP)。

传输协议(TCP、UDP、HTTP、HTTPS)

  1. TCP、UDP在传输层,HTTP、HTTPS在应用层
  2. 信息传递可靠性不同

Tranmission Control Protocal:传输控制协议,一种面向连接的、可靠的、基于字节流的传输层通信协议。协议包含了专门的传递保证机制。当数据接收方收到发送方的信息时,会自动向发送方发出确认消息,发送方只有收到该确认消息后才继续发送其他信息,否则将一直等待直到收到确认信息为止。
User Datagram Protocal:用户数据报协议。无连接,不对数据检查修改,可靠性低,较好的实用性,工作效率高,结构简单,网络开销小。
Hypertext Transfer Protocal:超文本传输协议。一个简单的请求-响应协议,通常运行在TCP上。
HTTPS:由HTTP加上TLS/SSL协议构建的可进行加密传输、身份认证的网络协议。主要通过数字证书、加密算法、非对称密钥等技术完成互联网数据传输加密,实现互联网传输安全保护。

TCP三次握手和四次挥手

三次握手:

  1. 客户端发送标有SYN(同步作用)的数据包个服务端,假设序号J;
  2. 服务端收到SYN(序号J),发送一个SYN(假设序号K)及ACK(应答作用,需要J+1)给客户端;
  3. 客户端收到SYN(序号K)和ACK(J+1),发送一个ACK(序号K+1)给服务端。

四次挥手:

  1. 客户端发送FIN给服务端,关闭客户端到服务端的数据传输,假设序号J;
  2. 服务端收到FIN,发送ACK(J+1)给客户端;
  3. 服务端发送FIN给客户端,关闭服务端到客户端的数据传输 ,假设序号K;
  4. 客户端收到FIN,发送ACK(K+1)给服务端。
    由于TCP是全双工,所有要双方单独关闭。

GET、POST

HTTP 请求方法

Nginx

  1. 反向代理
  2. 负载均衡(2种:内置策略(轮询、加权轮询、Ip hash)和扩展策略)
  3. web缓存

server { listen 8089; server_name localhost,lanxin.cn; …}
server_name配IP:固定到IP上;
server_name配域名:可解析为多个IP,则通常用轮询的方式询问,需要多做一步域名解析。

C#

CTS、CLS、CLR

CTS:Common Type System 通用系统类型。Int32、Int16→int、String→string、Boolean→bool
CLS:Common Language Specification 通用语言规范。不同语言语法的不同。
CLR:Common Language Runtime 公共语言运行时,就是.Net提供的那些类

string、String;int、Int32;Boolean、bool的区别

String、Int32、Boolean等都属于.Net中定义的类,而string、int、bool相当于C#中对这些类定义的别名。CTS。

.Net Framework中的类是专门供C#调用的是吗

不是。VB.Net、F#等语言都可以调用.Net Framework中的类。CTS、CLS。

.Net实现异构平台下对象的互操作

NET通过对各语言先编译成( IL),然后再执行时用( JIT)将其编译成本地平台代码,来实现异构平台下对象的互操作。

C#修饰符

应用程序域(AppDomain)

应用程序域是一种边界,它由公共语言运行库围绕同一应用程序范围内创建的对象建立(即,从应用程序入口点开始,沿着对象激活的序列的任何位置)。有助于将在一个应用程序中创建的对象与在其他应用程序中创建的对象隔离,以使运行时行为可以预知。
一个单独的进程可包含多个应用程序域。应用程序域可以理解为一种轻量级进程。起到安全的作用,占用资源小。

三层架构

通常意义上的三层架构就是将整个业务应用划分为:表现层(UI,用户界面)、业务逻辑层(BLL,数据逻辑处理)、数据访问层(DAL,数据库操作),实现“高内聚,低耦合”。一般来说,层次之间是向下依赖的。
优点: 分工明确,条理清晰,易于调试,而且具有可扩展性。
缺点: 增加成本。

面向对象三要素

托管代码

托管代码是运行.NET 公共语言运行时CLR的代码。
unsafe:非托管代码,不经过CLR运行,程序员自行分配和释放内存空间。

C#中的事件和委托

委托是类型,事件是对象。事件的内部是用委托实现的。
委托可以把一个方法作为参数代入另一个方法,可以理解为指向一个函数的指针。
事件只能注册、移除自己,不能赋值。事件内部就是一个 private 的委托和 add、remove 两个方法。

C# 委托(Delegate)

反射

反射提供描述程序集、模块和类型的对象(Type 类型)。 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问器字段和属性。 如果代码中使用了特性,可以利用反射来访问它们。

序列化

序列化:序列化是将对象转换为容易传输的格式的过程。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。在另一端,反序列化将从该流重新构造对象。

new 关键字用法

  • 运算符:创建对象和调用构造函数。
  • 修饰符:向基类成员隐藏继承成员。
  • 约束:在泛型声明中约束可能用作类型参数的参数的类型。

C#中的重写(override)、重载(overload)和覆盖(new)

用关键字 virtual 修饰的方法,叫虚方法。相应的没有用virtual修饰的方法,我们叫它实方法。

  • 重写是进行基类中函数的重写,且基方法必须与 override 方法具有相同的签名。
  • 重载是方法的名称相同,参数个数或参数类型不同,进行多次重载以适应不同的需要。
  • 重写是面向对象的概念,重载是面向过程的概念。
  • 当用子类创建父类的时候,重写会调用子方法,覆盖会调用父方法。

C#中索引器是否只能根据数字进行索引?是否允许多个索引器参数?

参数的个数和类型都是任意的。用reflector反编译可以看出,索引器的内部本质上就是set_item、get_item方法。

C#中的属性和public字段

公共字段只是用public修饰符所公开的简单公共变量,而属性则是对字段的封装,它使用get和set访问器来控制如何设置或返回字段值。
属性可以对设值、取值的过程进行非法值控制,且可以让get读取到的不是set设置的值。

传入某个属性的set方法的隐含参数的名称是什么?

value,它的类型和属性所声名的类型相同。

C#中的装箱(boxing)和拆箱(unboxing)

装箱:从值类型转换到引用类型。
拆箱:从引用类型转换到值类型。

C#中的类(class)和结构(struct)

Class可以被实例化,属于引用类型,是分配在内存的堆上的,类是引用传递的。
Struct属于值类型,是分配在内存的栈上的,结构体是值传递的。

值类型和引用类型

  1. 赋值:值类型将复制包含的值,引用类型将复制对象的引用,而不复制对象本身。
  2. 值类型不可能派生出新的类型,所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
  3. 值类型不可能包含 null 值:然而,可空类型功能允许将 null 赋给值类型。
  4. 每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。

泛型

通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用 。
类型安全和减少装箱、拆箱。提高性能、类型安全和质量,减少重复性的编程任务 。

C#中的接口和类

接口用于规范,抽象类用于共性。

接口
不能包含方法的实现
不能实例化
可多继承单继承
StreamReader、WebClient、Dictionary<K,V>、StringBuilder、SqlConnection、FileStream、File、Regex、List<T>IDisposable、IEnumerable、IDbConnection、IComparable、ICollection、IList、IDictionary
定义可拆分在不同源文件
接口、类和结构都可以从多个接口继承,类对接口叫做实现,不叫继承
接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员
接口和类都可以包含事件、索引器、方法和属性
接口抽象类
可多继承单继承
只能定义行为既可以定义行为,还可能提供实现
可以用于支持回调(CallBack)不能实现回调,因为继承不支持
包含方法、属性、索引器、事件的签名,不能定义字段和包含实现的方法可以定义字段、属性、包含有实现的方法
可作用于值类型(Struct)和引用类型(Class)可作用于引用类型
不能实例化
可通过继承实现其抽象方法

C#中的const与readonly

GC

GC是垃圾收集器。程序员不用担心内存管理,因为垃圾收集器会自动进行管理。GC只能处理托管内存资源的释放,对于非托管资源则不能使用GC进行回收,必须由程序员手工回收。
例如FileStream或者SqlConnection需要程序员调用Dispose进行资源的回收。
要请求垃圾收集,可以调用下面的方法:GC.Collection(),一般不需要手动调用。

进程和线程

进程线程
定义应用程序之间的边界定义代码执行堆栈和执行上下文的边界
进程之间不能共享代码和数据空间同一进程中的不同线程共享代码和数据空间
一个进程可以包括若干个线程

线程工作方式

多线程由内部线程调度程序管理,线程调度器通常是CLR委派给操作系统的函数。线程调度程序确保所有活动线程都被分配到合适的执行时间,线程在等待或阻止时 (例如,在一个独占锁或用户输入) 不会消耗 CPU 时间。
在单处理器计算机上,线程调度程序是执行时间切片 — 迅速切换每个活动线程。在 Windows 中, 一个时间片是通常数十毫秒为单位的区域 — — 相比来说 线程间相互切换比CPU更消耗资源。在多处理器计算机上,多线程用一种混合的时间切片和真正的并发性来实现,不同的线程会在不同的cpu运行代码。

C#中创建线程的四种方式

C#线程通信AutoResetEvent和ManualResetEvent

线程同步

https://blog.csdn.net/qq_43360872/article/details/108081628
https://www.cnblogs.com/waitkun/p/14588806.html

C#中的Task

能用foreach遍历访问的对象的要求

需要实现IEnumerable接口或声明GetEnumerator方法的类型。

net Remoting 的工作原理是什么

服务器端向客户端发送一个进程编号,一个程序域编号,以确定对象的位置。

O/R Mapping 的原理

利用反射,配置将对象和数据库表映射。

remoting和webservice两项技术的理解以及实际中的应用。

WS主要是可利用HTTP,穿透防火墙。而Remoting可以利用TCP/IP,二进制传送提高效率。

int、DateTime、string是否可以为null

int、DateTime为Struct类型,不能为null。
string为引用类型可以为null。

new字符串时创建了几个String Object

String s = new String("xyz");

两个对象,一个是“xyz”,一个是指向“xyz”的引用对象。

不是说字符串是不可变的吗?string s=“abc”;s="123"不就是变了吗?

String是不可变的。
s原指向一个内容是 "abc"的String对象,然后我们将s指向另一个内容是"123"的String对象,原来的对象还存在于内存之中,只是s这个引用变量不再指向它了。

C#中所有对象共同的基类

System.Object

是否可以继承String类

String类是sealed类故不可以继承。

如何把一个Array复制到ArrayList里

string[] str ={ "a", "b" }; 
ArrayList list1 = new ArrayList();
list1.AddRange(str);
ArrayList list2 = new ArrayList(s);

通过超链接怎样传递中文参数

用URL编码,通过QueryString传递,用urlencode编码/解码。

是否可以从一个static方法内部发出对非static方法的调用?

不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。

C#中ref和out

refout
参数传入的参数必须先被初始化必须在方法中对其完成初始化
关键字在方法的参数和执行方法时都要加ref在方法的参数和执行方法时都要加out
使用需要被调用的方法修改调用者的引用的时候需要retrun多个返回值的地方

C#内存泄露

C#中的弱引用(WeakReference)

C#设计模式

C#各版本新功能

C# SQLite

ADO.NET中的五个主要对象

Connection:主要是开启程序和数据库之间的连接。Close以后还可以Open,Dispose以后则不能再用。

Command:主要可以用来对数据库发出一些指令,例如可以对数据库下达增删改查数据等指令,以及调用存在数据库中的存储过程等。

DataAdapter:主要是在数据源以及DataSet 之间执行数据传输的工作,它可以透过Command 对象下达命令后,并将取得的数据放入DataSet 对象中。

DataSet:这个对象可以视为一个暂存区(Cache),可以把从数据库中所查询到的数据保留起来,甚至可以将整个数据库显示出来,DataSet是放在内存中的。DataSet 的能力不只是可以储存多个Table 而已,还可以透过DataAdapter对象取得一些例如主键等的数据表结构,并可以记录数据表间的关联。DataSet 对象可以说是ADO.NET 中重量级的对象,这个对象架构在DataAdapter对象上,本身不具备和数据源沟通的能力;也就是说我们是将DataAdapter对象当做DataSet 对象以及数据源间传输数据的桥梁。DataSet包含若干DataTable、DataTable包含若干DataRow。

DataReader:当我们只需要循序的读取数据而不需要其它操作时,可以使用DataReader 对象。DataReader对象只是一次一次向下循序的读取数据源中的数据,这些数据是存在数据库服务器中的,而不是一次性加载到程序的内存中的,只能(通过游标)读取当前行的数据,而且这些数据是只读的,并不允许作其它的操作。因为DataReader 在读取数据的时候限制了每次只读取一条,而且只能只读,所以使用起来不但节省资源而且效率很好。使用DataReader 对象除了效率较好之外,因为不用把数据全部传回,故可以降低网络的负载。

C# Linq

结构化查询语言SQL

参考:https://baike.baidu.com/item/%E7%BB%93%E6%9E%84%E5%8C%96%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80/10450182?fromtitle=sql%E8%AF%AD%E8%A8%80&fromid=4801972&fr=aladdin
结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。
结构化查询语言是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统, 可以使用相同的结构化查询语言作为数据输入与管理的接口。结构化查询语言语句可以嵌套,这使它具有极大的灵活性和强大的功能。

结构化查询语言包含6个部分:
数据查询语言(DQL: Data Query Language)、数据操作语言(DML:Data Manipulation Language)、事务控制语言(TCL)、数据控制语言(DCL)、数据定义语言(DDL)、。

数据库的六大范式

参考:https://baijiahao.baidu.com/s?id=1683424856311376285&wfr=spider&for=pc
数据库范式主要是为解决关系数据库中数据冗余、更新异常、插入异常、删除异常问题而引入的设计理念。简单来说,数据库范式可以避免数据冗余,减少数据库的存储空间,并且减轻维护数据完整性的成本。
分类:1NF、2NF、3NF、BCNF、4NF、5NF。

  1. 1NF 第一范式:强调属性的原子性约束,要求属性具有原子性,不可再分解。(冗余度大、会引起修改操作的不一致性、数据插入异常、数据删除异常。)
  2. 2NF 第二范式:强调记录的唯一性约束,数据表必须有一个主键,并且没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
  3. 3NF 第三范式:强调数据属性冗余性的约束,也就是非主键列必须直接依赖于主键。也就是消除了非主属性对码的传递函数依赖。
  4. BCNF(巴斯范式):强调函数依赖。所有非主属性对每一个候选键都是完全函数依赖; 所有的主属性对每一个不包含它的候选键,也是完全函数依赖;没有任何属性完全函数依赖于非候选键的任何一组属性。(若X函数确定Y且Y不在X内时X必含有码,则此关系属于BCNF。)
  5. 4NF 第四范式:强调多值依赖。非主属性不应该有多值,属性间不允许有非平凡且非函数依赖的多值依赖。(如果只考虑函数依赖,关系模式规范化程度最高的范式是BCNF;如果考虑多值依赖则是4NF。)
  6. 5NF 第五范式:完美范式,消除了4NF中的连接依赖。
  • 平凡的多值依赖:全集U=K+A,一个K可以对应于多个A,即K→→A。此时整个表就是一组一对多关系。
  • 非平凡的多值依赖:全集U=K+A+B,一个K可以对应于多个A,也可以对应于多个B,A与B互相独立,即K→→A,K→→B。整个表有多组一对多关系,且有:“一”部分是相同的属性集合,“多”部分是互相独立的属性集合。
  • 函数依赖是多值依赖的一种特殊的情况,而多值依赖实际上又是连接依赖的一种特殊情况。

sql注入

用户根据系统的程序构造非法的参数从而导致程序执行不是程序员期望的恶意SQL语句,例如' or 1='1
使用参数化的SQL就可以避免SQL注入。
SELECT * FROM user WHERE un='hello' and pd='world';
SELECT * FROM user WHERE un='' or 1='1' and pd='xxx';

数据库索引

使用索引可以加快数据的查询速度,不过由于数据插入过程中会建索引,所以会降低数据的插入、更新速度,索引还会占磁盘空间。

数据库优化

  1. 使用最合适的字段属性,比如能用char(2)就不用char(255)
  2. 使用连接(join)代替子查询,减少临时表
  3. 事务,不过有独占性
  4. 锁定表,避免其他语句对表的修改操作
  5. 外键
  6. 索引
  7. 优化查询语句

查询优化

  1. 尽量避免全表扫描
  2. 减少模糊查询
  3. 在建立索引的列上尽量不使用函数操作
  4. 尽量避免在where上对null值判断,容易导致放弃索引进行全表扫描

索引

聚集索引:数据行的物理顺序与列值(一般是主键列)的逻辑顺序相同,一个表只能有一个聚集索引。
非聚集索引:索引的逻辑顺序与磁盘上行的物理存储顺序不同。

主键和唯一索引

  • 主键一定是唯一索引,唯一索引不一定是主键
  • 一个表中,主键只能有一个,唯一索引可有多个
  • 主键不可为空,唯一索引可为空
  • 主键可是复合主键
  • 唯一索引表示索引值唯一,可由多个字段组成
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值