HTML及其他基础知识部分
渲染页面的流程
1.解析HTML,获得Dom树,快
2.解析Css,获得Cssom树,快
3.将两者整合成渲染树,快
4.布局:根据渲染树计算节点位置,慢
5.绘制:根据计算好的信息绘制页面,慢-
前端存储方法
- localstorage:永久生命周期
- sessionstorage:域名下所有选项卡被关闭时被清除
- cookie:由后端设置,通过response发送给前端
- indexedDB:js对象,空间大,可二进制
-
各个图像格式的区别是什么?
- jpg/jpeg:有损压缩方案,将不易被人眼察觉的图像颜色删除进行压缩;
- gif:分为静态和动画两种,支持透明背景图像;
- bmp:未经压缩,通用格式;
-
HTTP1.0,1.1,2.0的区别
- 长连接:1.0默认关闭,需要在http头加入"Connection: Keep-Alive”才能启用;而1.1是默认开启的
- 节约带宽:1.1支持只发送header信息,当客户端收到服务器返回的100时才开始把body发送到服务器
- 多路由复用:Http2.0的并发请求数量比1.1大
- 数据压缩:HTTP2.0支持header的数据压缩
- 服务器推送:HTTP2.0支持在web server请求时顺便把客户需要的资源推送至客户端
Js部分
-
es6常用新语法
- let / const
- for(let i in Array)
- 函数默认值
function demo(data = 1) { // ... } demo(); // 此时data默认为1
- 箭头函数
demo = (a, b) => a + b;
- 对象
const name = 'andy'; const age = 24; const Andy= { // 1. key和value同名时可以省略 name, age, // 2. 函数可以省略function do() { // do sth. } } // 3. 解构,对初始化的逆向操作 const Peter = { name: 'Peter', age: '20' } const {name: peterName, age: peterAge} = Peter; console.log(peterName, peterAge); // Peter 20
- 拓展运算符(…):用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
const arr1 = [1, 2]; const arr2 = [...arr1];
- 面向对象
class Person{ constructor(name, age) { this.name = name; this.age = age; } show() { console.log(this.name, this.age) } } // 实例化 const andy = new Person('andy', 24); andy.show(); // andy 24 // 继承 class Staff extends Person{ constructor(name, age, id) { super(name, age); this.id = id; } } const peter = new Staff('Peter', 21, 233); console.log(peter); // Peter 21
闭包:能够读取其他函数内部变量的函数,即定义在一个函数内部的函数,内部函数持有外部函数内变量的引用,并让这些变量始终保存在内存中;
js链式作用域:子对象会一级一级向上寻找所有父对象的变量,反之不行。
变量提升:在js解析时,在函数内部定义的变量都会提升到该函数的最开始的地方进行申明,在执行到时再进行赋值操作。
如何确定一个值是null?
const data = null;
console.log(typeof(data));
// Object
// 这里是一个Js的历史遗留问题,所以不能单纯的用typeof来验证
if(!Object.is(data, undefined) && Object.is(data, data)) {
// data is null
}
- Content-Type的类型
- 常用:text/html, text/javascript, image/jpeg, image/png, image/gif
- Ajax请求:application/x-www-form-urlencoded, multipart/form-data, application/json, application/xml
- 表单:application/x-www-form-unlencoded
- post请求、form提交等:application/x-www-form-unlencoded
- NaN定义:Not a Number,typeof输出Number
- typeof系列
- typeof(undefined) :undefined
- typeof(null):object
- typeof(NaN):Number
- Promise / async - await
- Promise是异步编程解决方案,状态凝固
- promise实例有
then
方法,用于异步计算,队列化,返回一个新的promise -
async
用于申明一个函数是异步的 -
await
只能用于async
内,表示在等待promise的返回结果再继续执行 - 引用:
.then()
要写一大串的,可以用await一行一行写清
- 数组api:
.concat
连接两个,.join
以指定规则组成字符串,.pop
删除最后一个,.shift
删除第一个,.push
尾+1,.splice(index, howmany)
删除并插入一个新的 - 继承的6种方式
- 原型链继承:让新实例的原型等于父类的实例
- 借用构造函数继承:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
- 组合继承(组合原型链继承和借用构造函数继承)
- 原型式继承:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象
- 寄生式继承:给原型式继承外面套了个壳子
- 寄生组合式继承
- 如何解决跨域:
- 起因:同源策略:浏览器安全策略,同协议、ip、端口的脚本才会执行
- 方案1:通过jsonp(填充式json)跨域:动态创建<script>标签,通过src不受同源策略约束获取数据,缺点:只能用get方法
- 方案2:通过修改
document.domain
来跨子域 - 方案3:使用
window.name
来跨域
- 原型链
1.每个实例对象( object )都有一个私有属性( proto )
2.proto指向它的构造函数的原型对象(prototype ) - 形参和实参:形参是函数声明时的变量,实参是调用函数时传入的具体参数
- obj为一个存储空间,赋值时传递储存空间,所以改变赋值后的结果也会改变原内容
var a = {name: a, value: 1}
b = a
b.name = “1”
console.log(a.name) // 1
-
map
和forEach
的区别?用法相同,但是map会返回一个新的对象 - 如何用js判断一个变量是否为整数?
- 通过
typeof
判断是否为number - 除1后是否与原值全等
- 通过
- Js实现快速排序?思路:
- 以中间的数为基准,比基准小的放左边,比基准大的放右边;
- 再按此方法对这两部分进行快排(递归算法);
- 不能再分后退出递归,并重新合并数组
function quickSort(arr){
if(arr.length<1){
return arr;
}
var pivotIndex=Math.floor(arr.length/2);//找到那个基准数
var pivot=arr.splice(pivotIndex,1)[0]; //取出基准数,并去除,splice返回值为数组。
var left=[];
var right=[];
for(var i=0;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot],quickSort(right)); //加入基准数
}
- 节流函数: JS进阶篇1---函数节流(throttle)
// 时间戳方案
function throttle(fn,wait){
var pre = Date.now();
return function(){
var context = this;
var args = arguments;
var now = Date.now();
if( now - pre >= wait){
fn.apply(context,args);
pre = Date.now();
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
// 定时器方案
function throttle(fn,wait){
var timer = null;
return function(){
var context = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
fn.apply(context,args);
timer = null;
},wait)
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
- 函数节流 和 函数防抖的异同
- 函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段;
- 函数节流是指一定时间内js方法只跑一次。比如人的眨眼睛,就是一定时间内眨一次;可以用于列表懒加载避免滚动出错时大量重复请求;
- 函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次,可以用于搜索框输入完成后一段时间再出发的联想搜索功能。
- 隐式转换:
- 字符串与算数运算符(+):
- 一边有string则全string并拼接
- 无则Number()做加法
- 关系运算符:
- 转换成number后比较
- 字符串会转Unicode,并从各自第一个字母开始比较
- 复杂数据类型会先toString()再toNumber()
- 示例
- 字符串与算数运算符(+):
[] == 0 // true
![] == 0 // true
[] == ![] // true
[] == [] // false
{} == !{} // false
{} == {} // false
- 箭头函数 和 普通函数的异同
- 箭头函数都是匿名函数;
- 箭头函数不能用于new构造函数;
-
this
的指向
①. 在普通函数中,this
指向调用它的对象,在构造函数中指向创建的对象实例;
②. 箭头函数本身没有this
,会在声明时捕获其上下文的this
,一经捕获就不再变化;
Css部分
文档定位分为哪3种?普通流/常规流,浮动流,固定流
如何脱离文档流?使用
float
或者position: absolute
实现部分无视和完全无视什么是BFC?:
BFC 即(Block Formatting Context)块级格式化上下文,指一个独立的块级渲染区域,只有块级盒子(box)参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与区域外部无关。-
BFC的形成条件?
- 根元素html标签就是一个bfc
- float的值不为none
- overflow的值不为visible
- display的值为 inline-block/ table-cell/ table-caption/ flex/ inline-flex
- position的值为absolute或fixed
-
display的属性及含义
-
display: none
:不显示 -
display: block
:块级元素,前后带有换行符,每个元素占一行的从上到下排列 -
display: inline
:默认,内联元素,前后没有换行符,从左到右排列,直到这一行排满,会出现折行现象 -
display: inline-block
: 内联块元素,从左到右排列,但不会折行
-
-
position的属性及含义
-
position: absolute
:绝对位置,相对于元素最近的已定位的祖先元素,若无则相对于body -
position: fixed
:固定位置,相对于浏览器进行定位 -
position: relative
:相对定位,相对于其正常位置 -
position: sticky
:粘性定位,基于用户滚动的位置
-
-
transform、transition和animation之间的异同?
- transform:描述元素静态样式,在鼠标点击、悬停时触发,触发结束后属性回归,本质上没有发生属性变化;
- transition:实现动画效果,可以定义动画的属性、时间、速度曲线以及延迟时间,只能设置头尾;
- animation:实现动画效果,可以定义动画名称,动画执行时间,速度曲线,动画延迟时间,播放次数,是否反向播放,更精确并且可以循环。
- css画一个三角形:内容尺寸为0,border宽40,隐藏3个border,剩下的就是三角形
- Css画一个无线旋转动画:-webkit-animation: anim 1s linear infinite
- 提高页面性能?预加载、懒加载、图片优化、Css置顶Js置底
- px和em的异同点?
- px像素,相对于显示器分辨率而言
- em字体尺寸,相对于当前对象内文本字体尺寸,继承父级字体大小,非固定
- Css隐藏元素的方法:
opacity: 0; visibility: hidden; display: none;
- 用css2和css3分别写一下垂直居中和水平居中?
/* Css3水平居中 */
{display: flex; justify-content: center;}
/* Css3垂直居中 */
{display: flex; align-items: center;}
/* Css2水平居中 */
{display: inline; text-align: center;}
/* Css2垂直居中 */
{height: 200px; line-height: 200px}
- 如何用Css画一个高等于宽的正方形?
<html>
<body>
<div id="container">
<div id="attr"></div>
</div>
</body>
</html>
<style>
#container {
width: 80%;
height: 500px;
}
#attr {
width: 50%;
height: 0;
padding-bottom: 50%;
background-color: aqua;
}
</style>
Vue部分
-
jQuery和Vue的区别?
- JQuery主要是通过选择器来选取DOM,对其进行操作,数据和页面是混合在一起的;
- Vue则是通过Vue对象将数据和视图完全分割开,对数据进行操作,不再需要引用相应的DOM对象;
-
Vue响应式数据绑定原理?
- Vue为MVVM框架,当数据模型
data
变化时,页面视图会得到响应更新,其原理对data
的getter
/setter
方法进行拦截(Object.defineProperty
或者Proxy
),利用发布订阅的设计模式,在getter
方法中进行订阅,在setter
方法中发布通知,让所有订阅者完成响应。 - 在响应式系统中,Vue会为数据模型
data
的每一个属性新建一个订阅中心作为发布者,而监听器watch
、计算属性computed
、视图渲染template
/render
三个角色同时作为订阅者,对于监听器watch
,会直接订阅观察监听的属性;对于计算属性computed
和视图渲染template
/render
,如果内部执行获取了data
的某个属性,就会执行该属性的getter
方法,然后自动完成对该属性的订阅,当属性被修改时,就会执行该属性的setter
方法,从而完成该属性的发布通知,通知所有订阅者进行更新。
- Vue为MVVM框架,当数据模型
Vue时间绑定原理?
每一个Vue实例都是一个Event Bus,当子组件被创建的时候,父组件将事件传递给子组件,子组件初始化的时候是有$on
方法将事件注册到内部,在需要的时候使用$emit
触发函数,而对于原生native事件,使用addEventListener绑定到真实的DOM元素上。-
-
beforeCreate
:是new Vue()
之后触发的第一个钩子,在当前阶段data
、methods
、computed
以及watch
上的数据和方法都不能被访问。 -
created
:在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated
函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick
来访问Dom。 -
beforeMount
:发生在挂载之前,在这之前<template>
模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated
。 -
mounted
:在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs
属性对Dom进行操作。 -
beforeUpdate
:发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。 -
updated
:发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。 -
beforeDestroy
:发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。 -
destroyed
:发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。
-
-
为什么组件data必须是一个函数?
- 因为组件可能会在很多地方被使用,如果data是一个对象,对象是
引用类型
,会导致一个组件的data更新时其他组件的data一起更新,所以data必须是函数,为每个实例创建一个自己的data,在使用同一个组件时也互不影响。
- 因为组件可能会在很多地方被使用,如果data是一个对象,对象是
Vue中如何watch对象:deep=true时可以检测对象中的属性变化
Vue的常用修饰符
.stop
:阻止冒泡
.lazy
:光标离开后才更新数据
.prevent
:阻止默认行为
.once
:只能用一次-
methods 中的方法与 computed 的区别
- computed是属性调用,而methods是函数调用
- computed带有缓存功能,而methods不是
-
computed
与watch
的区别- 计算属性computed更多是作为缓存功能的观察者,它可以将一个或者多个
data
的属性进行复杂的计算生成一个新的值,提供给渲染函数使用,当依赖的属性变化时,computed不会立即重新计算生成新的值,而是先标记为脏数据,当下次computed被获取时候,才会进行重新计算并返回。 - 而监听器watch并不具备缓存性,监听器watch提供一个监听函数,当监听的属性发生变化时,会立即执行该函数。
- 计算属性computed更多是作为缓存功能的观察者,它可以将一个或者多个
-
$set
- 如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。
- 使用方法:
this.$set(this.data, "key", value');
-
Vue.nextTick
- 定义:在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。
- 应用场景:
- 在Vue生命周期的
created()
钩子函数进行的DOM操作一定要放在Vue.nextTick()
的回调函数中。原因:是created()
钩子函数执行时DOM其实并未进行渲染。 - 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作应该放在
Vue.nextTick()
的回调函数中。原因:Vue异步执行DOM更新,只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变,如果同一个watcher被多次触发,只会被推入到队列中一次。
- 在Vue生命周期的
-
Vue中组件传参的方法
- 父子组件通讯
- 父组件 -> 子组件:
prop
; - 子组件 -> 父组件:
$on
/$emit
; - 获取组件实例:使用
$parent
/$children
,$refs.xxx
,获取到实例后直接获取属性数据或调用组件方法;
- 父组件 -> 子组件:
- 兄弟组件通信
-
Event Bus:每一个Vue实例都是一个Event Bus,都支持
$on
/$emit
,可以为兄弟组件的实例之间new一个Vue实例,作为Event Bus进行通信; - Vuex:将状态和方法提取到Vuex,完成共享。
-
Event Bus:每一个Vue实例都是一个Event Bus,都支持
- 父子组件通讯
-
slot是什么?有什么作用?原理是什么?
-
slot
即插槽,是Vue的内容分发机制,组件内部的模板引擎使用<slot>
元素作为承载分发内容的出口。slot是子组件的一个模板标签元素,而这一标签的显示规则由父组件决定。 - slot又分三类,默认插槽,具名插槽和作用域插槽。
- 默认插槽:又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有一个匿名插槽。
- 具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。
- 作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。
- 实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在
vm.$slot
中,默认插槽为vm.$slot.default
,具名插槽为vm.$slot.xxx
,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot
中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。
-
-
什么是虚拟DOM?
- Virtual DOM 是 DOM 节点在 JavaScript 中的一种抽象数据结构,之所以需要虚拟DOM,是因为浏览器中操作DOM的代价比较昂贵,频繁操作DOM会产生性能问题。虚拟DOM的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue对比更新前后的虚拟DOM,匹配找出尽可能少的需要更新的真实DOM,从而达到提升性能的目的。
-
Vue2.0 和 Vue3.0 的区别?
- 重构响应式系统,使用
Proxy
替换Object.defineProperty
,使用Proxy优势:
(1) 可直接监听数组类型的数据变化;
(2) 监听的目标为对象本身,不需要像Object.defineProperty
一样遍历每个属性,有一定的性能提升;
(3) 可拦截apply
、ownKeys
、has
等13种方法,而Object.defineProperty
不行;
(4) 直接实现对象属性的新增/删除; - 新增Composition API,更好的逻辑复用和代码组织;
- 重构 Virtual DOM:
- 模板编译时的优化,将一些静态节点编译成常量;
- slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件;
- 模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数);
- 代码结构调整,更便于Tree shaking,使得体积更小;
- 使用Typescript替换Flow。
- 重构响应式系统,使用
-
为什么要新增Composition API,它能解决什么问题
- Vue2.0中,随着功能的增加,组件变得越来越复杂,越来越难维护,而难以维护的根本原因是Vue的API设计迫使开发者使用
watch
,computed
,methods
选项组织代码,而不是实际的业务逻辑。 - 另外Vue2.0缺少一种较为简洁的低成本的机制来完成逻辑复用,虽然可以minxis完成逻辑复用,但是当mixin变多的时候,会使得难以找到对应的
data
、computed
或者method
来源于哪个mixin,使得类型推断难以进行。 - 所以Composition API的出现,主要是也是为了解决Option API带来的问题,第一个是代码组织问题,Compostion API可以让开发者根据业务逻辑组织自己的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他自己写的代码时,他可以更好的利用代码的组织反推出实际的业务逻辑,或者根据业务逻辑更好的理解代码。
- 第二个是实现代码的逻辑提取与复用,当然mixin也可以实现逻辑提取与复用,但是像前面所说的,多个mixin作用在同一个组件时,很难看出property是来源于哪个mixin,来源不清楚,另外,多个mixin的property存在变量命名冲突的风险。而Composition API刚好解决了这两个问题。
- Vue2.0中,随着功能的增加,组件变得越来越复杂,越来越难维护,而难以维护的根本原因是Vue的API设计迫使开发者使用
-
SSR的原理与好处?
在客户端请求服务器的时候,服务器到数据库中获取到相关的数据,并且在服务器内部将Vue组件渲染成HTML,并且将数据、HTML一并返回给客户端,这个在服务器将数据和组件转化为HTML的过程,叫做服务端渲染SSR。而当客户端拿到服务器渲染的HTML和数据之后,由于数据已经有了,客户端不需要再一次请求数据,而只需要将数据同步到组件或者Vuex内部即可。除了数据外,HTML也结构已经有了,客户端在渲染组件的时候,也只需要将HTML的DOM节点映射到Virtual DOM即可,不需要重新创建DOM节点,这个将数据和HTML同步的过程,又叫做客户端激活。
使用SSR的好处:
- 有利于SEO:其实就是有利于爬虫来爬你的页面,因为部分页面爬虫是不支持执行JavaScript的,这种不支持执行JavaScript的爬虫抓取到的非SSR的页面会是一个空的HTML页面,而有了SSR以后,这些爬虫就可以获取到完整的HTML结构的数据,进而收录到搜索引擎中。
- 白屏时间更短:相对于客户端渲染,服务端渲染在浏览器请求URL之后已经得到了一个带有数据的HTML文本,浏览器只需要解析HTML,直接构建DOM树就可以。而客户端渲染,需要先得到一个空的HTML页面,这个时候页面已经进入白屏,之后还需要经过加载并执行 JavaScript、请求后端服务器获取数据、JavaScript 渲染页面几个过程才可以看到最后的页面。特别是在复杂应用中,由于需要加载 JavaScript 脚本,越是复杂的应用,需要加载的 JavaScript 脚本就越多、越大,这会导致应用的首屏加载时间非常长,进而降低了体验感。
其他
-
webpack的核心概念
- 入口(entry):用于指示作为内部依赖图开始的文件;
-
输出(output):用于指定在哪里、以什么文件名输出webpack创建的
bundle
; - loader:用于让webpack有能力去处理其他类型的文件,并将它们转化为有效的模块,并添加至依赖图中;
- 插件(plugin):用于执行比loader范围更广的任务。包括:打包优化,资源管理,注入环境变量。
-
模式(mode):通过选择
development
,production
或none
之中的一个,来设置 mode 参数,以启用 webpack 内置在相应环境下的优化。
-
webpack的构建流程与原理 初始化 => 编译 => 输出
- 初始化参数:从配置文件(默认webpack.config.js)和shell语句中读取与合并参数,得出最终的参数
- 开始编译(compile):用上一步得到的参数初始化Comiler对象,加载所有配置的插件,通过执行对象的run方法开始执行编译
- 确定入口:根据配置中的entry找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,再递归 本步骤直到所有入口依赖的文件都经过处理
- 完成编译模块:经过第四步之后,得到了每个模块被翻译之后的最终内容以及他们之间的依赖关系
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的chunk,再将每个chunk转换成一个单独的文件加入输出列表中,这是可以修改输出内容的最后机会
- 输出完成:在确定好输出内容后,根据配置(webpack.config.js && shell)确定输出的路径和文件名,将文件的内容写入文件系统中(fs)
-
计算机网络知识
- OSI七层参考模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
- TCP和UDP的含义与异同
- 属于传输层
- TCP面向连接,传输可靠,用于传输大量数据,速度慢;
- UDP面向非连接,传输不可靠,用于传输少量数据,速度快;
- TCP多用于文件传输、邮件、远程登录,UDP用于即时通信、在线语音视频等
- HTTP是什么?加密的HTTP,HTTP+SSL
- 常用状态码
-
201
:请求成功并且服务器创建了新的资源,且其 URI 已经随Location 头信息返回 -
401
:请求要求验证身份 -
403
:服务器已经理解请求,但是拒绝执行它 -
404
:请求失败,请求所希望得到的资源未被在服务器上发现
-
-
常用的数据结构
- 数组:可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始;
- 栈:栈顶允许操作,栈底不允许操作。 特点是先进后出;
- 队列:队列可以在一端添加元素,在另一端取出元素,也就是先进先出;
- 链表:链表每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等;
- 树:由n(n>=1)个有限节点组成一个具有层次关系的集合,常见的是二叉树